Skip to main content

otel_rs/
error.rs

1//! Error types for the observability library.
2
3use opentelemetry_otlp::ExporterBuildError;
4use thiserror::Error;
5
6/// Main error type for the otel-rs library.
7#[derive(Debug, Error)]
8pub enum OtelError {
9    /// Error building an OTLP exporter.
10    #[error("OTLP exporter build error: {0}")]
11    ExporterBuildError(#[from] ExporterBuildError),
12
13    /// Unknown or unsupported OTLP protocol.
14    #[error("unknown OTLP protocol: {0} (supported: 'grpc', 'http')")]
15    UnknownProtocol(String),
16
17    /// Metrics shutdown error.
18    #[error("metrics shutdown error: {0}")]
19    MetricsShutdown(String),
20
21    /// Configuration error.
22    #[error("configuration error: {0}")]
23    Configuration(String),
24
25    /// Initialization error.
26    #[error("initialization error: {0}")]
27    Initialization(String),
28
29    /// Tracing subscriber already set globally.
30    #[error("tracing subscriber already initialized — only one can be set globally")]
31    SubscriberAlreadySet,
32}
33
34impl OtelError {
35    /// Create a configuration error.
36    #[must_use]
37    pub fn config(msg: impl Into<String>) -> Self {
38        Self::Configuration(msg.into())
39    }
40
41    /// Create an initialization error.
42    #[must_use]
43    pub fn init(msg: impl Into<String>) -> Self {
44        Self::Initialization(msg.into())
45    }
46}
47
48/// Result type alias for otel-rs operations.
49pub type OtelResult<T> = Result<T, OtelError>;
50
51/// Extension trait for adding context to errors.
52pub trait ErrorContext<T> {
53    /// Wrap the error with additional context.
54    fn context(self, ctx: impl Into<String>) -> OtelResult<T>;
55
56    /// Wrap the error with lazily-evaluated context.
57    fn with_context<F: FnOnce() -> String>(self, f: F) -> OtelResult<T>;
58}
59
60impl<T, E: std::error::Error + 'static> ErrorContext<T> for Result<T, E> {
61    fn context(self, ctx: impl Into<String>) -> OtelResult<T> {
62        self.map_err(|e| OtelError::Initialization(format!("{}: {e}", ctx.into())))
63    }
64
65    fn with_context<F: FnOnce() -> String>(self, f: F) -> OtelResult<T> {
66        self.map_err(|e| OtelError::Initialization(format!("{}: {e}", f())))
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn error_display() {
76        let err = OtelError::UnknownProtocol("websocket".into());
77        assert!(err.to_string().contains("websocket"));
78    }
79
80    #[test]
81    fn config_error() {
82        let err = OtelError::config("bad endpoint");
83        assert!(err.to_string().contains("bad endpoint"));
84    }
85}