Skip to main content

elph_core/logger/
mod.rs

1mod rotation;
2
3use elph_agent::LoggingOptions;
4use tracing_appender::non_blocking::{NonBlockingBuilder, WorkerGuard};
5use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
6
7pub use rotation::build_writer;
8
9/// Bounded queue for the async file writer. Caps memory under sustained log bursts
10/// (default upstream limit is 128_000 lines).
11const FILE_WRITER_BUFFER_LINES: usize = 16_384;
12
13/// Initializes the global tracing subscriber.
14///
15/// Returns a [`WorkerGuard`] that must be kept alive for the process lifetime so
16/// the non-blocking file writer can flush buffered records.
17pub fn init(options: LoggingOptions) -> Option<WorkerGuard> {
18    if cfg!(test) {
19        return None;
20    }
21
22    install_subscriber(&options)
23}
24
25fn non_blocking_writer(options: &LoggingOptions) -> (tracing_appender::non_blocking::NonBlocking, WorkerGuard) {
26    let writer = build_writer(&options.logs_dir, options.app_name, options.rotation, options.max_files)
27        .expect("failed to initialize rolling log writer");
28    NonBlockingBuilder::default()
29        .buffered_lines_limit(FILE_WRITER_BUFFER_LINES)
30        .finish(writer)
31}
32
33fn install_subscriber(options: &LoggingOptions) -> Option<WorkerGuard> {
34    let env_filter = EnvFilter::new(options.level.clone());
35
36    match (options.file_enabled, options.console_enabled) {
37        (true, true) => {
38            let (non_blocking, guard) = non_blocking_writer(options);
39
40            tracing_subscriber::registry()
41                .with(env_filter)
42                .with(
43                    fmt::layer()
44                        .json()
45                        .with_writer(non_blocking)
46                        .with_ansi(false)
47                        .with_target(true),
48                )
49                .with(
50                    fmt::layer()
51                        .with_writer(std::io::stdout)
52                        .with_target(true)
53                        .with_ansi(true),
54                )
55                .init();
56
57            Some(guard)
58        }
59        (true, false) => {
60            let (non_blocking, guard) = non_blocking_writer(options);
61
62            tracing_subscriber::registry()
63                .with(env_filter)
64                .with(
65                    fmt::layer()
66                        .json()
67                        .with_writer(non_blocking)
68                        .with_ansi(false)
69                        .with_target(true),
70                )
71                .init();
72
73            Some(guard)
74        }
75        (false, true) => {
76            tracing_subscriber::registry()
77                .with(env_filter)
78                .with(
79                    fmt::layer()
80                        .with_writer(std::io::stdout)
81                        .with_target(true)
82                        .with_ansi(true),
83                )
84                .init();
85
86            None
87        }
88        (false, false) => {
89            tracing_subscriber::registry().with(env_filter).init();
90            None
91        }
92    }
93}