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}