Skip to content

Commit c42511c

Browse files
committed
refactor: Return errors from parse_spec
1 parent 0e25d9e commit c42511c

File tree

2 files changed

+139
-47
lines changed

2 files changed

+139
-47
lines changed

crates/env_filter/src/filter.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use log::{LevelFilter, Metadata, Record};
66

77
use crate::enabled;
88
use crate::parse_spec;
9+
use crate::parser::ParseResult;
910
use crate::Directive;
1011
use crate::FilterOp;
1112

@@ -97,7 +98,17 @@ impl Builder {
9798
///
9899
/// [Enabling Logging]: ../index.html#enabling-logging
99100
pub fn parse(&mut self, filters: &str) -> &mut Self {
100-
let (directives, filter) = parse_spec(filters);
101+
#![allow(clippy::print_stderr)] // compatibility
102+
103+
let ParseResult {
104+
directives,
105+
filter,
106+
errors,
107+
} = parse_spec(filters);
108+
109+
for error in errors {
110+
eprintln!("warning: {error}, ignoring it");
111+
}
101112

102113
self.filter = filter;
103114

crates/env_filter/src/parser.rs

Lines changed: 127 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,38 @@ use log::LevelFilter;
33
use crate::Directive;
44
use crate::FilterOp;
55

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+
627
/// Parse a logging specification string (e.g: `crate1,crate2::mod3,crate3::x=error/foo`)
728
/// 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();
1231

1332
let mut parts = spec.split('/');
1433
let mods = parts.next();
1534
let filter = parts.next();
1635
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;
2338
}
2439
if let Some(m) = mods {
2540
for s in m.split(',').map(|ss| ss.trim()) {
@@ -42,50 +57,47 @@ pub(crate) fn parse_spec(spec: &str) -> (Vec<Directive>, Option<FilterOp>) {
4257
if let Ok(num) = part1.parse() {
4358
(num, Some(part0))
4459
} else {
45-
eprintln!(
46-
"warning: invalid logging spec '{}', \
47-
ignoring it",
48-
part1
49-
);
60+
result.add_error(format!("invalid logging spec '{}'", part1));
5061
continue;
5162
}
5263
}
5364
_ => {
54-
eprintln!(
55-
"warning: invalid logging spec '{}', \
56-
ignoring it",
57-
s
58-
);
65+
result.add_error(format!("invalid logging spec '{}'", s));
5966
continue;
6067
}
6168
};
62-
dirs.push(Directive {
69+
70+
result.add_directive(Directive {
6371
name: name.map(|s| s.to_owned()),
6472
level: log_level,
6573
});
6674
}
6775
}
6876

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)),
7481
}
75-
});
82+
}
7683

77-
(dirs, filter)
84+
result
7885
}
7986

8087
#[cfg(test)]
8188
mod tests {
8289
use log::LevelFilter;
8390

84-
use super::parse_spec;
91+
use super::{parse_spec, ParseResult};
8592

8693
#[test]
8794
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+
89101
assert_eq!(dirs.len(), 3);
90102
assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
91103
assert_eq!(dirs[0].level, LevelFilter::Error);
@@ -101,7 +113,12 @@ mod tests {
101113
#[test]
102114
fn parse_spec_invalid_crate() {
103115
// 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+
105122
assert_eq!(dirs.len(), 1);
106123
assert_eq!(dirs[0].name, Some("crate2".to_owned()));
107124
assert_eq!(dirs[0].level, LevelFilter::Debug);
@@ -111,7 +128,12 @@ mod tests {
111128
#[test]
112129
fn parse_spec_invalid_level() {
113130
// 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+
115137
assert_eq!(dirs.len(), 1);
116138
assert_eq!(dirs[0].name, Some("crate2".to_owned()));
117139
assert_eq!(dirs[0].level, LevelFilter::Debug);
@@ -121,7 +143,12 @@ mod tests {
121143
#[test]
122144
fn parse_spec_string_level() {
123145
// 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+
125152
assert_eq!(dirs.len(), 1);
126153
assert_eq!(dirs[0].name, Some("crate2".to_owned()));
127154
assert_eq!(dirs[0].level, LevelFilter::Warn);
@@ -131,7 +158,12 @@ mod tests {
131158
#[test]
132159
fn parse_spec_empty_level() {
133160
// 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+
135167
assert_eq!(dirs.len(), 1);
136168
assert_eq!(dirs[0].name, Some("crate2".to_owned()));
137169
assert_eq!(dirs[0].level, LevelFilter::max());
@@ -141,7 +173,11 @@ mod tests {
141173
#[test]
142174
fn parse_spec_empty_level_isolated() {
143175
// 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
145181
assert_eq!(dirs.len(), 0);
146182
assert!(filter.is_none());
147183
}
@@ -150,7 +186,11 @@ mod tests {
150186
fn parse_spec_blank_level_isolated() {
151187
// test parse_spec with a white-space-only string specified as the log
152188
// 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
154194
assert_eq!(dirs.len(), 0);
155195
assert!(filter.is_none());
156196
}
@@ -160,7 +200,11 @@ mod tests {
160200
// The spec should contain zero or more comma-separated string slices,
161201
// so a comma-only string should be interpreted as two empty strings
162202
// (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
164208
assert_eq!(dirs.len(), 0);
165209
assert!(filter.is_none());
166210
}
@@ -171,7 +215,11 @@ mod tests {
171215
// so this bogus spec should be interpreted as containing one empty
172216
// string and one blank string. Both should both be treated as
173217
// 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
175223
assert_eq!(dirs.len(), 0);
176224
assert!(filter.is_none());
177225
}
@@ -182,15 +230,23 @@ mod tests {
182230
// so this bogus spec should be interpreted as containing one blank
183231
// string and one empty string. Both should both be treated as
184232
// 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
186238
assert_eq!(dirs.len(), 0);
187239
assert!(filter.is_none());
188240
}
189241

190242
#[test]
191243
fn parse_spec_global() {
192244
// 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");
194250
assert_eq!(dirs.len(), 2);
195251
assert_eq!(dirs[0].name, None);
196252
assert_eq!(dirs[0].level, LevelFilter::Warn);
@@ -202,7 +258,11 @@ mod tests {
202258
#[test]
203259
fn parse_spec_global_bare_warn_lc() {
204260
// 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");
206266
assert_eq!(dirs.len(), 1);
207267
assert_eq!(dirs[0].name, None);
208268
assert_eq!(dirs[0].level, LevelFilter::Warn);
@@ -212,7 +272,11 @@ mod tests {
212272
#[test]
213273
fn parse_spec_global_bare_warn_uc() {
214274
// 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");
216280
assert_eq!(dirs.len(), 1);
217281
assert_eq!(dirs[0].name, None);
218282
assert_eq!(dirs[0].level, LevelFilter::Warn);
@@ -222,7 +286,11 @@ mod tests {
222286
#[test]
223287
fn parse_spec_global_bare_warn_mixed() {
224288
// 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");
226294
assert_eq!(dirs.len(), 1);
227295
assert_eq!(dirs[0].name, None);
228296
assert_eq!(dirs[0].level, LevelFilter::Warn);
@@ -231,7 +299,11 @@ mod tests {
231299

232300
#[test]
233301
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");
235307
assert_eq!(dirs.len(), 3);
236308
assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned()));
237309
assert_eq!(dirs[0].level, LevelFilter::Error);
@@ -246,7 +318,12 @@ mod tests {
246318

247319
#[test]
248320
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+
250327
assert_eq!(dirs.len(), 1);
251328
assert_eq!(dirs[0].name, Some("crate2".to_owned()));
252329
assert_eq!(dirs[0].level, LevelFilter::Debug);
@@ -255,7 +332,11 @@ mod tests {
255332

256333
#[test]
257334
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");
259340
assert_eq!(dirs.len(), 1);
260341
assert_eq!(dirs[0].name, Some("crate1".to_owned()));
261342
assert_eq!(dirs[0].level, LevelFilter::max());

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy