1010use cast:: transmute;
1111use either:: * ;
1212use libc:: { c_void, uintptr_t, c_char, exit, STDERR_FILENO } ;
13- use option:: { Some , None } ;
13+ use option:: { Some , None , Option } ;
1414use rt:: util:: dumb_println;
1515use str:: StrSlice ;
1616use str:: raw:: from_c_str;
@@ -20,7 +20,7 @@ use vec::ImmutableVector;
2020
2121
2222struct LogDirective {
23- name : ~str ,
23+ name : Option < ~str > ,
2424 level : u32
2525}
2626
@@ -30,7 +30,6 @@ struct ModEntry{
3030 log_level : * mut u32
3131}
3232
33- static MAX_LOG_DIRECTIVES : u32 = 255 ;
3433static MAX_LOG_LEVEL : u32 = 255 ;
3534static DEFAULT_LOG_LEVEL : u32 = 1 ;
3635
@@ -68,42 +67,82 @@ fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
6867 data : * c_void ) ;
6968 }
7069}
70+ static log_level_names : & ' static [ & ' static str ] = & ' static[ "error" , "warn" , "info" , "debug" ] ;
71+
72+ /// Parse an individual log level that is either a number or a symbolic log level
73+ fn parse_log_level ( level : & str ) -> Option < u32 > {
74+ let num = u32:: from_str ( level) ;
75+ let mut log_level;
76+ match num {
77+ Some ( num) => {
78+ if num < MAX_LOG_LEVEL {
79+ log_level = Some ( num) ;
80+ } else {
81+ log_level = Some ( MAX_LOG_LEVEL ) ;
82+ }
83+ }
84+ _ => {
85+ let position = log_level_names. iter ( ) . position ( |& name| name == level) ;
86+ match position {
87+ Some ( position) => {
88+ log_level = Some ( u32:: min ( MAX_LOG_LEVEL , ( position + 1 ) as u32 ) )
89+ } ,
90+ _ => {
91+ log_level = None ;
92+ }
93+ }
94+ }
95+ }
96+ log_level
97+ }
98+
7199
72100/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
73101/// and return a vector with log directives.
74- /// Valid log levels are 0-255, with the most likely ones being 0-3 (defined in std::).
102+ /// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
103+ /// Also supports string log levels of error, warn, info, and debug
104+
75105fn parse_logging_spec ( spec : ~str ) -> ~[ LogDirective ] {
76106 let mut dirs = ~[ ] ;
77107 for s in spec. split_iter ( ',' ) {
78108 let parts: ~[ & str ] = s. split_iter ( '=' ) . collect ( ) ;
79- let mut loglevel;
109+ let mut log_level;
110+ let mut name = Some ( parts[ 0 ] . to_owned ( ) ) ;
80111 match parts. len ( ) {
81- 1 => loglevel = MAX_LOG_LEVEL ,
82- 2 => {
83- let num = u32:: from_str ( parts[ 1 ] ) ;
84- match ( num) {
112+ 1 => {
113+ //if the single argument is a log-level string or number,
114+ //treat that as a global fallback
115+ let possible_log_level = parse_log_level ( parts[ 0 ] ) ;
116+ match possible_log_level {
85117 Some ( num) => {
86- if num < MAX_LOG_LEVEL {
87- loglevel = num;
88- } else {
89- loglevel = MAX_LOG_LEVEL ;
90- }
118+ name = None ;
119+ log_level = num;
120+ } ,
121+ _ => {
122+ log_level = MAX_LOG_LEVEL
91123 }
124+ }
125+ }
126+ 2 => {
127+ let possible_log_level = parse_log_level ( parts[ 1 ] ) ;
128+ match possible_log_level {
129+ Some ( num) => {
130+ log_level = num;
131+ } ,
92132 _ => {
93- dumb_println ( fmt ! ( "warning: invalid logging spec \
94- '%s', ignoring it", s ) ) ;
95- loop ;
133+ dumb_println ( fmt ! ( "warning: invalid logging spec \
134+ '%s', ignoring it", parts [ 1 ] ) ) ;
135+ loop ;
96136 }
97137 }
98- if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL }
99138 } ,
100139 _ => {
101140 dumb_println ( fmt ! ( "warning: invalid logging spec '%s',\
102141 ignoring it", s) ) ;
103142 loop ;
104143 }
105144 }
106- let dir = LogDirective { name : parts [ 0 ] . to_owned ( ) , level : loglevel } ;
145+ let dir = LogDirective { name : name , level : log_level } ;
107146 dirs. push ( dir) ;
108147 }
109148 return dirs;
@@ -113,18 +152,30 @@ fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
113152/// of log directives
114153fn update_entry ( dirs : & [ LogDirective ] , entry : * mut ModEntry ) -> u32 {
115154 let mut new_lvl: u32 = DEFAULT_LOG_LEVEL ;
116- let mut longest_match = 0 ;
155+ let mut longest_match = - 1 i ;
117156 unsafe {
118157 for dir in dirs. iter ( ) {
119- let name = from_c_str ( ( * entry) . name ) ;
120- if name. starts_with ( dir. name ) && dir. name . len ( ) > longest_match {
121- longest_match = dir. name . len ( ) ;
122- new_lvl = dir. level ;
123- }
158+ match dir. name {
159+ None => {
160+ if longest_match == -1 {
161+ longest_match = 0 ;
162+ new_lvl = dir. level ;
163+ }
164+ }
165+ Some ( ref dir_name) => {
166+ let name = from_c_str ( ( * entry) . name ) ;
167+ let len = dir_name. len ( ) as int ;
168+ if name. starts_with ( * dir_name) &&
169+ len >= longest_match {
170+ longest_match = len;
171+ new_lvl = dir. level ;
172+ }
173+ }
174+ } ;
124175 }
125176 * ( * entry) . log_level = new_lvl;
126177 }
127- if longest_match > 0 { return 1 ; } else { return 0 ; }
178+ if longest_match >= 0 { return 1 ; } else { return 0 ; }
128179}
129180
130181#[ fixed_stack_segment] #[ inline( never) ]
@@ -238,45 +289,66 @@ extern {
238289// Tests for parse_logging_spec()
239290#[ test]
240291fn parse_logging_spec_valid( ) {
241- let dirs: ~ [ LogDirective ] = parse_logging_spec ( ~"crate1:: mod1=1 , crate1:: mod2, crate2=4 ") ;
292+ let dirs = parse_logging_spec ( ~"crate1:: mod1=1 , crate1:: mod2, crate2=4 ") ;
242293 assert_eq ! ( dirs. len( ) , 3 ) ;
243- assert ! ( dirs[ 0 ] . name == ~"crate1:: mod1");
294+ assert!( dirs[ 0 ] . name == Some ( ~"crate1:: mod1") );
244295 assert_eq!(dirs[0].level, 1);
245296
246- assert!(dirs[1].name == ~" crate1:: mod2");
297+ assert!(dirs[1].name == Some( ~" crate1:: mod2") );
247298 assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
248299
249- assert!(dirs[2].name == ~" crate2");
300+ assert!(dirs[2].name == Some( ~" crate2") );
250301 assert_eq!(dirs[2].level, 4);
251302}
252303
253304#[test]
254305fn parse_logging_spec_invalid_crate() {
255306 // test parse_logging_spec with multiple = in specification
256- let dirs: ~[LogDirective] = parse_logging_spec(~" crate1:: mod1=1 =2 , crate2=4 ");
307+ let dirs = parse_logging_spec(~" crate1:: mod1=1 =2 , crate2=4 ");
257308 assert_eq!(dirs.len(), 1);
258- assert!(dirs[0].name == ~" crate2");
309+ assert!(dirs[0].name == Some( ~" crate2") );
259310 assert_eq!(dirs[0].level, 4);
260311}
261312
262313#[test]
263314fn parse_logging_spec_invalid_log_level() {
264315 // test parse_logging_spec with 'noNumber' as log level
265- let dirs: ~[LogDirective] = parse_logging_spec(~" crate1:: mod1=noNumber, crate2=4 ");
316+ let dirs = parse_logging_spec(~" crate1:: mod1=noNumber, crate2=4 ");
266317 assert_eq!(dirs.len(), 1);
267- assert!(dirs[0].name == ~" crate2");
318+ assert!(dirs[0].name == Some( ~" crate2") );
268319 assert_eq!(dirs[0].level, 4);
269320}
270321
322+ #[test]
323+ fn parse_logging_spec_string_log_level() {
324+ // test parse_logging_spec with 'warn' as log level
325+ let dirs = parse_logging_spec(~" crate1:: mod1=wrong, crate2=warn");
326+ assert_eq!(dirs.len(), 1);
327+ assert!(dirs[0].name == Some(~" crate2"));
328+ assert_eq!(dirs[0].level, 2);
329+ }
330+
331+ #[test]
332+ fn parse_logging_spec_global() {
333+ // test parse_logging_spec with no crate
334+ let dirs = parse_logging_spec(~" warn, crate2=4 ");
335+ assert_eq!(dirs.len(), 2);
336+ assert!(dirs[0].name == None);
337+ assert_eq!(dirs[0].level, 2);
338+ assert!(dirs[1].name == Some(~" crate2"));
339+ assert_eq!(dirs[1].level, 4);
340+ }
341+
271342// Tests for update_entry
272343#[test]
273344fn update_entry_match_full_path() {
274345 use c_str::ToCStr;
275- let dirs = ~[LogDirective {name: ~" crate1:: mod1", level: 2 },
276- LogDirective {name: ~" crate2", level: 3}];
346+ let dirs = ~[LogDirective {name: Some(~" crate1:: mod1"), level: 2 },
347+ LogDirective {name: Some(~" crate2"), level: 3}];
348+ let level = &mut 0;
277349 unsafe {
278350 do " crate1:: mod1".to_c_str().with_ref |ptr| {
279- let entry= &ModEntry {name: ptr, log_level: &mut 0 };
351+ let entry= &ModEntry {name: ptr, log_level: level };
280352 let m = update_entry(dirs, transmute(entry));
281353 assert!(*entry.log_level == 2);
282354 assert!(m == 1);
@@ -287,11 +359,12 @@ fn update_entry_match_full_path() {
287359#[test]
288360fn update_entry_no_match() {
289361 use c_str::ToCStr;
290- let dirs = ~[LogDirective {name: ~" crate1:: mod1", level: 2 },
291- LogDirective {name: ~" crate2", level: 3}];
362+ let dirs = ~[LogDirective {name: Some(~" crate1:: mod1"), level: 2 },
363+ LogDirective {name: Some(~" crate2"), level: 3}];
364+ let level = &mut 0;
292365 unsafe {
293366 do " crate3:: mod1".to_c_str().with_ref |ptr| {
294- let entry= &ModEntry {name: ptr, log_level: &mut 0 };
367+ let entry= &ModEntry {name: ptr, log_level: level };
295368 let m = update_entry(dirs, transmute(entry));
296369 assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
297370 assert!(m == 0);
@@ -302,11 +375,12 @@ fn update_entry_no_match() {
302375#[test]
303376fn update_entry_match_beginning() {
304377 use c_str::ToCStr;
305- let dirs = ~[LogDirective {name: ~" crate1:: mod1", level: 2 },
306- LogDirective {name: ~" crate2", level: 3}];
378+ let dirs = ~[LogDirective {name: Some(~" crate1:: mod1"), level: 2 },
379+ LogDirective {name: Some(~" crate2"), level: 3}];
380+ let level = &mut 0;
307381 unsafe {
308382 do " crate2:: mod1".to_c_str().with_ref |ptr| {
309- let entry= &ModEntry {name: ptr, log_level: &mut 0 };
383+ let entry= &ModEntry {name: ptr, log_level: level };
310384 let m = update_entry(dirs, transmute(entry));
311385 assert!(*entry.log_level == 3);
312386 assert!(m == 1);
@@ -317,14 +391,39 @@ fn update_entry_match_beginning() {
317391#[test]
318392fn update_entry_match_beginning_longest_match() {
319393 use c_str::ToCStr;
320- let dirs = ~[LogDirective {name: ~" crate1:: mod1", level: 2 },
321- LogDirective {name: ~" crate2", level: 3}, LogDirective {name: ~" crate2:: mod ", level: 4}];
394+ let dirs = ~[LogDirective {name: Some(~" crate1:: mod1"), level: 2 },
395+ LogDirective {name: Some(~" crate2"), level: 3},
396+ LogDirective {name: Some(~" crate2:: mod "), level: 4}];
397+ let level = &mut 0;
322398 unsafe {
323399 do " crate2:: mod1".to_c_str().with_ref |ptr| {
324- let entry = & ModEntry { name: ptr, log_level: & mut 0 } ;
400+ let entry = &ModEntry {name: ptr, log_level: level };
325401 let m = update_entry(dirs, transmute(entry));
326402 assert!(*entry.log_level == 4);
327403 assert!(m == 1);
328404 }
329405 }
330406}
407+
408+ #[test]
409+ fn update_entry_match_default() {
410+ use c_str::ToCStr;
411+ let dirs = ~[LogDirective {name: Some(~" crate1:: mod1"), level: 2 },
412+ LogDirective {name: None, level: 3}
413+ ];
414+ let level = &mut 0;
415+ unsafe {
416+ do " crate1:: mod1".to_c_str().with_ref |ptr| {
417+ let entry= &ModEntry {name: ptr, log_level: level};
418+ let m = update_entry(dirs, transmute(entry));
419+ assert!(*entry.log_level == 2);
420+ assert!(m == 1);
421+ }
422+ do " crate2:: mod2" . to_c_str( ) . with_ref |ptr| {
423+ let entry= & ModEntry { name: ptr, log_level: level} ;
424+ let m = update_entry( dirs, transmute( entry) ) ;
425+ assert!( * entry. log_level == 3 ) ;
426+ assert!( m == 1 ) ;
427+ }
428+ }
429+ }
0 commit comments