@@ -3,23 +3,38 @@ use log::LevelFilter;
3
3
use crate :: Directive ;
4
4
use crate :: FilterOp ;
5
5
6
+ #[ derive( Default , Debug ) ]
7
+ pub ( crate ) struct ParseResult {
8
+ pub ( crate ) directives : Vec < Directive > ,
9
+ pub ( crate ) filter : Option < FilterOp > ,
10
+ pub ( crate ) errors : Vec < String > ,
11
+ }
12
+
13
+ impl ParseResult {
14
+ fn add_directive ( & mut self , directive : Directive ) {
15
+ self . directives . push ( directive) ;
16
+ }
17
+
18
+ fn set_filter ( & mut self , filter : FilterOp ) {
19
+ self . filter = Some ( filter) ;
20
+ }
21
+
22
+ fn add_error ( & mut self , message : String ) {
23
+ self . errors . push ( message) ;
24
+ }
25
+ }
26
+
6
27
/// Parse a logging specification string (e.g: `crate1,crate2::mod3,crate3::x=error/foo`)
7
28
/// and return a vector with log directives.
8
- pub ( crate ) fn parse_spec ( spec : & str ) -> ( Vec < Directive > , Option < FilterOp > ) {
9
- #![ allow( clippy:: print_stderr) ] // compatibility
10
-
11
- let mut dirs = Vec :: new ( ) ;
29
+ pub ( crate ) fn parse_spec ( spec : & str ) -> ParseResult {
30
+ let mut result = ParseResult :: default ( ) ;
12
31
13
32
let mut parts = spec. split ( '/' ) ;
14
33
let mods = parts. next ( ) ;
15
34
let filter = parts. next ( ) ;
16
35
if parts. next ( ) . is_some ( ) {
17
- eprintln ! (
18
- "warning: invalid logging spec '{}', \
19
- ignoring it (too many '/'s)",
20
- spec
21
- ) ;
22
- return ( dirs, None ) ;
36
+ result. add_error ( format ! ( "invalid logging spec '{}' (too many '/'s)" , spec) ) ;
37
+ return result;
23
38
}
24
39
if let Some ( m) = mods {
25
40
for s in m. split ( ',' ) . map ( |ss| ss. trim ( ) ) {
@@ -42,50 +57,47 @@ pub(crate) fn parse_spec(spec: &str) -> (Vec<Directive>, Option<FilterOp>) {
42
57
if let Ok ( num) = part1. parse ( ) {
43
58
( num, Some ( part0) )
44
59
} else {
45
- eprintln ! (
46
- "warning: invalid logging spec '{}', \
47
- ignoring it",
48
- part1
49
- ) ;
60
+ result. add_error ( format ! ( "invalid logging spec '{}'" , part1) ) ;
50
61
continue ;
51
62
}
52
63
}
53
64
_ => {
54
- eprintln ! (
55
- "warning: invalid logging spec '{}', \
56
- ignoring it",
57
- s
58
- ) ;
65
+ result. add_error ( format ! ( "invalid logging spec '{}'" , s) ) ;
59
66
continue ;
60
67
}
61
68
} ;
62
- dirs. push ( Directive {
69
+
70
+ result. add_directive ( Directive {
63
71
name : name. map ( |s| s. to_owned ( ) ) ,
64
72
level : log_level,
65
73
} ) ;
66
74
}
67
75
}
68
76
69
- let filter = filter. and_then ( |filter| match FilterOp :: new ( filter) {
70
- Ok ( re) => Some ( re) ,
71
- Err ( e) => {
72
- eprintln ! ( "warning: invalid regex filter - {}" , e) ;
73
- None
77
+ if let Some ( filter) = filter {
78
+ match FilterOp :: new ( filter) {
79
+ Ok ( filter_op) => result. set_filter ( filter_op) ,
80
+ Err ( err) => result. add_error ( format ! ( "invalid regex filter - {}" , err) ) ,
74
81
}
75
- } ) ;
82
+ }
76
83
77
- ( dirs , filter )
84
+ result
78
85
}
79
86
80
87
#[ cfg( test) ]
81
88
mod tests {
82
89
use log:: LevelFilter ;
83
90
84
- use super :: parse_spec;
91
+ use super :: { parse_spec, ParseResult } ;
85
92
86
93
#[ test]
87
94
fn parse_spec_valid ( ) {
88
- let ( dirs, filter) = parse_spec ( "crate1::mod1=error,crate1::mod2,crate2=debug" ) ;
95
+ let ParseResult {
96
+ directives : dirs,
97
+ filter,
98
+ ..
99
+ } = parse_spec ( "crate1::mod1=error,crate1::mod2,crate2=debug" ) ;
100
+
89
101
assert_eq ! ( dirs. len( ) , 3 ) ;
90
102
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1::mod1" . to_owned( ) ) ) ;
91
103
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Error ) ;
@@ -101,7 +113,12 @@ mod tests {
101
113
#[ test]
102
114
fn parse_spec_invalid_crate ( ) {
103
115
// test parse_spec with multiple = in specification
104
- let ( dirs, filter) = parse_spec ( "crate1::mod1=warn=info,crate2=debug" ) ;
116
+ let ParseResult {
117
+ directives : dirs,
118
+ filter,
119
+ ..
120
+ } = parse_spec ( "crate1::mod1=warn=info,crate2=debug" ) ;
121
+
105
122
assert_eq ! ( dirs. len( ) , 1 ) ;
106
123
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
107
124
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
@@ -111,7 +128,12 @@ mod tests {
111
128
#[ test]
112
129
fn parse_spec_invalid_level ( ) {
113
130
// test parse_spec with 'noNumber' as log level
114
- let ( dirs, filter) = parse_spec ( "crate1::mod1=noNumber,crate2=debug" ) ;
131
+ let ParseResult {
132
+ directives : dirs,
133
+ filter,
134
+ ..
135
+ } = parse_spec ( "crate1::mod1=noNumber,crate2=debug" ) ;
136
+
115
137
assert_eq ! ( dirs. len( ) , 1 ) ;
116
138
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
117
139
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
@@ -121,7 +143,12 @@ mod tests {
121
143
#[ test]
122
144
fn parse_spec_string_level ( ) {
123
145
// test parse_spec with 'warn' as log level
124
- let ( dirs, filter) = parse_spec ( "crate1::mod1=wrong,crate2=warn" ) ;
146
+ let ParseResult {
147
+ directives : dirs,
148
+ filter,
149
+ ..
150
+ } = parse_spec ( "crate1::mod1=wrong,crate2=warn" ) ;
151
+
125
152
assert_eq ! ( dirs. len( ) , 1 ) ;
126
153
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
127
154
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Warn ) ;
@@ -131,7 +158,12 @@ mod tests {
131
158
#[ test]
132
159
fn parse_spec_empty_level ( ) {
133
160
// test parse_spec with '' as log level
134
- let ( dirs, filter) = parse_spec ( "crate1::mod1=wrong,crate2=" ) ;
161
+ let ParseResult {
162
+ directives : dirs,
163
+ filter,
164
+ ..
165
+ } = parse_spec ( "crate1::mod1=wrong,crate2=" ) ;
166
+
135
167
assert_eq ! ( dirs. len( ) , 1 ) ;
136
168
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
137
169
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: max( ) ) ;
@@ -141,7 +173,11 @@ mod tests {
141
173
#[ test]
142
174
fn parse_spec_empty_level_isolated ( ) {
143
175
// test parse_spec with "" as log level (and the entire spec str)
144
- let ( dirs, filter) = parse_spec ( "" ) ; // should be ignored
176
+ let ParseResult {
177
+ directives : dirs,
178
+ filter,
179
+ ..
180
+ } = parse_spec ( "" ) ; // should be ignored
145
181
assert_eq ! ( dirs. len( ) , 0 ) ;
146
182
assert ! ( filter. is_none( ) ) ;
147
183
}
@@ -150,7 +186,11 @@ mod tests {
150
186
fn parse_spec_blank_level_isolated ( ) {
151
187
// test parse_spec with a white-space-only string specified as the log
152
188
// level (and the entire spec str)
153
- let ( dirs, filter) = parse_spec ( " " ) ; // should be ignored
189
+ let ParseResult {
190
+ directives : dirs,
191
+ filter,
192
+ ..
193
+ } = parse_spec ( " " ) ; // should be ignored
154
194
assert_eq ! ( dirs. len( ) , 0 ) ;
155
195
assert ! ( filter. is_none( ) ) ;
156
196
}
@@ -160,7 +200,11 @@ mod tests {
160
200
// The spec should contain zero or more comma-separated string slices,
161
201
// so a comma-only string should be interpreted as two empty strings
162
202
// (which should both be treated as invalid, so ignored).
163
- let ( dirs, filter) = parse_spec ( "," ) ; // should be ignored
203
+ let ParseResult {
204
+ directives : dirs,
205
+ filter,
206
+ ..
207
+ } = parse_spec ( "," ) ; // should be ignored
164
208
assert_eq ! ( dirs. len( ) , 0 ) ;
165
209
assert ! ( filter. is_none( ) ) ;
166
210
}
@@ -171,7 +215,11 @@ mod tests {
171
215
// so this bogus spec should be interpreted as containing one empty
172
216
// string and one blank string. Both should both be treated as
173
217
// invalid, so ignored.
174
- let ( dirs, filter) = parse_spec ( ", " ) ; // should be ignored
218
+ let ParseResult {
219
+ directives : dirs,
220
+ filter,
221
+ ..
222
+ } = parse_spec ( ", " ) ; // should be ignored
175
223
assert_eq ! ( dirs. len( ) , 0 ) ;
176
224
assert ! ( filter. is_none( ) ) ;
177
225
}
@@ -182,15 +230,23 @@ mod tests {
182
230
// so this bogus spec should be interpreted as containing one blank
183
231
// string and one empty string. Both should both be treated as
184
232
// invalid, so ignored.
185
- let ( dirs, filter) = parse_spec ( " ," ) ; // should be ignored
233
+ let ParseResult {
234
+ directives : dirs,
235
+ filter,
236
+ ..
237
+ } = parse_spec ( " ," ) ; // should be ignored
186
238
assert_eq ! ( dirs. len( ) , 0 ) ;
187
239
assert ! ( filter. is_none( ) ) ;
188
240
}
189
241
190
242
#[ test]
191
243
fn parse_spec_global ( ) {
192
244
// test parse_spec with no crate
193
- let ( dirs, filter) = parse_spec ( "warn,crate2=debug" ) ;
245
+ let ParseResult {
246
+ directives : dirs,
247
+ filter,
248
+ ..
249
+ } = parse_spec ( "warn,crate2=debug" ) ;
194
250
assert_eq ! ( dirs. len( ) , 2 ) ;
195
251
assert_eq ! ( dirs[ 0 ] . name, None ) ;
196
252
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Warn ) ;
@@ -202,7 +258,11 @@ mod tests {
202
258
#[ test]
203
259
fn parse_spec_global_bare_warn_lc ( ) {
204
260
// test parse_spec with no crate, in isolation, all lowercase
205
- let ( dirs, filter) = parse_spec ( "warn" ) ;
261
+ let ParseResult {
262
+ directives : dirs,
263
+ filter,
264
+ ..
265
+ } = parse_spec ( "warn" ) ;
206
266
assert_eq ! ( dirs. len( ) , 1 ) ;
207
267
assert_eq ! ( dirs[ 0 ] . name, None ) ;
208
268
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Warn ) ;
@@ -212,7 +272,11 @@ mod tests {
212
272
#[ test]
213
273
fn parse_spec_global_bare_warn_uc ( ) {
214
274
// test parse_spec with no crate, in isolation, all uppercase
215
- let ( dirs, filter) = parse_spec ( "WARN" ) ;
275
+ let ParseResult {
276
+ directives : dirs,
277
+ filter,
278
+ ..
279
+ } = parse_spec ( "WARN" ) ;
216
280
assert_eq ! ( dirs. len( ) , 1 ) ;
217
281
assert_eq ! ( dirs[ 0 ] . name, None ) ;
218
282
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Warn ) ;
@@ -222,7 +286,11 @@ mod tests {
222
286
#[ test]
223
287
fn parse_spec_global_bare_warn_mixed ( ) {
224
288
// test parse_spec with no crate, in isolation, mixed case
225
- let ( dirs, filter) = parse_spec ( "wArN" ) ;
289
+ let ParseResult {
290
+ directives : dirs,
291
+ filter,
292
+ ..
293
+ } = parse_spec ( "wArN" ) ;
226
294
assert_eq ! ( dirs. len( ) , 1 ) ;
227
295
assert_eq ! ( dirs[ 0 ] . name, None ) ;
228
296
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Warn ) ;
@@ -231,7 +299,11 @@ mod tests {
231
299
232
300
#[ test]
233
301
fn parse_spec_valid_filter ( ) {
234
- let ( dirs, filter) = parse_spec ( "crate1::mod1=error,crate1::mod2,crate2=debug/abc" ) ;
302
+ let ParseResult {
303
+ directives : dirs,
304
+ filter,
305
+ ..
306
+ } = parse_spec ( "crate1::mod1=error,crate1::mod2,crate2=debug/abc" ) ;
235
307
assert_eq ! ( dirs. len( ) , 3 ) ;
236
308
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1::mod1" . to_owned( ) ) ) ;
237
309
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Error ) ;
@@ -246,7 +318,12 @@ mod tests {
246
318
247
319
#[ test]
248
320
fn parse_spec_invalid_crate_filter ( ) {
249
- let ( dirs, filter) = parse_spec ( "crate1::mod1=error=warn,crate2=debug/a.c" ) ;
321
+ let ParseResult {
322
+ directives : dirs,
323
+ filter,
324
+ ..
325
+ } = parse_spec ( "crate1::mod1=error=warn,crate2=debug/a.c" ) ;
326
+
250
327
assert_eq ! ( dirs. len( ) , 1 ) ;
251
328
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_owned( ) ) ) ;
252
329
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: Debug ) ;
@@ -255,7 +332,11 @@ mod tests {
255
332
256
333
#[ test]
257
334
fn parse_spec_empty_with_filter ( ) {
258
- let ( dirs, filter) = parse_spec ( "crate1/a*c" ) ;
335
+ let ParseResult {
336
+ directives : dirs,
337
+ filter,
338
+ ..
339
+ } = parse_spec ( "crate1/a*c" ) ;
259
340
assert_eq ! ( dirs. len( ) , 1 ) ;
260
341
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1" . to_owned( ) ) ) ;
261
342
assert_eq ! ( dirs[ 0 ] . level, LevelFilter :: max( ) ) ;
0 commit comments