10
10
use cast:: transmute;
11
11
use either:: * ;
12
12
use libc:: { c_void, uintptr_t, c_char, exit, STDERR_FILENO } ;
13
- use option:: { Some , None } ;
13
+ use option:: { Some , None , Option } ;
14
14
use rt:: util:: dumb_println;
15
15
use str:: StrSlice ;
16
16
use str:: raw:: from_c_str;
@@ -20,7 +20,7 @@ use vec::ImmutableVector;
20
20
21
21
22
22
struct LogDirective {
23
- name : ~str ,
23
+ name : Option < ~str > ,
24
24
level : u32
25
25
}
26
26
@@ -30,7 +30,6 @@ struct ModEntry{
30
30
log_level : * mut u32
31
31
}
32
32
33
- static MAX_LOG_DIRECTIVES : u32 = 255 ;
34
33
static MAX_LOG_LEVEL : u32 = 255 ;
35
34
static DEFAULT_LOG_LEVEL : u32 = 1 ;
36
35
@@ -68,42 +67,82 @@ fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
68
67
data : * c_void ) ;
69
68
}
70
69
}
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
+
71
99
72
100
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
73
101
/// 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
+
75
105
fn parse_logging_spec ( spec : ~str ) -> ~[ LogDirective ] {
76
106
let mut dirs = ~[ ] ;
77
107
for s in spec. split_iter ( ',' ) {
78
108
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 ( ) ) ;
80
111
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 {
85
117
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
91
123
}
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
+ } ,
92
132
_ => {
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 ;
96
136
}
97
137
}
98
- if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL }
99
138
} ,
100
139
_ => {
101
140
dumb_println ( fmt ! ( "warning: invalid logging spec '%s',\
102
141
ignoring it", s) ) ;
103
142
loop ;
104
143
}
105
144
}
106
- let dir = LogDirective { name : parts [ 0 ] . to_owned ( ) , level : loglevel } ;
145
+ let dir = LogDirective { name : name , level : log_level } ;
107
146
dirs. push ( dir) ;
108
147
}
109
148
return dirs;
@@ -113,18 +152,30 @@ fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
113
152
/// of log directives
114
153
fn update_entry ( dirs : & [ LogDirective ] , entry : * mut ModEntry ) -> u32 {
115
154
let mut new_lvl: u32 = DEFAULT_LOG_LEVEL ;
116
- let mut longest_match = 0 ;
155
+ let mut longest_match = - 1 i ;
117
156
unsafe {
118
157
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
+ } ;
124
175
}
125
176
* ( * entry) . log_level = new_lvl;
126
177
}
127
- if longest_match > 0 { return 1 ; } else { return 0 ; }
178
+ if longest_match >= 0 { return 1 ; } else { return 0 ; }
128
179
}
129
180
130
181
#[ fixed_stack_segment] #[ inline( never) ]
@@ -238,45 +289,66 @@ extern {
238
289
// Tests for parse_logging_spec()
239
290
#[ test]
240
291
fn 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 ") ;
242
293
assert_eq ! ( dirs. len( ) , 3 ) ;
243
- assert ! ( dirs[ 0 ] . name == ~"crate1:: mod1");
294
+ assert!( dirs[ 0 ] . name == Some ( ~"crate1:: mod1") );
244
295
assert_eq!(dirs[0].level, 1);
245
296
246
- assert!(dirs[1].name == ~" crate1:: mod2");
297
+ assert!(dirs[1].name == Some( ~" crate1:: mod2") );
247
298
assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
248
299
249
- assert!(dirs[2].name == ~" crate2");
300
+ assert!(dirs[2].name == Some( ~" crate2") );
250
301
assert_eq!(dirs[2].level, 4);
251
302
}
252
303
253
304
#[test]
254
305
fn parse_logging_spec_invalid_crate() {
255
306
// 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 ");
257
308
assert_eq!(dirs.len(), 1);
258
- assert!(dirs[0].name == ~" crate2");
309
+ assert!(dirs[0].name == Some( ~" crate2") );
259
310
assert_eq!(dirs[0].level, 4);
260
311
}
261
312
262
313
#[test]
263
314
fn parse_logging_spec_invalid_log_level() {
264
315
// 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 ");
266
317
assert_eq!(dirs.len(), 1);
267
- assert!(dirs[0].name == ~" crate2");
318
+ assert!(dirs[0].name == Some( ~" crate2") );
268
319
assert_eq!(dirs[0].level, 4);
269
320
}
270
321
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
+
271
342
// Tests for update_entry
272
343
#[test]
273
344
fn update_entry_match_full_path() {
274
345
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;
277
349
unsafe {
278
350
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 };
280
352
let m = update_entry(dirs, transmute(entry));
281
353
assert!(*entry.log_level == 2);
282
354
assert!(m == 1);
@@ -287,11 +359,12 @@ fn update_entry_match_full_path() {
287
359
#[test]
288
360
fn update_entry_no_match() {
289
361
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;
292
365
unsafe {
293
366
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 };
295
368
let m = update_entry(dirs, transmute(entry));
296
369
assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
297
370
assert!(m == 0);
@@ -302,11 +375,12 @@ fn update_entry_no_match() {
302
375
#[test]
303
376
fn update_entry_match_beginning() {
304
377
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;
307
381
unsafe {
308
382
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 };
310
384
let m = update_entry(dirs, transmute(entry));
311
385
assert!(*entry.log_level == 3);
312
386
assert!(m == 1);
@@ -317,14 +391,39 @@ fn update_entry_match_beginning() {
317
391
#[test]
318
392
fn update_entry_match_beginning_longest_match() {
319
393
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;
322
398
unsafe {
323
399
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 };
325
401
let m = update_entry(dirs, transmute(entry));
326
402
assert!(*entry.log_level == 4);
327
403
assert!(m == 1);
328
404
}
329
405
}
330
406
}
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