Skip to main content

piquel_log/
lib.rs

1//! Small, composable backend initialization for [`tracing`].
2//!
3//! `piquel-log` is intended for applications that want a straightforward
4//! way to install a `tracing` backend without exposing a large custom API.
5//! The crate always supports console output and can optionally support file
6//! output and `log` crate interoperability behind Cargo features.
7//!
8//! # Quick start
9//!
10//! ```rust
11//! use piquel_log::Logger;
12//!
13//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
14//! Logger::new().init()?;
15//! tracing::info!("hello from tracing");
16//! # Ok(())
17//! # }
18//! ```
19//!
20//! # Existing subscriber stacks
21//!
22//! If your application already builds a `tracing_subscriber` registry, use
23//! [`Logger::build`] and attach the returned [`BackendLayer`] yourself.
24//!
25//! ```rust
26//! use piquel_log::Logger;
27//! use tracing_subscriber::{filter::LevelFilter, prelude::*, Registry};
28//!
29//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
30//! let backend = Logger::new().build()?;
31//! let subscriber = Registry::default().with(LevelFilter::INFO).with(backend);
32//! let _guard = tracing::subscriber::set_default(subscriber);
33//! tracing::info!("hello from a custom stack");
34//! # Ok(())
35//! # }
36//! ```
37//!
38//! # `log` interoperability
39//!
40//! When the `log` feature is enabled, [`Logger::with_log_bridge`] can install
41//! `tracing_log::LogTracer` during [`Logger::init`] so that `log` records are
42//! re-emitted as `tracing` events.
43//!
44//! ```rust
45//! # #[cfg(feature = "log")]
46//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
47//! use piquel_log::Logger;
48//!
49//! Logger::new().with_log_bridge(true).init()?;
50//! log::warn!("bridged from log");
51//! # Ok(())
52//! # }
53//! # #[cfg(not(feature = "log"))]
54//! # fn main() {}
55//! ```
56//!
57//! # Feature matrix
58//!
59//! - default: console backend only
60//! - `file`: configurable file output
61//! - `log`: explicit `log` to `tracing` bridge during `init`
62//! - `full`: enables `file` and `log`
63//!
64//! # Non-goals for v0.1
65//!
66//! - query APIs
67//! - target allowlists or message filters
68//! - file rotation or retention policies
69//! - exposing individual internal sink/layer types
70
71#![cfg_attr(docsrs, feature(doc_cfg))]
72
73mod config;
74mod error;
75mod format;
76mod layer;
77mod sink;
78mod sinks;
79
80use std::fmt;
81
82pub use crate::config::Logger;
83pub use crate::error::{BuildError, InitError};
84pub use crate::layer::BackendLayer;
85
86#[cfg(feature = "file")]
87#[cfg_attr(docsrs, doc(cfg(feature = "file")))]
88pub use crate::config::FileConfig;
89
90/// Severity level of a log entry.
91///
92/// Variants are ordered by severity so that comparisons work intuitively:
93/// `Error` is the **most** severe and `Trace` is the **least**.
94///
95/// ```rust
96/// use piquel_log::LogLevel;
97///
98/// assert!(LogLevel::Error < LogLevel::Warn);
99/// assert!(LogLevel::Warn  < LogLevel::Info);
100/// assert!(LogLevel::Info  < LogLevel::Debug);
101/// assert!(LogLevel::Debug < LogLevel::Trace);
102/// ```
103///
104/// This ordering is what powers [`Filter::min_level`]: passing
105/// `LogLevel::Warn` keeps `Error` and `Warn` (both ≤ `Warn` in severity).
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub enum LogLevel {
108    Error = 0,
109    Warn = 1,
110    Info = 2,
111    Debug = 3,
112    Trace = 4,
113}
114
115impl From<LogLevel> for tracing::metadata::LevelFilter {
116    fn from(level: LogLevel) -> Self {
117        match level {
118            LogLevel::Error => Self::ERROR,
119            LogLevel::Warn => Self::WARN,
120            LogLevel::Info => Self::INFO,
121            LogLevel::Debug => Self::DEBUG,
122            LogLevel::Trace => Self::TRACE,
123        }
124    }
125}
126
127impl From<&tracing::Level> for LogLevel {
128    fn from(level: &tracing::Level) -> Self {
129        match *level {
130            tracing::Level::ERROR => Self::Error,
131            tracing::Level::WARN => Self::Warn,
132            tracing::Level::INFO => Self::Info,
133            tracing::Level::DEBUG => Self::Debug,
134            tracing::Level::TRACE => Self::Trace,
135        }
136    }
137}
138
139impl fmt::Display for LogLevel {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        write!(
142            f,
143            "{}",
144            match self {
145                Self::Error => "ERROR",
146                Self::Warn => "WARN",
147                Self::Info => "INFO",
148                Self::Debug => "DEBUG",
149                Self::Trace => "TRACE",
150            }
151        )
152    }
153}