Skip to main content

sc_command/
observability.rs

1//! Canonical event injection without linking a logging runtime.
2//!
3//! Applications may implement this open receiver port and own their sinks and
4//! lifecycle. This temporary 1.5.0 contract is removed after upstream capability
5//! proof: <https://github.com/randlee/sc-runtime/issues/97> (ADR-RUN-0017).
6
7use sc_observability_types::{LogEvent, ServiceName, v2};
8
9use std::sync::Arc;
10
11/// A trusted synchronous canonical event receiver.
12///
13/// Implementations must return promptly, perform no sink I/O or capacity wait,
14/// and never panic. Libraries treat rejection as best effort.
15pub trait CanonicalLog: Send + Sync {
16    /// Returns the receiver's service identity.
17    fn service_name(&self) -> &ServiceName;
18
19    /// Attempts immediate event admission.
20    ///
21    /// # Errors
22    /// Returns an event error when the receiver rejects the event.
23    fn emit(&self, event: LogEvent) -> Result<(), v2::EventError>;
24}
25
26/// Shared ownership of an object-safe canonical event receiver.
27pub type SharedCanonicalLog = Arc<dyn CanonicalLog>;
28
29/// A receiver that retains a service name and discards all events.
30#[derive(Clone, Debug)]
31pub struct NoopCanonicalLog {
32    service: ServiceName,
33}
34
35impl NoopCanonicalLog {
36    /// Creates a discarding receiver with the supplied validated identity.
37    #[must_use]
38    pub fn new(service_name: ServiceName) -> Self {
39        Self {
40            service: service_name,
41        }
42    }
43
44    /// Uses a valid static service name, falling back to `noop` for invalid names.
45    ///
46    /// The fixed fallback is validated by the exact types 1.5.0 dependency.
47    /// ADR-RUN-0017 permits only this literal invariant; caller input is never
48    /// unwrapped. Upstream capability cleanup removes this temporary exception.
49    #[must_use]
50    pub fn named_or_default(service: &'static str) -> Self {
51        let service = ServiceName::new(service).unwrap_or_else(|_| {
52            // ADR-RUN-0017 fixed-literal invariant, bounded by exact types =1.5.0.
53            // Never unwrap caller/environment data. Remove with upstream cleanup:
54            // https://github.com/randlee/sc-runtime/issues/97
55            ServiceName::new("noop")
56                .expect("fixed noop identity is valid in pinned sc-observability-types 1.5.0")
57        });
58        Self::new(service)
59    }
60}
61
62impl CanonicalLog for NoopCanonicalLog {
63    fn service_name(&self) -> &ServiceName {
64        &self.service
65    }
66
67    fn emit(&self, _event: LogEvent) -> Result<(), v2::EventError> {
68        Ok(())
69    }
70}
71
72#[cfg(feature = "test-util")]
73mod test_util;
74
75#[cfg(feature = "test-util")]
76pub use test_util::{RecordingCanonicalLog, RejectingCanonicalLog};
77
78#[cfg(test)]
79mod tests;