11//! clap [Args](clap::Args) for logging configuration.
22
33use crate :: dirs:: { LogsDir , PlatformPath } ;
4- use clap:: { Args , ValueEnum } ;
4+ use clap:: { ArgAction , Args , ValueEnum } ;
55use reth_tracing:: {
6- tracing_subscriber:: { registry :: LookupSpan , EnvFilter } ,
7- BoxedLayer , FileWorkerGuard ,
6+ tracing_subscriber:: filter :: Directive , FileInfo , FileWorkerGuard , LayerInfo , LogFormat ,
7+ RethTracer , Tracer ,
88} ;
99use 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
1812const MB_TO_BYTES : u64 = 1024 * 1024 ;
1913
2014/// The log configuration.
2115#[ derive( Debug , Args ) ]
2216#[ command( next_help_heading = "Logging" ) ]
2317pub 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
6579impl 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+ }
0 commit comments