1use std::io;
4use std::fmt::Write;
5use tracing::{Event, Subscriber};
6use tracing::field::{Field, Visit};
7use tracing_appender::non_blocking::WorkerGuard;
8use tracing_subscriber::layer::Context;
9use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter, Layer, Registry};
10
11pub struct StringVisitor<'a> {
12 pub string: &'a mut String,
13}
14
15impl<'a> Visit for StringVisitor<'a> {
16 fn record_debug(&mut self, _field: &Field, value: &dyn std::fmt::Debug) {
17 let _ = write!(self.string, "{:?}", value);
19 }
20}
21
22pub struct CustomLayer {
23 pub callback: fn(&Event<'_>),
24}
25
26impl CustomLayer {
27 pub fn new(f: fn(_event: &Event<'_>)) -> Self {
28 Self { callback: f }
29 }
30}
31impl Default for CustomLayer {
32 fn default() -> Self {
33 CustomLayer::new(|_| {})
34 }
35}
36
37impl<S> Layer<S> for CustomLayer
38where
39 S: Subscriber,
40{
41 fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {
42 (self.callback)(_event);
43 }
44}
45
46pub fn init_tracing(
49 max_log_files: Option<u32>,
50 custom_hook: Option<fn(&Event<'_>)>,
51) -> (WorkerGuard, WorkerGuard) {
52 let env_filter = EnvFilter::try_from_default_env()
54 .or_else(|_| EnvFilter::try_new("info"))
55 .unwrap();
56
57 let (console_writer, console_guard) = tracing_appender::non_blocking(io::stdout());
59
60 let file_appender = tracing_appender::rolling::RollingFileAppender::builder()
61 .rotation(tracing_appender::rolling::Rotation::DAILY) .filename_prefix("app") .filename_suffix("log") .max_log_files(max_log_files.unwrap_or(2) as usize) .build("logs") .expect("initializing rolling file appender failed");
67 let (file_writer, file_guard) = tracing_appender::non_blocking(file_appender);
68
69 let console_layer = fmt::layer()
70 .with_timer(fmt::time::ChronoLocal::rfc_3339())
71 .with_target(false)
72 .with_writer(console_writer)
73 .with_ansi(atty::is(atty::Stream::Stdout)) .with_file(true) .with_line_number(true) .with_thread_names(false)
77 .compact();
78
79 let file_layer = fmt::layer()
80 .with_timer(fmt::time::ChronoLocal::rfc_3339())
81 .with_target(false)
82 .with_writer(file_writer)
83 .with_ansi(false)
84 .with_file(true)
85 .with_line_number(true)
86 .with_thread_names(false)
87 .compact();
88
89 let custom_layer = if let Some(fn_hook) = custom_hook {
90 CustomLayer::new(fn_hook)
91 } else {
92 CustomLayer::default()
93 };
94
95 let subscriber = Registry::default()
97 .with(env_filter)
98 .with(console_layer)
99 .with(file_layer)
100 .with(custom_layer);
101
102 tracing::subscriber::set_global_default(subscriber)
103 .expect("Failed to set global tracing subscriber");
104
105
106 (console_guard, file_guard)
108}