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}