@@ -4,8 +4,6 @@ use crate::filter::{
4
4
env:: { field, FieldMap } ,
5
5
level:: LevelFilter ,
6
6
} ;
7
- use once_cell:: sync:: Lazy ;
8
- use regex:: Regex ;
9
7
use std:: { cmp:: Ordering , fmt, iter:: FromIterator , str:: FromStr } ;
10
8
use tracing_core:: { span, Level , Metadata } ;
11
9
@@ -120,99 +118,118 @@ impl Directive {
120
118
}
121
119
122
120
pub ( super ) fn parse ( from : & str , regex : bool ) -> Result < Self , ParseError > {
123
- static DIRECTIVE_RE : Lazy < Regex > = Lazy :: new ( || {
124
- Regex :: new (
125
- r"(?x)
126
- ^(?P<global_level>(?i:trace|debug|info|warn|error|off|[0-5]))$ |
127
- # ^^^.
128
- # `note: we match log level names case-insensitively
129
- ^
130
- (?: # target name or span name
131
- (?P<target>[\w:-]+)|(?P<span>\[[^\]]*\])
132
- ){1,2}
133
- (?: # level or nothing
134
- =(?P<level>(?i:trace|debug|info|warn|error|off|[0-5]))?
135
- # ^^^.
136
- # `note: we match log level names case-insensitively
137
- )?
138
- $
139
- " ,
140
- )
141
- . unwrap ( )
142
- } ) ;
143
- static SPAN_PART_RE : Lazy < Regex > =
144
- Lazy :: new ( || Regex :: new ( r"(?P<name>[^\]\{]+)?(?:\{(?P<fields>[^\}]*)\})?" ) . unwrap ( ) ) ;
145
- static FIELD_FILTER_RE : Lazy < Regex > =
146
- // TODO(eliza): this doesn't _currently_ handle value matchers that include comma
147
- // characters. We should fix that.
148
- Lazy :: new ( || {
149
- Regex :: new (
150
- r"(?x)
151
- (
152
- # field name
153
- [[:word:]][[[:word:]]\.]*
154
- # value part (optional)
155
- (?:=[^,]+)?
156
- )
157
- # trailing comma or EOS
158
- (?:,\s?|$)
159
- " ,
160
- )
161
- . unwrap ( )
162
- } ) ;
163
-
164
- let caps = DIRECTIVE_RE . captures ( from) . ok_or_else ( ParseError :: new) ?;
121
+ let mut cur = Self {
122
+ level : LevelFilter :: TRACE ,
123
+ target : None ,
124
+ in_span : None ,
125
+ fields : Vec :: new ( ) ,
126
+ } ;
127
+
128
+ #[ derive( Debug ) ]
129
+ enum ParseState {
130
+ Start ,
131
+ LevelOrTarget { start : usize } ,
132
+ Span { span_start : usize } ,
133
+ Field { field_start : usize } ,
134
+ Fields ,
135
+ Target ,
136
+ Level { level_start : usize } ,
137
+ Complete ,
138
+ }
165
139
166
- if let Some ( level) = caps
167
- . name ( "global_level" )
168
- . and_then ( |s| s. as_str ( ) . parse ( ) . ok ( ) )
169
- {
170
- return Ok ( Directive {
171
- level,
172
- ..Default :: default ( )
173
- } ) ;
140
+ use ParseState :: * ;
141
+ let mut state = Start ;
142
+ for ( i, c) in from. char_indices ( ) {
143
+ state = match ( state, c) {
144
+ ( Start , '[' ) => Span { span_start : i + 1 } ,
145
+ ( Start , _) => LevelOrTarget { start : i } ,
146
+ ( LevelOrTarget { start } , '=' ) => {
147
+ cur. target = Some ( from[ start..i] . to_owned ( ) ) ;
148
+ Level { level_start : i + 1 }
149
+ }
150
+ ( LevelOrTarget { start } , '[' ) => {
151
+ cur. target = Some ( from[ start..i] . to_owned ( ) ) ;
152
+ Span { span_start : i + 1 }
153
+ }
154
+ ( LevelOrTarget { start } , ',' ) => {
155
+ let ( level, target) = match & from[ start..] {
156
+ "" => ( LevelFilter :: TRACE , None ) ,
157
+ level_or_target => match LevelFilter :: from_str ( level_or_target) {
158
+ Ok ( level) => ( level, None ) ,
159
+ Err ( _) => ( LevelFilter :: TRACE , Some ( level_or_target. to_owned ( ) ) ) ,
160
+ } ,
161
+ } ;
162
+
163
+ cur. level = level;
164
+ cur. target = target;
165
+ Complete
166
+ }
167
+ ( state @ LevelOrTarget { .. } , _) => state,
168
+ ( Target , '=' ) => Level { level_start : i + 1 } ,
169
+ ( Span { span_start } , ']' ) => {
170
+ cur. in_span = Some ( from[ span_start..i] . to_owned ( ) ) ;
171
+ Target
172
+ }
173
+ ( Span { span_start } , '{' ) => {
174
+ cur. in_span = match & from[ span_start..i] {
175
+ "" => None ,
176
+ _ => Some ( from[ span_start..i] . to_owned ( ) ) ,
177
+ } ;
178
+ Field { field_start : i + 1 }
179
+ }
180
+ ( state @ Span { .. } , _) => state,
181
+ ( Field { field_start } , '}' ) => {
182
+ cur. fields . push ( match & from[ field_start..i] {
183
+ "" => return Err ( ParseError :: new ( ) ) ,
184
+ field => field:: Match :: parse ( field, regex) ?,
185
+ } ) ;
186
+ Fields
187
+ }
188
+ ( Field { field_start } , ',' ) => {
189
+ cur. fields . push ( match & from[ field_start..i] {
190
+ "" => return Err ( ParseError :: new ( ) ) ,
191
+ field => field:: Match :: parse ( field, regex) ?,
192
+ } ) ;
193
+ Field { field_start : i + 1 }
194
+ }
195
+ ( state @ Field { .. } , _) => state,
196
+ ( Fields , ']' ) => Target ,
197
+ ( Level { level_start } , ',' ) => {
198
+ cur. level = match & from[ level_start..i] {
199
+ "" => LevelFilter :: TRACE ,
200
+ level => LevelFilter :: from_str ( level) ?,
201
+ } ;
202
+ Complete
203
+ }
204
+ ( state @ Level { .. } , _) => state,
205
+ _ => return Err ( ParseError :: new ( ) ) ,
206
+ } ;
174
207
}
175
208
176
- let target = caps. name ( "target" ) . and_then ( |c| {
177
- let s = c. as_str ( ) ;
178
- if s. parse :: < LevelFilter > ( ) . is_ok ( ) {
179
- None
180
- } else {
181
- Some ( s. to_owned ( ) )
209
+ match state {
210
+ LevelOrTarget { start } => {
211
+ let ( level, target) = match & from[ start..] {
212
+ "" => ( LevelFilter :: TRACE , None ) ,
213
+ level_or_target => match LevelFilter :: from_str ( level_or_target) {
214
+ Ok ( level) => ( level, None ) ,
215
+ Err ( _) => ( LevelFilter :: TRACE , Some ( level_or_target. to_owned ( ) ) ) ,
216
+ } ,
217
+ } ;
218
+
219
+ cur. level = level;
220
+ cur. target = target;
182
221
}
183
- } ) ;
184
-
185
- let ( in_span, fields) = caps
186
- . name ( "span" )
187
- . and_then ( |cap| {
188
- let cap = cap. as_str ( ) . trim_matches ( |c| c == '[' || c == ']' ) ;
189
- let caps = SPAN_PART_RE . captures ( cap) ?;
190
- let span = caps. name ( "name" ) . map ( |c| c. as_str ( ) . to_owned ( ) ) ;
191
- let fields = caps
192
- . name ( "fields" )
193
- . map ( |c| {
194
- FIELD_FILTER_RE
195
- . find_iter ( c. as_str ( ) )
196
- . map ( |c| field:: Match :: parse ( c. as_str ( ) , regex) )
197
- . collect :: < Result < Vec < _ > , _ > > ( )
198
- } )
199
- . unwrap_or_else ( || Ok ( Vec :: new ( ) ) ) ;
200
- Some ( ( span, fields) )
201
- } )
202
- . unwrap_or_else ( || ( None , Ok ( Vec :: new ( ) ) ) ) ;
203
-
204
- let level = caps
205
- . name ( "level" )
206
- . and_then ( |l| l. as_str ( ) . parse ( ) . ok ( ) )
207
- // Setting the target without the level enables every level for that target
208
- . unwrap_or ( LevelFilter :: TRACE ) ;
222
+ Level { level_start } => {
223
+ cur. level = match & from[ level_start..] {
224
+ "" => LevelFilter :: TRACE ,
225
+ level => LevelFilter :: from_str ( level) ?,
226
+ } ;
227
+ }
228
+ Target | Complete => { }
229
+ _ => return Err ( ParseError :: new ( ) ) ,
230
+ } ;
209
231
210
- Ok ( Self {
211
- level,
212
- target,
213
- in_span,
214
- fields : fields?,
215
- } )
232
+ Ok ( cur)
216
233
}
217
234
}
218
235
0 commit comments