Skip to content

Commit 8078c51

Browse files
loocaproshekhirin
andauthored
Json structured logs (#5784)
Co-authored-by: Alexey Shekhirin <[email protected]>
1 parent e122773 commit 8078c51

File tree

7 files changed

+591
-210
lines changed

7 files changed

+591
-210
lines changed

Cargo.lock

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/reth/src/args/log_args.rs

Lines changed: 101 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,41 @@
11
//! clap [Args](clap::Args) for logging configuration.
22
33
use crate::dirs::{LogsDir, PlatformPath};
4-
use clap::{Args, ValueEnum};
4+
use clap::{ArgAction, Args, ValueEnum};
55
use reth_tracing::{
6-
tracing_subscriber::{registry::LookupSpan, EnvFilter},
7-
BoxedLayer, FileWorkerGuard,
6+
tracing_subscriber::filter::Directive, FileInfo, FileWorkerGuard, LayerInfo, LogFormat,
7+
RethTracer, Tracer,
88
};
99
use std::{fmt, fmt::Display};
10-
use tracing::Subscriber;
11-
12-
/// Default [directives](reth_tracing::tracing_subscriber::filter::Directive) for [EnvFilter] which
13-
/// disables high-frequency debug logs from `hyper` and `trust-dns`
14-
const DEFAULT_ENV_FILTER_DIRECTIVES: [&str; 3] =
15-
["hyper::proto::h1=off", "trust_dns_proto=off", "atrust_dns_resolver=off"];
16-
10+
use tracing::{level_filters::LevelFilter, Level};
1711
/// Constant to convert megabytes to bytes
1812
const MB_TO_BYTES: u64 = 1024 * 1024;
1913

2014
/// The log configuration.
2115
#[derive(Debug, Args)]
2216
#[command(next_help_heading = "Logging")]
2317
pub struct LogArgs {
18+
/// The format to use for logs written to stdout.
19+
#[arg(long = "log.stdout.format", value_name = "FORMAT", global = true, default_value_t = LogFormat::Terminal)]
20+
pub log_stdout_format: LogFormat,
21+
22+
/// The filter to use for logs written to stdout.
23+
#[arg(
24+
long = "log.stdout.filter",
25+
value_name = "FILTER",
26+
global = true,
27+
default_value = "info"
28+
)]
29+
pub log_stdout_filter: String,
30+
31+
/// The format to use for logs written to the log file.
32+
#[arg(long = "log.file.format", value_name = "FORMAT", global = true, default_value_t = LogFormat::Terminal)]
33+
pub log_file_format: LogFormat,
34+
35+
/// The filter to use for logs written to the log file.
36+
#[arg(long = "log.file.filter", value_name = "FILTER", global = true, default_value = "debug")]
37+
pub log_file_filter: String,
38+
2439
/// The path to put log files in.
2540
#[arg(long = "log.file.directory", value_name = "PATH", global = true, default_value_t)]
2641
pub log_file_directory: PlatformPath<LogsDir>,
@@ -34,10 +49,6 @@ pub struct LogArgs {
3449
#[arg(long = "log.file.max-files", value_name = "COUNT", global = true, default_value_t = 5)]
3550
pub log_file_max_files: usize,
3651

37-
/// The filter to use for logs written to the log file.
38-
#[arg(long = "log.file.filter", value_name = "FILTER", global = true, default_value = "debug")]
39-
pub log_file_filter: String,
40-
4152
/// Write logs to journald.
4253
#[arg(long = "log.journald", global = true)]
4354
pub journald: bool,
@@ -60,55 +71,50 @@ pub struct LogArgs {
6071
default_value_t = ColorMode::Always
6172
)]
6273
pub color: ColorMode,
74+
/// The verbosity settings for the tracer.
75+
#[clap(flatten)]
76+
pub verbosity: Verbosity,
6377
}
6478

6579
impl LogArgs {
66-
/// Builds tracing layers from the current log options.
67-
pub fn layers<S>(&self) -> eyre::Result<(Vec<BoxedLayer<S>>, Option<FileWorkerGuard>)>
68-
where
69-
S: Subscriber,
70-
for<'a> S: LookupSpan<'a>,
71-
{
72-
let mut layers = Vec::new();
73-
74-
// Function to create a new EnvFilter with environment (from `RUST_LOG` env var), default
75-
// (from `DEFAULT_DIRECTIVES`) and additional directives.
76-
let create_env_filter = |additional_directives: &str| -> eyre::Result<EnvFilter> {
77-
let env_filter = EnvFilter::builder().from_env_lossy();
78-
79-
DEFAULT_ENV_FILTER_DIRECTIVES
80-
.into_iter()
81-
.chain(additional_directives.split(','))
82-
.try_fold(env_filter, |env_filter, directive| {
83-
Ok(env_filter.add_directive(directive.parse()?))
84-
})
85-
};
86-
87-
// Create and add the journald layer if enabled
80+
/// Creates a [LayerInfo] instance.
81+
fn layer(&self, format: LogFormat, filter: String, use_color: bool) -> LayerInfo {
82+
LayerInfo::new(
83+
format,
84+
filter,
85+
self.verbosity.directive(),
86+
if use_color { Some(self.color.to_string()) } else { None },
87+
)
88+
}
89+
90+
/// File info from the current log options.
91+
fn file_info(&self) -> FileInfo {
92+
FileInfo::new(
93+
self.log_file_directory.clone().into(),
94+
self.log_file_max_size * MB_TO_BYTES,
95+
self.log_file_max_files,
96+
)
97+
}
98+
99+
/// Initializes tracing with the configured options from cli args.
100+
pub fn init_tracing(&self) -> eyre::Result<Option<FileWorkerGuard>> {
101+
let mut tracer = RethTracer::new();
102+
103+
let stdout = self.layer(self.log_stdout_format, self.log_stdout_filter.clone(), true);
104+
tracer = tracer.with_stdout(stdout);
105+
88106
if self.journald {
89-
let journald_filter = create_env_filter(&self.journald_filter)?;
90-
layers.push(
91-
reth_tracing::journald(journald_filter).expect("Could not connect to journald"),
92-
);
107+
tracer = tracer.with_journald(self.journald_filter.clone());
93108
}
94109

95-
// Create and add the file logging layer if enabled
96-
let file_guard = if self.log_file_max_files > 0 {
97-
let file_filter = create_env_filter(&self.log_file_filter)?;
98-
let (layer, guard) = reth_tracing::file(
99-
file_filter,
100-
&self.log_file_directory,
101-
"reth.log",
102-
self.log_file_max_size * MB_TO_BYTES,
103-
self.log_file_max_files,
104-
);
105-
layers.push(layer);
106-
Some(guard)
107-
} else {
108-
None
109-
};
110+
if self.log_file_max_files > 0 {
111+
let info = self.file_info();
112+
let file = self.layer(self.log_file_format, self.log_file_filter.clone(), false);
113+
tracer = tracer.with_file(file, info);
114+
}
110115

111-
Ok((layers, file_guard))
116+
let guard = tracer.init()?;
117+
Ok(guard)
112118
}
113119
}
114120

@@ -132,3 +138,42 @@ impl Display for ColorMode {
132138
}
133139
}
134140
}
141+
142+
/// The verbosity settings for the cli.
143+
#[derive(Debug, Copy, Clone, Args)]
144+
#[command(next_help_heading = "Display")]
145+
pub struct Verbosity {
146+
/// Set the minimum log level.
147+
///
148+
/// -v Errors
149+
/// -vv Warnings
150+
/// -vvv Info
151+
/// -vvvv Debug
152+
/// -vvvvv Traces (warning: very verbose!)
153+
#[clap(short, long, action = ArgAction::Count, global = true, default_value_t = 3, verbatim_doc_comment, help_heading = "Display")]
154+
verbosity: u8,
155+
156+
/// Silence all log output.
157+
#[clap(long, alias = "silent", short = 'q', global = true, help_heading = "Display")]
158+
quiet: bool,
159+
}
160+
161+
impl Verbosity {
162+
/// Get the corresponding [Directive] for the given verbosity, or none if the verbosity
163+
/// corresponds to silent.
164+
pub fn directive(&self) -> Directive {
165+
if self.quiet {
166+
LevelFilter::OFF.into()
167+
} else {
168+
let level = match self.verbosity - 1 {
169+
0 => Level::ERROR,
170+
1 => Level::WARN,
171+
2 => Level::INFO,
172+
3 => Level::DEBUG,
173+
_ => Level::TRACE,
174+
};
175+
176+
level.into()
177+
}
178+
}
179+
}

bin/reth/src/cli/mod.rs

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,9 @@ use crate::{
1212
runner::CliRunner,
1313
version::{LONG_VERSION, SHORT_VERSION},
1414
};
15-
use clap::{value_parser, ArgAction, Args, Parser, Subcommand};
15+
use clap::{value_parser, Parser, Subcommand};
1616
use reth_primitives::ChainSpec;
17-
use reth_tracing::{
18-
tracing::{metadata::LevelFilter, Level},
19-
tracing_subscriber::filter::Directive,
20-
FileWorkerGuard,
21-
};
17+
use reth_tracing::FileWorkerGuard;
2218
use std::sync::Arc;
2319

2420
pub mod components;
@@ -67,9 +63,6 @@ pub struct Cli<Ext: RethCliExt = ()> {
6763

6864
#[clap(flatten)]
6965
logs: LogArgs,
70-
71-
#[clap(flatten)]
72-
verbosity: Verbosity,
7366
}
7467

7568
impl<Ext: RethCliExt> Cli<Ext> {
@@ -101,13 +94,7 @@ impl<Ext: RethCliExt> Cli<Ext> {
10194
/// If file logging is enabled, this function returns a guard that must be kept alive to ensure
10295
/// that all logs are flushed to disk.
10396
pub fn init_tracing(&self) -> eyre::Result<Option<FileWorkerGuard>> {
104-
let mut layers =
105-
vec![reth_tracing::stdout(self.verbosity.directive(), &self.logs.color.to_string())];
106-
107-
let (additional_layers, guard) = self.logs.layers()?;
108-
layers.extend(additional_layers);
109-
110-
reth_tracing::init(layers);
97+
let guard = self.logs.init_tracing()?;
11198
Ok(guard)
11299
}
113100

@@ -173,45 +160,6 @@ impl<Ext: RethCliExt> Commands<Ext> {
173160
}
174161
}
175162

176-
/// The verbosity settings for the cli.
177-
#[derive(Debug, Copy, Clone, Args)]
178-
#[command(next_help_heading = "Display")]
179-
pub struct Verbosity {
180-
/// Set the minimum log level.
181-
///
182-
/// -v Errors
183-
/// -vv Warnings
184-
/// -vvv Info
185-
/// -vvvv Debug
186-
/// -vvvvv Traces (warning: very verbose!)
187-
#[clap(short, long, action = ArgAction::Count, global = true, default_value_t = 3, verbatim_doc_comment, help_heading = "Display")]
188-
verbosity: u8,
189-
190-
/// Silence all log output.
191-
#[clap(long, alias = "silent", short = 'q', global = true, help_heading = "Display")]
192-
quiet: bool,
193-
}
194-
195-
impl Verbosity {
196-
/// Get the corresponding [Directive] for the given verbosity, or none if the verbosity
197-
/// corresponds to silent.
198-
pub fn directive(&self) -> Directive {
199-
if self.quiet {
200-
LevelFilter::OFF.into()
201-
} else {
202-
let level = match self.verbosity - 1 {
203-
0 => Level::ERROR,
204-
1 => Level::WARN,
205-
2 => Level::INFO,
206-
3 => Level::DEBUG,
207-
_ => Level::TRACE,
208-
};
209-
210-
format!("{level}").parse().unwrap()
211-
}
212-
}
213-
}
214-
215163
#[cfg(test)]
216164
mod tests {
217165
use clap::CommandFactory;

crates/tracing/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ workspace = true
1313

1414
[dependencies]
1515
tracing.workspace = true
16-
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] }
16+
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "json"] }
1717
tracing-appender.workspace = true
1818
tracing-journald = "0.3"
19+
tracing-logfmt = "0.3.3"
1920
rolling-file = "0.2.0"
21+
eyre.workspace = true
22+
clap = { workspace = true, features = ["derive"] }

0 commit comments

Comments
 (0)