1use std::path::PathBuf;
10pub use tracing_subscriber::{fmt, prelude::*, EnvFilter};
11
12#[derive(Debug, Clone)]
14pub struct LogConfig {
15 pub log_dir: Option<PathBuf>,
17
18 pub level: String,
20
21 pub json_format: bool,
23}
24
25impl Default for LogConfig {
26 fn default() -> Self {
27 Self {
28 log_dir: None,
29 level: "info".to_string(),
30 json_format: cfg!(feature = "json"),
31 }
32 }
33}
34
35pub fn init_logging(config: LogConfig) -> anyhow::Result<()> {
58 let filter =
60 EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(&config.level));
61
62 match config.log_dir {
63 None => init_stdout_logging(filter, config.json_format),
64 Some(dir) => init_file_logging(dir, filter, config.json_format),
65 }
66}
67
68#[allow(unused_variables)]
70fn init_stdout_logging(filter: EnvFilter, json_format: bool) -> anyhow::Result<()> {
71 #[cfg(feature = "json")]
72 {
73 if json_format {
74 tracing_subscriber::registry()
75 .with(filter)
76 .with(
77 fmt::layer()
78 .json()
79 .with_target(true)
80 .with_current_span(true)
81 .with_span_list(false)
82 .with_thread_ids(true)
83 .with_thread_names(true),
84 )
85 .init();
86 return Ok(());
87 }
88 }
89
90 tracing_subscriber::registry()
92 .with(filter)
93 .with(
94 fmt::layer()
95 .compact()
96 .with_target(true)
97 .with_thread_ids(false),
98 )
99 .init();
100
101 Ok(())
102}
103
104#[allow(unused_variables)]
106fn init_file_logging(log_dir: PathBuf, filter: EnvFilter, json_format: bool) -> anyhow::Result<()> {
107 std::fs::create_dir_all(&log_dir)?;
109
110 let file_appender = tracing_appender::rolling::daily(log_dir, "probe.log");
112 let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
113
114 #[cfg(feature = "json")]
115 {
116 if json_format {
117 tracing_subscriber::registry()
118 .with(filter)
119 .with(
120 fmt::layer()
121 .json()
122 .with_target(true)
123 .with_current_span(true)
124 .with_span_list(false)
125 .with_thread_ids(true)
126 .with_thread_names(true)
127 .with_writer(non_blocking),
128 )
129 .init();
130 return Ok(());
131 }
132 }
133
134 tracing_subscriber::registry()
136 .with(filter)
137 .with(
138 fmt::layer()
139 .with_target(true)
140 .with_thread_ids(true)
141 .with_ansi(false) .with_writer(non_blocking),
143 )
144 .init();
145
146 Ok(())
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_default_config() {
155 let config = LogConfig::default();
156 assert_eq!(config.level, "info");
157 assert!(config.log_dir.is_none());
158 }
159}