Skip to content

Commit 0900811

Browse files
BramBonnejplatte
authored andcommitted
Ensure unique directive names when building filters
Use a HashMap to ensure that filter directives have unique names. This allows later calls to filter::Builder methods to override earlier calls, as specified in the documentation.
1 parent 1a8379a commit 0900811

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

src/filter/mod.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
//! [`Filter::matches`]: struct.Filter.html#method.matches
6060
6161
use log::{Level, LevelFilter, Metadata, Record};
62+
use std::collections::HashMap;
6263
use std::env;
6364
use std::fmt;
6465
use std::mem;
@@ -107,7 +108,7 @@ pub struct Filter {
107108
///
108109
/// [`Filter`]: struct.Filter.html
109110
pub struct Builder {
110-
directives: Vec<Directive>,
111+
directives: HashMap<Option<String>, LevelFilter>,
111112
filter: Option<inner::Filter>,
112113
built: bool,
113114
}
@@ -171,7 +172,7 @@ impl Builder {
171172
/// Initializes the filter builder with defaults.
172173
pub fn new() -> Builder {
173174
Builder {
174-
directives: Vec::new(),
175+
directives: HashMap::new(),
175176
filter: None,
176177
built: false,
177178
}
@@ -203,10 +204,7 @@ impl Builder {
203204
/// The given module (if any) will log at most the specified level provided.
204205
/// If no module is provided then the filter will apply to all log messages.
205206
pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
206-
self.directives.push(Directive {
207-
name: module.map(|s| s.to_string()),
208-
level,
209-
});
207+
self.directives.insert(module.map(|s| s.to_string()), level);
210208
self
211209
}
212210

@@ -221,7 +219,7 @@ impl Builder {
221219
self.filter = filter;
222220

223221
for directive in directives {
224-
self.directives.push(directive);
222+
self.directives.insert(directive.name, directive.level);
225223
}
226224
self
227225
}
@@ -231,24 +229,31 @@ impl Builder {
231229
assert!(!self.built, "attempt to re-use consumed builder");
232230
self.built = true;
233231

232+
let mut directives = Vec::new();
234233
if self.directives.is_empty() {
235234
// Adds the default filter if none exist
236-
self.directives.push(Directive {
235+
directives.push(Directive {
237236
name: None,
238237
level: LevelFilter::Error,
239238
});
240239
} else {
240+
// Consume map of directives.
241+
let directives_map = mem::replace(&mut self.directives, HashMap::new());
242+
directives = directives_map
243+
.into_iter()
244+
.map(|(name, level)| Directive { name, level })
245+
.collect();
241246
// Sort the directives by length of their name, this allows a
242247
// little more efficient lookup at runtime.
243-
self.directives.sort_by(|a, b| {
248+
directives.sort_by(|a, b| {
244249
let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
245250
let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
246251
alen.cmp(&blen)
247252
});
248253
}
249254

250255
Filter {
251-
directives: mem::replace(&mut self.directives, Vec::new()),
256+
directives: mem::replace(&mut directives, Vec::new()),
252257
filter: mem::replace(&mut self.filter, None),
253258
}
254259
}

src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,4 +1280,20 @@ mod tests {
12801280

12811281
assert_eq!(Some("from default".to_owned()), env.get_write_style());
12821282
}
1283+
1284+
#[test]
1285+
fn builder_parse_env_overrides_existing_filters() {
1286+
env::set_var(
1287+
"builder_parse_default_env_overrides_existing_filters",
1288+
"debug",
1289+
);
1290+
let env = Env::new().filter("builder_parse_default_env_overrides_existing_filters");
1291+
1292+
let mut builder = Builder::new();
1293+
builder.filter_level(LevelFilter::Trace);
1294+
// Overrides global level to debug
1295+
builder.parse_env(env);
1296+
1297+
assert_eq!(builder.filter.build().filter(), LevelFilter::Debug);
1298+
}
12831299
}

0 commit comments

Comments
 (0)