1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
use crate::OsLog;
use dashmap::DashMap;
use log::{LevelFilter, Log, Metadata, Record};
pub struct OsLogger {
loggers: DashMap<String, (Option<LevelFilter>, OsLog)>,
subsystem: String,
}
impl Log for OsLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
let max_level = self
.loggers
.get(metadata.target())
.and_then(|pair| (*pair).0)
.unwrap_or_else(|| log::max_level());
metadata.level() <= max_level
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let pair = self
.loggers
.entry(record.target().into())
.or_insert((None, OsLog::new(&self.subsystem, record.target())));
let message = std::format!("{}", record.args());
(*pair).1.with_level(record.level().into(), &message);
}
}
fn flush(&self) {}
}
impl OsLogger {
/// Creates a new logger. You must also call `init` to finalize the set up.
/// By default the level filter will be set to `LevelFilter::Trace`.
pub fn new(subsystem: &str) -> Self {
Self {
loggers: DashMap::new(),
subsystem: subsystem.to_string(),
}
}
/// Only levels at or above `level` will be logged.
pub fn level_filter(self, level: LevelFilter) -> Self {
log::set_max_level(level);
self
}
/// Sets or updates the category's level filter.
pub fn category_level_filter(self, category: &str, level: LevelFilter) -> Self {
self.loggers
.entry(category.into())
.and_modify(|(existing_level, _)| *existing_level = Some(level))
.or_insert((Some(level), OsLog::new(&self.subsystem, category)));
self
}
pub fn init(self) -> Result<(), log::SetLoggerError> {
log::set_boxed_logger(Box::new(self))
}
}
#[cfg(test)]
mod tests {
use super::*;
use log::{debug, error, info, trace, warn};
#[test]
fn test_basic_usage() {
OsLogger::new("com.example.oslog")
.level_filter(LevelFilter::Trace)
.category_level_filter("Settings", LevelFilter::Warn)
.category_level_filter("Database", LevelFilter::Error)
.category_level_filter("Database", LevelFilter::Trace)
.init()
.unwrap();
// This will not be logged because of its category's custom level filter.
info!(target: "Settings", "Info");
warn!(target: "Settings", "Warn");
error!(target: "Settings", "Error");
trace!("Trace");
debug!("Debug");
info!("Info");
warn!(target: "Database", "Warn");
error!("Error");
}
}
|