reth_tracing/
formatter.rs

1use crate::layers::BoxedLayer;
2use clap::ValueEnum;
3use std::{fmt, fmt::Display};
4use tracing_appender::non_blocking::NonBlocking;
5use tracing_subscriber::{EnvFilter, Layer, Registry};
6
7/// Represents the logging format.
8///
9/// This enum defines the supported formats for logging output.
10/// It is used to configure the format layer of a tracing subscriber.
11#[derive(Debug, Copy, Clone, ValueEnum, Eq, PartialEq)]
12pub enum LogFormat {
13    /// Represents JSON formatting for logs.
14    /// This format outputs log records as JSON objects,
15    /// making it suitable for structured logging.
16    Json,
17
18    /// Represents logfmt (key=value) formatting for logs.
19    /// This format is concise and human-readable,
20    /// typically used in command-line applications.
21    LogFmt,
22
23    /// Represents terminal-friendly formatting for logs.
24    Terminal,
25}
26
27impl LogFormat {
28    /// Applies the specified logging format to create a new layer.
29    ///
30    /// This method constructs a tracing layer with the selected format,
31    /// along with additional configurations for filtering and output.
32    ///
33    /// # Arguments
34    /// * `filter` - An `EnvFilter` used to determine which log records to output.
35    /// * `color` - An optional string that enables or disables ANSI color codes in the logs.
36    /// * `file_writer` - An optional `NonBlocking` writer for directing logs to a file.
37    ///
38    /// # Returns
39    /// A `BoxedLayer<Registry>` that can be added to a tracing subscriber.
40    pub fn apply(
41        &self,
42        filter: EnvFilter,
43        color: Option<String>,
44        file_writer: Option<NonBlocking>,
45    ) -> BoxedLayer<Registry> {
46        let ansi = if let Some(color) = color {
47            std::env::var("RUST_LOG_STYLE").map(|val| val != "never").unwrap_or(color != "never")
48        } else {
49            false
50        };
51        let target = std::env::var("RUST_LOG_TARGET")
52            // `RUST_LOG_TARGET` always overrides default behaviour
53            .map(|val| val != "0")
54            .unwrap_or_else(|_|
55                // If `RUST_LOG_TARGET` is not set, show target in logs only if the max enabled
56                // level is higher than INFO (DEBUG, TRACE)
57                filter.max_level_hint().is_none_or(|max_level| max_level > tracing::Level::INFO));
58
59        match self {
60            Self::Json => {
61                let layer =
62                    tracing_subscriber::fmt::layer().json().with_ansi(ansi).with_target(target);
63
64                if let Some(writer) = file_writer {
65                    layer.with_writer(writer).with_filter(filter).boxed()
66                } else {
67                    layer.with_filter(filter).boxed()
68                }
69            }
70            Self::LogFmt => tracing_logfmt::layer().with_filter(filter).boxed(),
71            Self::Terminal => {
72                let layer = tracing_subscriber::fmt::layer().with_ansi(ansi).with_target(target);
73
74                if let Some(writer) = file_writer {
75                    layer.with_writer(writer).with_filter(filter).boxed()
76                } else {
77                    layer.with_filter(filter).boxed()
78                }
79            }
80        }
81    }
82}
83
84impl Display for LogFormat {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        match self {
87            Self::Json => write!(f, "json"),
88            Self::LogFmt => write!(f, "logfmt"),
89            Self::Terminal => write!(f, "terminal"),
90        }
91    }
92}