reth_tracing/lib.rs
1//! The `tracing` module provides functionalities for setting up and configuring logging.
2//!
3//! It includes structures and functions to create and manage various logging layers: stdout,
4//! file, or journald. The module's primary entry point is the `Tracer` struct, which can be
5//! configured to use different logging formats and destinations. If no layer is specified, it will
6//! default to stdout.
7//!
8//! # Examples
9//!
10//! Basic usage:
11//!
12//! ```
13//! use reth_tracing::{
14//! LayerInfo, RethTracer, Tracer,
15//! tracing::level_filters::LevelFilter,
16//! LogFormat,
17//! };
18//!
19//! fn main() -> eyre::Result<()> {
20//! let tracer = RethTracer::new().with_stdout(LayerInfo::new(
21//! LogFormat::Json,
22//! LevelFilter::INFO.to_string(),
23//! "debug".to_string(),
24//! None,
25//! ));
26//!
27//! tracer.init()?;
28//!
29//! // Your application logic here
30//!
31//! Ok(())
32//! }
33//! ```
34//!
35//! This example sets up a tracer with JSON format logging for journald and terminal-friendly
36//! format for file logging.
37
38#![doc(
39 html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
40 html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
41 issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
42)]
43#![cfg_attr(not(test), warn(unused_crate_dependencies))]
44#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
45
46// Re-export tracing crates
47pub use tracing;
48pub use tracing_appender;
49pub use tracing_subscriber;
50
51// Re-export our types
52pub use formatter::LogFormat;
53pub use layers::{FileInfo, FileWorkerGuard};
54pub use test_tracer::TestTracer;
55
56mod formatter;
57mod layers;
58mod test_tracer;
59
60use crate::layers::Layers;
61use tracing::level_filters::LevelFilter;
62use tracing_appender::non_blocking::WorkerGuard;
63use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
64
65/// Tracer for application logging.
66///
67/// Manages the configuration and initialization of logging layers,
68/// including standard output, optional journald, and optional file logging.
69#[derive(Debug, Clone)]
70pub struct RethTracer {
71 stdout: LayerInfo,
72 journald: Option<String>,
73 file: Option<(LayerInfo, FileInfo)>,
74}
75
76impl RethTracer {
77 /// Constructs a new `Tracer` with default settings.
78 ///
79 /// Initializes with default stdout layer configuration.
80 /// Journald and file layers are not set by default.
81 pub fn new() -> Self {
82 Self { stdout: LayerInfo::default(), journald: None, file: None }
83 }
84
85 /// Sets a custom configuration for the stdout layer.
86 ///
87 /// # Arguments
88 /// * `config` - The `LayerInfo` to use for the stdout layer.
89 pub fn with_stdout(mut self, config: LayerInfo) -> Self {
90 self.stdout = config;
91 self
92 }
93
94 /// Sets the journald layer filter.
95 ///
96 /// # Arguments
97 /// * `filter` - The `filter` to use for the journald layer.
98 pub fn with_journald(mut self, filter: String) -> Self {
99 self.journald = Some(filter);
100 self
101 }
102
103 /// Sets the file layer configuration and associated file info.
104 ///
105 /// # Arguments
106 /// * `config` - The `LayerInfo` to use for the file layer.
107 /// * `file_info` - The `FileInfo` containing details about the log file.
108 pub fn with_file(mut self, config: LayerInfo, file_info: FileInfo) -> Self {
109 self.file = Some((config, file_info));
110 self
111 }
112}
113
114impl Default for RethTracer {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120/// Configuration for a logging layer.
121///
122/// This struct holds configuration parameters for a tracing layer, including
123/// the format, filtering directives, optional coloring, and directive.
124#[derive(Debug, Clone)]
125pub struct LayerInfo {
126 format: LogFormat,
127 default_directive: String,
128 filters: String,
129 color: Option<String>,
130}
131
132impl LayerInfo {
133 /// Constructs a new `LayerInfo`.
134 ///
135 /// # Arguments
136 /// * `format` - Specifies the format for log messages. Possible values are:
137 /// - `LogFormat::Json` for JSON formatting.
138 /// - `LogFormat::LogFmt` for logfmt (key=value) formatting.
139 /// - `LogFormat::Terminal` for human-readable, terminal-friendly formatting.
140 /// * `default_directive` - Directive for filtering log messages.
141 /// * `filters` - Additional filtering parameters as a string.
142 /// * `color` - Optional color configuration for the log messages.
143 pub const fn new(
144 format: LogFormat,
145 default_directive: String,
146 filters: String,
147 color: Option<String>,
148 ) -> Self {
149 Self { format, default_directive, filters, color }
150 }
151}
152
153impl Default for LayerInfo {
154 /// Provides default values for `LayerInfo`.
155 ///
156 /// By default, it uses terminal format, INFO level filter,
157 /// no additional filters, and no color configuration.
158 fn default() -> Self {
159 Self {
160 format: LogFormat::Terminal,
161 default_directive: LevelFilter::INFO.to_string(),
162 filters: String::new(),
163 color: Some("always".to_string()),
164 }
165 }
166}
167
168/// Trait defining a general interface for logging configuration.
169///
170/// The `Tracer` trait provides a standardized way to initialize logging configurations
171/// in an application. Implementations of this trait can specify different logging setups,
172/// such as standard output logging, file logging, journald logging, or custom logging
173/// configurations tailored for specific environments (like testing).
174pub trait Tracer {
175 /// Initialize the logging configuration.
176 /// # Returns
177 /// An `eyre::Result` which is `Ok` with an optional `WorkerGuard` if a file layer is used,
178 /// or an `Err` in case of an error during initialization.
179 fn init(self) -> eyre::Result<Option<WorkerGuard>>;
180}
181
182impl Tracer for RethTracer {
183 /// Initializes the logging system based on the configured layers.
184 ///
185 /// This method sets up the global tracing subscriber with the specified
186 /// stdout, journald, and file layers.
187 ///
188 /// The default layer is stdout.
189 ///
190 /// # Returns
191 /// An `eyre::Result` which is `Ok` with an optional `WorkerGuard` if a file layer is used,
192 /// or an `Err` in case of an error during initialization.
193 fn init(self) -> eyre::Result<Option<WorkerGuard>> {
194 let mut layers = Layers::new();
195
196 layers.stdout(
197 self.stdout.format,
198 self.stdout.default_directive.parse()?,
199 &self.stdout.filters,
200 self.stdout.color,
201 )?;
202
203 if let Some(config) = self.journald {
204 layers.journald(&config)?;
205 }
206
207 let file_guard = if let Some((config, file_info)) = self.file {
208 Some(layers.file(config.format, &config.filters, file_info)?)
209 } else {
210 None
211 };
212
213 // The error is returned if the global default subscriber is already set,
214 // so it's safe to ignore it
215 let _ = tracing_subscriber::registry().with(layers.into_inner()).try_init();
216 Ok(file_guard)
217 }
218}
219
220/// Initializes a tracing subscriber for tests.
221///
222/// The filter is configurable via `RUST_LOG`.
223///
224/// # Note
225///
226/// The subscriber will silently fail if it could not be installed.
227pub fn init_test_tracing() {
228 let _ = TestTracer::default().init();
229}