Skip to main content

sc_observability/
builder.rs

1#![expect(
2    clippy::missing_errors_doc,
3    reason = "builder error behavior is documented at the facade level, and repeating it on each constructor would add low-signal boilerplate"
4)]
5#![expect(
6    clippy::must_use_candidate,
7    reason = "builder methods are used immediately in fluent construction, so extra must_use decoration is intentionally omitted here"
8)]
9
10use std::sync::{Arc, atomic::AtomicBool};
11
12use sc_observability_types::InitError;
13
14use crate::{
15    ConsoleSink, JsonlFileSink, Logger, LoggerConfig, LoggerRuntime, SinkRegistration,
16    default_log_path,
17};
18
19/// Construction-time logger builder that owns sink registration.
20#[expect(
21    missing_debug_implementations,
22    reason = "the builder stores registration trait objects whose debug representation is not part of the public API"
23)]
24pub struct LoggerBuilder {
25    config: LoggerConfig,
26    sinks: Vec<SinkRegistration>,
27}
28
29impl LoggerBuilder {
30    /// Creates a builder with the configured built-in sinks.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use std::path::PathBuf;
36    /// use sc_observability::{LoggerBuilder, LoggerConfig};
37    /// use sc_observability_types::ServiceName;
38    ///
39    /// let builder = LoggerBuilder::new(LoggerConfig::default_for(
40    ///     ServiceName::new("demo").expect("valid service"),
41    ///     PathBuf::from("logs"),
42    /// ))
43    /// .expect("valid logger config");
44    ///
45    /// let _logger = builder.build();
46    /// ```
47    pub fn new(config: LoggerConfig) -> Result<Self, InitError> {
48        let active_log_path = default_log_path(&config.log_root, &config.service_name);
49        let mut sinks = Vec::new();
50
51        if config.enable_file_sink {
52            let sink = JsonlFileSink::new(active_log_path, config.rotation, config.retention);
53            sinks.push(SinkRegistration::new(Arc::new(sink)));
54        }
55
56        if config.enable_console_sink {
57            sinks.push(SinkRegistration::new(Arc::new(ConsoleSink::stdout())));
58        }
59
60        Ok(Self { config, sinks })
61    }
62
63    /// Registers one additional sink before the logger runtime is built.
64    pub fn register_sink(&mut self, registration: SinkRegistration) -> &mut Self {
65        self.sinks.push(registration);
66        self
67    }
68
69    /// Finalizes construction and returns the logger runtime.
70    pub fn build(self) -> Logger {
71        let active_log_path = default_log_path(&self.config.log_root, &self.config.service_name);
72        let query_available = active_log_path.exists() || self.config.enable_file_sink;
73        Logger {
74            config: self.config,
75            sinks: self.sinks,
76            shutdown: Arc::new(AtomicBool::new(false)),
77            runtime: LoggerRuntime::new(query_available),
78        }
79    }
80}