Skip to main content

sc_observability_types/
errors.rs

1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4use crate::{Diagnostic, DiagnosticInfo, ErrorContext, sealed};
5
6/// Error returned when process identity resolution fails.
7#[derive(Debug, PartialEq, Serialize, Deserialize, Error)]
8#[error("{0}")]
9pub struct IdentityError(#[source] pub Box<ErrorContext>);
10
11impl sealed::Sealed for IdentityError {}
12
13impl DiagnosticInfo for IdentityError {
14    fn diagnostic(&self) -> &Diagnostic {
15        self.0.diagnostic()
16    }
17}
18
19macro_rules! error_wrapper {
20    ($(#[$meta:meta])* $name:ident) => {
21        $(#[$meta])*
22        #[derive(Debug, PartialEq, Serialize, Deserialize, Error)]
23        #[error("{0}")]
24        pub struct $name(#[source] pub Box<ErrorContext>);
25
26        impl sealed::Sealed for $name {}
27
28        impl DiagnosticInfo for $name {
29            fn diagnostic(&self) -> &Diagnostic {
30                self.0.diagnostic()
31            }
32        }
33    };
34}
35
36error_wrapper!(
37    /// Initialization error returned by public construction entry points.
38    InitError
39);
40error_wrapper!(
41    /// Event validation or lifecycle error returned during emit paths.
42    EventError
43);
44error_wrapper!(
45    /// Flush error returned by explicit flush operations.
46    FlushError
47);
48error_wrapper!(
49    /// Shutdown error returned when graceful shutdown fails.
50    ShutdownError
51);
52error_wrapper!(
53    /// Projection error returned by log/span/metric projectors.
54    ProjectionError
55);
56error_wrapper!(
57    /// Subscriber error returned by observation subscribers.
58    SubscriberError
59);
60error_wrapper!(
61    /// Logging sink error returned by concrete sink implementations.
62    LogSinkError
63);
64error_wrapper!(
65    /// Export error returned by concrete telemetry exporters.
66    ExportError
67);
68
69/// Routing/runtime error returned by `Observability::emit`.
70#[derive(Debug, PartialEq, Serialize, Deserialize, Error)]
71pub enum ObservationError {
72    #[error("observation runtime is shut down")]
73    /// The routing runtime has already been shut down.
74    Shutdown,
75    #[error("{0}")]
76    /// The runtime could not accept more observations.
77    QueueFull(#[source] Box<ErrorContext>),
78    #[error("{0}")]
79    /// No eligible subscriber or projector path handled the observation.
80    RoutingFailure(#[source] Box<ErrorContext>),
81}
82
83/// Telemetry emit error returned by `Telemetry` operations.
84#[derive(Debug, PartialEq, Serialize, Deserialize, Error)]
85pub enum TelemetryError {
86    #[error("telemetry runtime is shut down")]
87    /// The telemetry runtime has already been shut down.
88    Shutdown,
89    #[error("{0}")]
90    /// Export or span-assembly work failed for the requested telemetry operation.
91    ExportFailure(#[source] Box<ErrorContext>),
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    use crate::{Remediation, error_codes};
98
99    #[test]
100    fn wrapper_errors_expose_source_context() {
101        let wrapped = InitError(Box::new(
102            ErrorContext::new(
103                error_codes::DIAGNOSTIC_INVALID,
104                "operation failed",
105                Remediation::not_recoverable("investigate manually"),
106            )
107            .source(Box::new(std::io::Error::other("disk full"))),
108        ));
109
110        let source = std::error::Error::source(&wrapped).expect("context source");
111        assert_eq!(source.to_string(), "operation failed; caused by: disk full");
112        assert_eq!(
113            source.source().map(ToString::to_string).as_deref(),
114            Some("disk full")
115        );
116    }
117}