arachnid_cli/config/kinds/
tracing.rs

1/*
2    Appellation: tracing <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use crate::config::LogLevel;
6use tracing_subscriber::filter::EnvFilter;
7
8fn default_true() -> bool {
9    true
10}
11
12#[derive(
13    Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
14)]
15#[serde(default)]
16pub struct TracingConfig {
17    #[serde(default = "default_true")]
18    pub ansi: bool,
19    pub file: bool,
20    pub level: LogLevel,
21    pub line_number: bool,
22    pub target: bool,
23    pub thread_ids: bool,
24    pub thread_names: bool,
25    #[serde(default = "default_true")]
26    pub timer: bool,
27}
28
29impl TracingConfig {
30    /// initialize a new instance of the tracing configuration from the given log level
31    pub const fn new(level: LogLevel) -> Self {
32        Self {
33            ansi: true,
34            file: false,
35            level,
36            line_number: false,
37            target: false,
38            thread_ids: false,
39            thread_names: false,
40            timer: true,
41        }
42    }
43    /// returns true if ansi output is enabled
44    pub const fn ansi(&self) -> bool {
45        self.ansi
46    }
47    /// returns true if file output is enabled
48    pub fn file(&self) -> bool {
49        self.file
50    }
51    /// returns a copy of the configured log level
52    pub const fn level(&self) -> LogLevel {
53        self.level
54    }
55    /// returns true if the line numbers are enabled
56    pub const fn line_number(&self) -> bool {
57        self.line_number
58    }
59    /// returns true if the target is enabled
60    pub const fn target(&self) -> bool {
61        self.target
62    }
63    /// returns true if thread ids are enabled
64    pub const fn thread_ids(&self) -> bool {
65        self.thread_ids
66    }
67    /// returns true if thread names are enabled
68    pub const fn thread_names(&self) -> bool {
69        self.thread_names
70    }
71    /// update the ansi setting and return a mutable reference to self
72    pub const fn set_ansi(&mut self, ansi: bool) -> &mut Self {
73        self.ansi = ansi;
74        self
75    }
76    /// set whether to log to file or not
77    pub const fn set_file(&mut self, file: bool) -> &mut Self {
78        self.file = file;
79        self
80    }
81    /// update the log level and return a mutable reference to self
82    pub const fn set_level(&mut self, level: LogLevel) -> &mut Self {
83        self.level = level;
84        self
85    }
86    /// update if the line number should be displayed
87    pub const fn set_line_number(&mut self, line_number: bool) -> &mut Self {
88        self.line_number = line_number;
89        self
90    }
91    /// update the target flag and return a mutable reference to self.
92    pub const fn set_target(&mut self, target: bool) -> &mut Self {
93        self.target = target;
94        self
95    }
96    /// update the thread ids flag and return a mutable reference to self.
97    pub const fn set_thread_ids(&mut self, thread_ids: bool) -> &mut Self {
98        self.thread_ids = thread_ids;
99        self
100    }
101    /// update the thread names flag and return a mutable reference to self.
102    pub const fn set_thread_names(&mut self, thread_names: bool) -> &mut Self {
103        self.thread_names = thread_names;
104        self
105    }
106
107    pub const fn set_timer(&mut self, timer: bool) -> &mut Self {
108        self.timer = timer;
109        self
110    }
111
112    pub fn with_ansi(self, ansi: bool) -> Self {
113        Self { ansi, ..self }
114    }
115
116    pub fn with_file(self, file: bool) -> Self {
117        Self { file, ..self }
118    }
119
120    pub fn with_level(self, level: LogLevel) -> Self {
121        Self { level, ..self }
122    }
123
124    pub fn with_line_number(self, line_number: bool) -> Self {
125        Self {
126            line_number,
127            ..self
128        }
129    }
130
131    pub fn with_target(self, target: bool) -> Self {
132        Self { target, ..self }
133    }
134
135    pub fn with_thread_ids(self, thread_ids: bool) -> Self {
136        Self { thread_ids, ..self }
137    }
138
139    pub fn with_thread_names(self, thread_names: bool) -> Self {
140        Self {
141            thread_names,
142            ..self
143        }
144    }
145    /// create an env filter from the current configuration
146    pub fn get_env_filter(&self, name: &str) -> EnvFilter {
147        EnvFilter::try_from_default_env().unwrap_or_else(|_| {
148            format!("{name}={level},tower_http={level}", level = self.level).into()
149        })
150    }
151    /// Initialize the tracer with the given name
152    pub fn init_tracing(&self, name: &str) {
153        use tracing_subscriber::util::SubscriberInitExt;
154
155        let filter = self.get_env_filter(name);
156        tracing_subscriber::fmt()
157            .compact()
158            .with_ansi(self.ansi())
159            .with_env_filter(filter)
160            .with_file(self.file)
161            .with_line_number(self.line_number)
162            .with_max_level(self.level.as_tracing_level())
163            .with_target(self.target)
164            .with_thread_ids(self.thread_ids)
165            .with_thread_names(self.thread_names)
166            .with_timer(tracing_subscriber::fmt::time::uptime())
167            .finish()
168            .init();
169        tracing::debug! { "initialized tracing for {name}" }
170    }
171}
172
173impl Default for TracingConfig {
174    fn default() -> Self {
175        Self::new(LogLevel::Trace)
176    }
177}
178
179impl core::fmt::Display for TracingConfig {
180    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181        f.write_str(serde_json::to_string(self).unwrap().as_str())
182    }
183}