Skip to main content

veilid_core/logging/veilid_tracing/
log_output.rs

1use tracing_subscriber::Registry;
2
3use super::*;
4
5use std::path::{Path, PathBuf};
6
7/// Where a [LogOutput] sends its formatted log events.
8#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
9pub enum LogOutputKind {
10    /// Standard output of the process.
11    StdOut,
12    /// Standard error of the process.
13    StdErr,
14    /// A file on disk.
15    File,
16    /// `VeilidUpdate::Log` events delivered through the API.
17    Api,
18    /// A caller-supplied `tracing` layer, identified by name.
19    Layer(String),
20}
21
22/// A log output to be included in the `log_outputs` parameter of `VeilidLog::try_init`
23///
24/// Example: (debug logs to the terminal, and informational logs to the api tracing layer)
25/// ```rust,no_run
26/// # use veilid_core::*;
27/// let log_outputs = [
28///     LogOutput::stdout(true).with_common_log_level(VeilidConfigLogLevel::Debug),
29///     LogOutput::api().with_common_log_level(VeilidConfigLogLevel::Info)
30/// ];
31/// ```
32/// Example: (no logs to the terminal)
33/// ```
34/// # use veilid_core::*;
35/// let log_outputs = [LogOutput::stdout(true)];
36///
37/// let logs = VeilidTracing::try_init(log_outputs).expect("logs failed to initialize");
38/// // ...
39/// logs.try_apply_facility_level("#common", VeilidConfigLogLevel::Debug).expect("should set log level");
40/// ```
41#[must_use]
42pub struct LogOutput {
43    pub(super) kind: LogOutputKind,
44    pub(super) color: bool,
45    pub(super) path: PathBuf,
46    pub(super) append: bool,
47    pub(super) directives: Vec<VeilidLogDirective>,
48    pub(super) layer: Option<LogOutputLayer>,
49}
50
51pub type LogOutputLayer =
52    Box<dyn tracing_subscriber::layer::Layer<Registry> + Send + Sync + 'static>;
53
54impl LogOutput {
55    /// Creates a log writing to standard output
56    pub fn stdout(color: bool) -> Self {
57        Self {
58            kind: LogOutputKind::StdOut,
59            color,
60            path: PathBuf::new(),
61            append: false,
62            directives: vec![],
63            layer: None,
64        }
65    }
66
67    /// Creates a log writing to standard error
68    pub fn stderr(color: bool) -> Self {
69        Self {
70            kind: LogOutputKind::StdErr,
71            color,
72            path: PathBuf::new(),
73            append: false,
74            directives: vec![],
75            layer: None,
76        }
77    }
78
79    /// Creates a log writing to a file on disk
80    pub fn file<P: AsRef<Path>>(path: P, append: bool) -> Self {
81        Self {
82            kind: LogOutputKind::File,
83            color: false,
84            path: path.as_ref().to_owned(),
85            append,
86            directives: vec![],
87            layer: None,
88        }
89    }
90
91    /// Create a log that sends log output to `VeilidUpdate::Log` events
92    pub fn api() -> Self {
93        Self {
94            kind: LogOutputKind::Api,
95            color: false,
96            path: PathBuf::new(),
97            append: false,
98            directives: vec![],
99            layer: None,
100        }
101    }
102
103    /// Creates a log that accepts an arbitrary `tracing` layer
104    pub fn layer<L>(name: String, layer: LogOutputLayer) -> Self {
105        Self {
106            kind: LogOutputKind::Layer(name),
107            color: false,
108            path: PathBuf::new(),
109            append: false,
110            directives: vec![],
111            layer: Some(layer),
112        }
113    }
114
115    /// Convenience function that applies a default log level to the 'veilid::common' Veilid log tags
116    pub fn with_common_log_level(mut self, level: VeilidConfigLogLevel) -> Self {
117        self.directives
118            .push(VeilidLogDirective::try_facility_level("veilid::common", Some(level)).unwrap());
119        self
120    }
121
122    /// Change which log facilities are enabled by default on this log output.
123    /// This can also be changed after the VeilidLog is initialized.
124    pub fn try_with_directives<C: TryIntoIterVeilidLogDirective>(
125        mut self,
126        directives: C,
127    ) -> VeilidAPIResult<Self> {
128        let mut directives = directives.try_into_iter()?.collect();
129        self.directives.append(&mut directives);
130        Ok(self)
131    }
132}