captains_log/
log_filter.rs

1use std::{
2    fmt,
3    io::Write,
4    str,
5    sync::atomic::{AtomicUsize, Ordering},
6};
7
8use log::{kv::*, *};
9
10/// A LogFilter supports concurrent control the log level.
11/// Use in combine with macros  logger_XXX
12///
13/// # Example
14/// ```
15/// use captains_log::*;
16/// let logger = LogFilter::new(123);
17/// logger.set_level(log::Level::Error);
18/// // info will be filtered
19/// logger_info!(logger, "using LogFilter {}", "ok");
20/// logger_error!(logger, "error occur");
21/// ```
22pub struct LogFilter {
23    req_id: u64,
24    req_str: [u8; 16],
25    max_level: AtomicUsize,
26}
27
28impl Clone for LogFilter {
29    fn clone(&self) -> Self {
30        Self {
31            req_id: self.req_id,
32            req_str: self.req_str.clone(),
33            max_level: AtomicUsize::new(self.get_level()),
34        }
35    }
36}
37
38impl LogFilter {
39    pub fn new(req_id: u64) -> Self {
40        let mut s =
41            Self { req_id, max_level: AtomicUsize::new(Level::Trace as usize), req_str: [0u8; 16] };
42        write!(&mut s.req_str[..], "{:016x}", req_id).expect("to hex");
43        s
44    }
45
46    /// When LogFilter is shared in Arc, allows concurrently changing log level filter
47    #[inline]
48    pub fn set_level(&self, level: Level) {
49        self.max_level.store(level as usize, Ordering::Relaxed);
50    }
51
52    #[inline]
53    pub fn get_level(&self) -> usize {
54        self.max_level.load(Ordering::Relaxed)
55    }
56
57    #[doc(hidden)]
58    #[inline(always)]
59    pub fn _private_api_log(
60        &self, args: fmt::Arguments, level: Level,
61        &(target, module_path, file, line): &(&str, &str, &str, u32),
62    ) {
63        let record = RecordBuilder::new()
64            .level(level)
65            .target(target)
66            .module_path(Some(module_path))
67            .file(Some(file))
68            .line(Some(line))
69            .key_values(&self)
70            .args(args)
71            .build();
72        logger().log(&record);
73    }
74}
75
76impl log::kv::Source for LogFilter {
77    #[inline(always)]
78    fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> {
79        visitor.visit_pair("req_id".to_key(), unsafe {
80            str::from_utf8_unchecked(&self.req_str).into()
81        })
82    }
83
84    #[inline(always)]
85    fn get<'a>(&'a self, key: Key) -> Option<Value<'a>> {
86        if self.req_id != 0 && key.as_ref() == "req_id" {
87            return Some(unsafe { str::from_utf8_unchecked(&self.req_str).into() });
88        }
89        return None;
90    }
91
92    #[inline(always)]
93    fn count(&self) -> usize {
94        1
95    }
96}