micromegas_tracing/logs/events.rs
1use crate::levels::{Level, LevelFilter};
2use std::sync::atomic::{AtomicU32, Ordering};
3
4#[derive(Debug)]
5pub struct LogMetadata<'a> {
6 pub level: Level,
7 pub level_filter: AtomicU32,
8 pub fmt_str: &'a str,
9 pub target: &'a str,
10 pub module_path: &'a str,
11 pub file: &'a str,
12 pub line: u32,
13}
14
15pub const FILTER_LEVEL_UNSET_VALUE: u32 = 0xF;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum FilterState {
19 /// The filter needs to be updated.
20 Outdated,
21 /// The filter is up to date but no filter is set.
22 NotSet,
23 /// The filter is up to date a filter level is set.
24 Set(LevelFilter),
25}
26
27impl LogMetadata<'_> {
28 /// This is a way to efficiency implement finer grade filtering by amortizing its
29 /// cost. An atomic is used to store a level filter and a 16 bit generation.
30 /// Allowing a config update to be applied to the level filter multiple times during
31 /// the lifetime of the process.
32 ///
33 /// ```ignore
34 /// const GENERATION: u16 = 1;
35 /// let level_filter = metadata.level_filter(GENERATION).unwrap_or_else(|| {
36 /// let level_filter = self.level_filter(metadata.target);
37 /// metadata.set_level_filter(level_filter, GENERATION);
38 /// level_filter
39 /// });
40 /// if metadata.level <= level_filter {
41 /// ...
42 /// }
43 /// ```
44 ///
45 pub fn level_filter(&self, generation: u16) -> FilterState {
46 let level_filter = self.level_filter.load(Ordering::Relaxed);
47 if generation > ((level_filter >> 16) as u16) {
48 FilterState::Outdated
49 } else {
50 LevelFilter::from_u32(level_filter & FILTER_LEVEL_UNSET_VALUE)
51 .map_or(FilterState::NotSet, |level_filter| {
52 FilterState::Set(level_filter)
53 })
54 }
55 }
56
57 /// Sets the level filter if the generation is greater than the current generation.
58 ///
59 pub fn set_level_filter(&self, generation: u16, level_filter: Option<LevelFilter>) {
60 let new = level_filter.map_or(FILTER_LEVEL_UNSET_VALUE, |filter_level| filter_level as u32)
61 | (u32::from(generation) << 16);
62 let mut current = self.level_filter.load(Ordering::Relaxed);
63 if generation <= (current >> 16) as u16 {
64 // value was updated form another thread with a newer generation
65 return;
66 }
67 loop {
68 match self.level_filter.compare_exchange(
69 current,
70 new,
71 Ordering::SeqCst,
72 Ordering::Relaxed,
73 ) {
74 Ok(_) => {
75 return;
76 }
77 Err(x) => {
78 if generation <= (x >> 16) as u16 {
79 return;
80 }
81 current = x;
82 }
83 };
84 }
85 }
86}