@@ -5,6 +5,9 @@ use camino::Utf8Path;
55use std:: io:: IsTerminal ;
66use std:: str:: FromStr ;
77use std:: sync:: Arc ;
8+ use tracing_subscriber:: util:: SubscriberInitExt ;
9+
10+ const DEFAULT_LEVEL : tracing:: Level = tracing:: Level :: INFO ;
811
912#[ macro_export]
1013/// The basic subscriber
@@ -19,9 +22,11 @@ macro_rules! subscriber_builder {
1922
2023/// Configures and enables logging taking into account flags, env variables and file config.
2124///
22- /// 1. Log config is taken from the file configuration first
23- /// 2. If `RUST_LOG` variable is set, it overrides file-based configuration
24- /// 3. If `--debug` or `--log-level` flags are set, they override previous steps
25+ /// Priority order (highest to lowest):
26+ /// 1. `--debug` or `--log-level` flags
27+ /// 2. `RUST_LOG` environment variable
28+ /// 3. File configuration (`system.toml`)
29+ /// 4. Default level (INFO)
2530///
2631/// Reports all the log events sent either with the `log` crate or the `tracing`
2732/// crate.
@@ -30,29 +35,17 @@ pub fn log_init(
3035 flags : & LogConfigArgs ,
3136 config_dir : & Utf8Path ,
3237) -> Result < ( ) , SystemTomlError > {
33- let subscriber = subscriber_builder ! ( ) ;
34-
35- let log_level = flags
36- . log_level
37- . or ( flags. debug . then_some ( tracing:: Level :: DEBUG ) ) ;
38-
39- if let Some ( log_level) = log_level {
40- subscriber. with_max_level ( log_level) . init ( ) ;
41- return Ok ( ( ) ) ;
42- }
43-
44- if std:: env:: var ( "RUST_LOG" ) . is_ok ( ) {
45- subscriber
46- . with_env_filter ( tracing_subscriber:: EnvFilter :: from_default_env ( ) )
47- . with_file ( true )
48- . with_line_number ( true )
49- . init ( ) ;
50- return Ok ( ( ) ) ;
51- }
52-
53- let log_level = get_log_level ( sname, config_dir) ?;
54- subscriber. with_max_level ( log_level) . init ( ) ;
38+ log_init_with_default_level ( sname, flags, config_dir, DEFAULT_LEVEL )
39+ }
5540
41+ pub fn log_init_with_default_level (
42+ sname : & str ,
43+ flags : & LogConfigArgs ,
44+ config_dir : & Utf8Path ,
45+ default_level : tracing:: Level ,
46+ ) -> Result < ( ) , SystemTomlError > {
47+ let logger = logger ( sname, flags, Some ( config_dir) , default_level) ?;
48+ logger. init ( ) ;
5649 Ok ( ( ) )
5750}
5851
@@ -64,6 +57,7 @@ pub fn unconfigured_logger() -> Arc<dyn tracing::Subscriber + Send + Sync> {
6457 log_level : None ,
6558 } ,
6659 None ,
60+ DEFAULT_LEVEL ,
6761 )
6862 . unwrap ( )
6963}
@@ -72,47 +66,59 @@ fn logger(
7266 sname : & str ,
7367 flags : & LogConfigArgs ,
7468 config_dir : Option < & Utf8Path > ,
69+ default_level : tracing:: Level ,
7570) -> Result < Arc < dyn tracing:: Subscriber + Send + Sync > , SystemTomlError > {
76- let subscriber = tracing_subscriber:: fmt ( )
77- . with_writer ( std:: io:: stderr)
78- . with_ansi ( std:: io:: stderr ( ) . is_terminal ( ) && yansi:: Condition :: no_color ( ) )
79- . with_timer ( tracing_subscriber:: fmt:: time:: UtcTime :: rfc_3339 ( ) ) ;
71+ let subscriber = subscriber_builder ! ( ) ;
72+
73+ // first use log level from flags
8074 let log_level = flags
8175 . log_level
8276 . or ( flags. debug . then_some ( tracing:: Level :: DEBUG ) ) ;
8377
8478 if let Some ( log_level) = log_level {
85- Ok ( Arc :: new ( subscriber. with_max_level ( log_level) . finish ( ) ) )
86- } else if std:: env:: var ( "RUST_LOG" ) . is_ok ( ) {
87- Ok ( Arc :: new (
79+ return Ok ( Arc :: new ( subscriber. with_max_level ( log_level) . finish ( ) ) ) ;
80+ }
81+
82+ // if no flags used, use EnvFilter
83+ if std:: env:: var ( "RUST_LOG" ) . is_ok ( ) {
84+ return Ok ( Arc :: new (
8885 subscriber
8986 . with_env_filter ( tracing_subscriber:: EnvFilter :: from_default_env ( ) )
9087 . with_file ( true )
9188 . with_line_number ( true )
9289 . finish ( ) ,
93- ) )
94- } else {
95- let log_level = config_dir
96- . map ( |config_dir| get_log_level ( sname, config_dir) )
97- . unwrap_or ( Ok ( DEFAULT_MAX_LEVEL ) ) ?;
98- Ok ( Arc :: new ( subscriber. with_max_level ( log_level) . finish ( ) ) )
90+ ) ) ;
91+ }
92+
93+ // if no EnvFilter, get log level from config file
94+ if let Some ( log_level) = config_dir. and_then ( |config_dir| {
95+ get_log_level_from_config_file ( sname, config_dir)
96+ . ok ( )
97+ . flatten ( )
98+ } ) {
99+ return Ok ( Arc :: new ( subscriber. with_max_level ( log_level) . finish ( ) ) ) ;
99100 }
100- }
101101
102- const DEFAULT_MAX_LEVEL : tracing:: Level = tracing:: Level :: INFO ;
102+ // otherwise, use the default log level
103+ Ok ( Arc :: new ( subscriber. with_max_level ( default_level) . finish ( ) ) )
104+ }
103105
104- pub fn get_log_level (
106+ /// Return the log level for a given service, if it's defined in the config file. Otherwise return `None`.
107+ pub fn get_log_level_from_config_file (
105108 sname : & str ,
106109 config_dir : & Utf8Path ,
107- ) -> Result < tracing:: Level , SystemTomlError > {
110+ ) -> Result < Option < tracing:: Level > , SystemTomlError > {
108111 let loglevel = SystemConfig :: try_new ( config_dir) ?. log ;
109112 match loglevel. get ( sname) {
110- Some ( ll) => tracing:: Level :: from_str ( & ll. to_uppercase ( ) ) . map_err ( |_| {
111- SystemTomlError :: InvalidLogLevel {
112- name : ll. to_string ( ) ,
113- }
114- } ) ,
115- None => Ok ( tracing:: Level :: INFO ) ,
113+ Some ( ll) => {
114+ let ll = tracing:: Level :: from_str ( & ll. to_uppercase ( ) ) . map_err ( |_| {
115+ SystemTomlError :: InvalidLogLevel {
116+ name : ll. to_string ( ) ,
117+ }
118+ } ) ?;
119+ Ok ( Some ( ll) )
120+ }
121+ None => Ok ( None ) ,
116122 }
117123}
118124
@@ -151,8 +157,8 @@ mod tests {
151157 "# ;
152158
153159 let ( _dir, config_dir) = create_temp_system_config ( toml_conf) ?;
154- let res = get_log_level ( "tedge_mapper" , & config_dir) ?;
155- assert_eq ! ( Level :: DEBUG , res) ;
160+ let res = get_log_level_from_config_file ( "tedge_mapper" , & config_dir) ?;
161+ assert_eq ! ( Some ( Level :: DEBUG ) , res) ;
156162 Ok ( ( ) )
157163 }
158164
@@ -163,7 +169,7 @@ mod tests {
163169 tedge_mapper = "other"
164170 "# ;
165171 let ( _dir, config_dir) = create_temp_system_config ( toml_conf) ?;
166- let res = get_log_level ( "tedge_mapper" , & config_dir) . unwrap_err ( ) ;
172+ let res = get_log_level_from_config_file ( "tedge_mapper" , & config_dir) . unwrap_err ( ) ;
167173 assert_eq ! (
168174 "Invalid log level: \" other\" , supported levels are info, warn, error and debug" ,
169175 res. to_string( )
@@ -179,7 +185,7 @@ mod tests {
179185 "# ;
180186
181187 let ( _dir, config_dir) = create_temp_system_config ( toml_conf) ?;
182- let res = get_log_level ( "tedge_mapper" , & config_dir) . unwrap_err ( ) ;
188+ let res = get_log_level_from_config_file ( "tedge_mapper" , & config_dir) . unwrap_err ( ) ;
183189
184190 assert_eq ! (
185191 "Invalid log level: \" \" , supported levels are info, warn, error and debug" ,
@@ -196,8 +202,8 @@ mod tests {
196202 "# ;
197203
198204 let ( _dir, config_dir) = create_temp_system_config ( toml_conf) ?;
199- let res = get_log_level ( "tedge_mapper" , & config_dir) . unwrap ( ) ;
200- assert_eq ! ( Level :: INFO , res) ;
205+ let res = get_log_level_from_config_file ( "tedge_mapper" , & config_dir) . unwrap ( ) ;
206+ assert_eq ! ( None , res) ;
201207 Ok ( ( ) )
202208 }
203209
0 commit comments