@@ -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,120 @@ 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. trim ( ) . char_indices ( ) {
143
+ state = match ( state, c) {
144
+ ( Start , '[' ) => Span { span_start : i + 1 } ,
145
+ ( Start , c) if !c. is_alphanumeric ( ) => return Err ( ParseError :: new ( ) ) ,
146
+ ( Start , _) => LevelOrTarget { start : i } ,
147
+ ( LevelOrTarget { start } , '=' ) => {
148
+ cur. target = Some ( from[ start..i] . to_owned ( ) ) ;
149
+ Level { level_start : i + 1 }
150
+ }
151
+ ( LevelOrTarget { start } , '[' ) => {
152
+ cur. target = Some ( from[ start..i] . to_owned ( ) ) ;
153
+ Span { span_start : i + 1 }
154
+ }
155
+ ( LevelOrTarget { start } , ',' ) => {
156
+ let ( level, target) = match & from[ start..] {
157
+ "" => ( LevelFilter :: TRACE , None ) ,
158
+ level_or_target => match LevelFilter :: from_str ( level_or_target) {
159
+ Ok ( level) => ( level, None ) ,
160
+ Err ( _) => ( LevelFilter :: TRACE , Some ( level_or_target. to_owned ( ) ) ) ,
161
+ } ,
162
+ } ;
163
+
164
+ cur. level = level;
165
+ cur. target = target;
166
+ Complete
167
+ }
168
+ ( state @ LevelOrTarget { .. } , _) => state,
169
+ ( Target , '=' ) => Level { level_start : i + 1 } ,
170
+ ( Span { span_start } , ']' ) => {
171
+ cur. in_span = Some ( from[ span_start..i] . to_owned ( ) ) ;
172
+ Target
173
+ }
174
+ ( Span { span_start } , '{' ) => {
175
+ cur. in_span = match & from[ span_start..i] {
176
+ "" => None ,
177
+ _ => Some ( from[ span_start..i] . to_owned ( ) ) ,
178
+ } ;
179
+ Field { field_start : i + 1 }
180
+ }
181
+ ( state @ Span { .. } , _) => state,
182
+ ( Field { field_start } , '}' ) => {
183
+ cur. fields . push ( match & from[ field_start..i] {
184
+ "" => return Err ( ParseError :: new ( ) ) ,
185
+ field => field:: Match :: parse ( field, regex) ?,
186
+ } ) ;
187
+ Fields
188
+ }
189
+ ( Field { field_start } , ',' ) => {
190
+ cur. fields . push ( match & from[ field_start..i] {
191
+ "" => return Err ( ParseError :: new ( ) ) ,
192
+ field => field:: Match :: parse ( field, regex) ?,
193
+ } ) ;
194
+ Field { field_start : i + 1 }
195
+ }
196
+ ( state @ Field { .. } , _) => state,
197
+ ( Fields , ']' ) => Target ,
198
+ ( Level { level_start } , ',' ) => {
199
+ cur. level = match & from[ level_start..i] {
200
+ "" => LevelFilter :: TRACE ,
201
+ level => LevelFilter :: from_str ( level) ?,
202
+ } ;
203
+ Complete
204
+ }
205
+ ( state @ Level { .. } , _) => state,
206
+ _ => return Err ( ParseError :: new ( ) ) ,
207
+ } ;
174
208
}
175
209
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 ( ) )
210
+ match state {
211
+ LevelOrTarget { start } => {
212
+ let ( level, target) = match & from[ start..] {
213
+ "" => ( LevelFilter :: TRACE , None ) ,
214
+ level_or_target => match LevelFilter :: from_str ( level_or_target) {
215
+ Ok ( level) => ( level, None ) ,
216
+ // Setting the target without the level enables every level for that target
217
+ Err ( _) => ( LevelFilter :: TRACE , Some ( level_or_target. to_owned ( ) ) ) ,
218
+ } ,
219
+ } ;
220
+
221
+ cur. level = level;
222
+ cur. target = target;
182
223
}
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 ) ;
224
+ Level { level_start } => {
225
+ cur. level = match & from[ level_start..] {
226
+ "" => LevelFilter :: TRACE ,
227
+ level => LevelFilter :: from_str ( level) ?,
228
+ } ;
229
+ }
230
+ Target | Complete => { }
231
+ _ => return Err ( ParseError :: new ( ) ) ,
232
+ } ;
209
233
210
- Ok ( Self {
211
- level,
212
- target,
213
- in_span,
214
- fields : fields?,
215
- } )
234
+ Ok ( cur)
216
235
}
217
236
}
218
237
0 commit comments