1use opentelemetry_otlp::ExporterBuildError;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum OtelError {
9 #[error("OTLP exporter build error: {0}")]
11 ExporterBuildError(#[from] ExporterBuildError),
12
13 #[error("unknown OTLP protocol: {0} (supported: 'grpc', 'http')")]
15 UnknownProtocol(String),
16
17 #[error("metrics shutdown error: {0}")]
19 MetricsShutdown(String),
20
21 #[error("configuration error: {0}")]
23 Configuration(String),
24
25 #[error("initialization error: {0}")]
27 Initialization(String),
28
29 #[error("tracing subscriber already initialized — only one can be set globally")]
31 SubscriberAlreadySet,
32}
33
34impl OtelError {
35 #[must_use]
37 pub fn config(msg: impl Into<String>) -> Self {
38 Self::Configuration(msg.into())
39 }
40
41 #[must_use]
43 pub fn init(msg: impl Into<String>) -> Self {
44 Self::Initialization(msg.into())
45 }
46}
47
48pub type OtelResult<T> = Result<T, OtelError>;
50
51pub trait ErrorContext<T> {
53 fn context(self, ctx: impl Into<String>) -> OtelResult<T>;
55
56 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}