8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use regex:: Regex ;
11
12
use std:: ascii:: AsciiExt ;
12
13
use std:: cmp;
13
14
@@ -28,14 +29,23 @@ fn parse_log_level(level: &str) -> Option<u32> {
28
29
} ) . map ( |p| cmp:: min ( p, :: MAX_LOG_LEVEL ) )
29
30
}
30
31
31
- /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
32
+ /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo ")
32
33
/// and return a vector with log directives.
33
34
///
34
35
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
35
36
/// std::). Also supports string log levels of error, warn, info, and debug
36
- pub fn parse_logging_spec ( spec : & str ) -> Vec < LogDirective > {
37
+ pub fn parse_logging_spec ( spec : & str ) -> ( Vec < LogDirective > , Option < Regex > ) {
37
38
let mut dirs = Vec :: new ( ) ;
38
- for s in spec. split ( ',' ) {
39
+
40
+ let mut parts = spec. split ( '/' ) ;
41
+ let mods = parts. next ( ) ;
42
+ let filter = parts. next ( ) ;
43
+ if parts. next ( ) . is_some ( ) {
44
+ println ! ( "warning: invalid logging spec '{}', \
45
+ ignoring it (too many '/'s)", spec) ;
46
+ return ( dirs, None ) ;
47
+ }
48
+ mods. map ( |m| { for s in m. split ( ',' ) {
39
49
if s. len ( ) == 0 { continue }
40
50
let mut parts = s. split ( '=' ) ;
41
51
let ( log_level, name) = match ( parts. next ( ) , parts. next ( ) . map ( |s| s. trim ( ) ) , parts. next ( ) ) {
@@ -68,8 +78,19 @@ pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
68
78
name : name. map ( |s| s. to_string ( ) ) ,
69
79
level : log_level,
70
80
} ) ;
71
- }
72
- return dirs;
81
+ } } ) ;
82
+
83
+ let filter = filter. map_or ( None , |filter| {
84
+ match Regex :: new ( filter) {
85
+ Ok ( re) => Some ( re) ,
86
+ Err ( e) => {
87
+ println ! ( "warning: invalid regex filter - {}" , e) ;
88
+ None
89
+ }
90
+ }
91
+ } ) ;
92
+
93
+ return ( dirs, filter) ;
73
94
}
74
95
75
96
#[ cfg( test) ]
@@ -78,7 +99,7 @@ mod tests {
78
99
79
100
#[ test]
80
101
fn parse_logging_spec_valid ( ) {
81
- let dirs = parse_logging_spec ( "crate1::mod1=1,crate1::mod2,crate2=4" ) ;
102
+ let ( dirs, filter ) = parse_logging_spec ( "crate1::mod1=1,crate1::mod2,crate2=4" ) ;
82
103
let dirs = dirs. as_slice ( ) ;
83
104
assert_eq ! ( dirs. len( ) , 3 ) ;
84
105
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1::mod1" . to_string( ) ) ) ;
@@ -89,57 +110,99 @@ mod tests {
89
110
90
111
assert_eq ! ( dirs[ 2 ] . name, Some ( "crate2" . to_string( ) ) ) ;
91
112
assert_eq ! ( dirs[ 2 ] . level, 4 ) ;
113
+ assert ! ( filter. is_none( ) ) ;
92
114
}
93
115
94
116
#[ test]
95
117
fn parse_logging_spec_invalid_crate ( ) {
96
118
// test parse_logging_spec with multiple = in specification
97
- let dirs = parse_logging_spec ( "crate1::mod1=1=2,crate2=4" ) ;
119
+ let ( dirs, filter ) = parse_logging_spec ( "crate1::mod1=1=2,crate2=4" ) ;
98
120
let dirs = dirs. as_slice ( ) ;
99
121
assert_eq ! ( dirs. len( ) , 1 ) ;
100
122
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_string( ) ) ) ;
101
123
assert_eq ! ( dirs[ 0 ] . level, 4 ) ;
124
+ assert ! ( filter. is_none( ) ) ;
102
125
}
103
126
104
127
#[ test]
105
128
fn parse_logging_spec_invalid_log_level ( ) {
106
129
// test parse_logging_spec with 'noNumber' as log level
107
- let dirs = parse_logging_spec ( "crate1::mod1=noNumber,crate2=4" ) ;
130
+ let ( dirs, filter ) = parse_logging_spec ( "crate1::mod1=noNumber,crate2=4" ) ;
108
131
let dirs = dirs. as_slice ( ) ;
109
132
assert_eq ! ( dirs. len( ) , 1 ) ;
110
133
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_string( ) ) ) ;
111
134
assert_eq ! ( dirs[ 0 ] . level, 4 ) ;
135
+ assert ! ( filter. is_none( ) ) ;
112
136
}
113
137
114
138
#[ test]
115
139
fn parse_logging_spec_string_log_level ( ) {
116
140
// test parse_logging_spec with 'warn' as log level
117
- let dirs = parse_logging_spec ( "crate1::mod1=wrong,crate2=warn" ) ;
141
+ let ( dirs, filter ) = parse_logging_spec ( "crate1::mod1=wrong,crate2=warn" ) ;
118
142
let dirs = dirs. as_slice ( ) ;
119
143
assert_eq ! ( dirs. len( ) , 1 ) ;
120
144
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_string( ) ) ) ;
121
145
assert_eq ! ( dirs[ 0 ] . level, :: WARN ) ;
146
+ assert ! ( filter. is_none( ) ) ;
122
147
}
123
148
124
149
#[ test]
125
150
fn parse_logging_spec_empty_log_level ( ) {
126
151
// test parse_logging_spec with '' as log level
127
- let dirs = parse_logging_spec ( "crate1::mod1=wrong,crate2=" ) ;
152
+ let ( dirs, filter ) = parse_logging_spec ( "crate1::mod1=wrong,crate2=" ) ;
128
153
let dirs = dirs. as_slice ( ) ;
129
154
assert_eq ! ( dirs. len( ) , 1 ) ;
130
155
assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_string( ) ) ) ;
131
156
assert_eq ! ( dirs[ 0 ] . level, :: MAX_LOG_LEVEL ) ;
157
+ assert ! ( filter. is_none( ) ) ;
132
158
}
133
159
134
160
#[ test]
135
161
fn parse_logging_spec_global ( ) {
136
162
// test parse_logging_spec with no crate
137
- let dirs = parse_logging_spec ( "warn,crate2=4" ) ;
163
+ let ( dirs, filter ) = parse_logging_spec ( "warn,crate2=4" ) ;
138
164
let dirs = dirs. as_slice ( ) ;
139
165
assert_eq ! ( dirs. len( ) , 2 ) ;
140
166
assert_eq ! ( dirs[ 0 ] . name, None ) ;
141
167
assert_eq ! ( dirs[ 0 ] . level, 2 ) ;
142
168
assert_eq ! ( dirs[ 1 ] . name, Some ( "crate2" . to_string( ) ) ) ;
143
169
assert_eq ! ( dirs[ 1 ] . level, 4 ) ;
170
+ assert ! ( filter. is_none( ) ) ;
171
+ }
172
+
173
+ #[ test]
174
+ fn parse_logging_spec_valid_filter ( ) {
175
+ let ( dirs, filter) = parse_logging_spec ( "crate1::mod1=1,crate1::mod2,crate2=4/abc" ) ;
176
+ let dirs = dirs. as_slice ( ) ;
177
+ assert_eq ! ( dirs. len( ) , 3 ) ;
178
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1::mod1" . to_string( ) ) ) ;
179
+ assert_eq ! ( dirs[ 0 ] . level, 1 ) ;
180
+
181
+ assert_eq ! ( dirs[ 1 ] . name, Some ( "crate1::mod2" . to_string( ) ) ) ;
182
+ assert_eq ! ( dirs[ 1 ] . level, :: MAX_LOG_LEVEL ) ;
183
+
184
+ assert_eq ! ( dirs[ 2 ] . name, Some ( "crate2" . to_string( ) ) ) ;
185
+ assert_eq ! ( dirs[ 2 ] . level, 4 ) ;
186
+ assert ! ( filter. is_some( ) && filter. unwrap( ) . to_string( ) . as_slice( ) == "abc" ) ;
187
+ }
188
+
189
+ #[ test]
190
+ fn parse_logging_spec_invalid_crate_filter ( ) {
191
+ let ( dirs, filter) = parse_logging_spec ( "crate1::mod1=1=2,crate2=4/a.c" ) ;
192
+ let dirs = dirs. as_slice ( ) ;
193
+ assert_eq ! ( dirs. len( ) , 1 ) ;
194
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate2" . to_string( ) ) ) ;
195
+ assert_eq ! ( dirs[ 0 ] . level, 4 ) ;
196
+ assert ! ( filter. is_some( ) && filter. unwrap( ) . to_string( ) . as_slice( ) == "a.c" ) ;
197
+ }
198
+
199
+ #[ test]
200
+ fn parse_logging_spec_empty_with_filter ( ) {
201
+ let ( dirs, filter) = parse_logging_spec ( "crate1/a*c" ) ;
202
+ let dirs = dirs. as_slice ( ) ;
203
+ assert_eq ! ( dirs. len( ) , 1 ) ;
204
+ assert_eq ! ( dirs[ 0 ] . name, Some ( "crate1" . to_string( ) ) ) ;
205
+ assert_eq ! ( dirs[ 0 ] . level, :: MAX_LOG_LEVEL ) ;
206
+ assert ! ( filter. is_some( ) && filter. unwrap( ) . to_string( ) . as_slice( ) == "a*c" ) ;
144
207
}
145
208
}
0 commit comments