sc_observability/
builder.rs1#![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#[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 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 pub fn register_sink(&mut self, registration: SinkRegistration) -> &mut Self {
65 self.sinks.push(registration);
66 self
67 }
68
69 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}