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 = Self {
41            req_id,
42            max_level: AtomicUsize::new(Level::Trace as usize),
43            req_str: [0u8; 16],
44        };
45        write!(&mut s.req_str[..], "{:016x}", req_id).expect("to hex");
46        s
47    }
48
49    /// When LogFilter is shared in Arc, allows concurrently changing log level filter
50    #[inline]
51    pub fn set_level(&self, level: Level) {
52        self.max_level.store(level as usize, Ordering::Relaxed);
53    }
54
55    #[inline]
56    pub fn get_level(&self) -> usize {
57        self.max_level.load(Ordering::Relaxed)
58    }
59
60    #[doc(hidden)]
61    #[inline(always)]
62    pub fn _private_api_log(
63        &self,
64        args: fmt::Arguments,
65        level: Level,
66        &(target, module_path, file, line): &(&str, &str, &str, u32),
67    ) {
68        let record = RecordBuilder::new()
69            .level(level)
70            .target(target)
71            .module_path(Some(module_path))
72            .file(Some(file))
73            .line(Some(line))
74            .key_values(&self)
75            .args(args)
76            .build();
77        logger().log(&record);
78    }
79}
80
81impl log::kv::Source for LogFilter {
82    #[inline(always)]
83    fn visit<'kvs>(&'kvs self, visitor: &mut dyn Visitor<'kvs>) -> Result<(), Error> {
84        visitor.visit_pair("req_id".to_key(), unsafe {
85            str::from_utf8_unchecked(&self.req_str).into()
86        })
87    }
88
89    #[inline(always)]
90    fn get<'a>(&'a self, key: Key) -> Option<Value<'a>> {
91        if self.req_id != 0 && key.as_ref() == "req_id" {
92            return Some(unsafe { str::from_utf8_unchecked(&self.req_str).into() });
93        }
94        return None;
95    }
96
97    #[inline(always)]
98    fn count(&self) -> usize {
99        1
100    }
101}