use autumn_web::AutumnError;
use http::StatusCode;
use crate::config::ConfigError;
#[derive(Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum OtelError {
#[error(transparent)]
Config(#[from] ConfigError),
#[error("the OTLP exporter failed")]
#[non_exhaustive]
Export {
kind: ErrorKind,
detail: String,
},
#[error("the otel plugin is not installed: add `.plugin(OtelPlugin::new())`")]
NotInstalled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
Config,
Export,
NotInstalled,
}
impl OtelError {
#[must_use]
pub const fn kind(&self) -> ErrorKind {
match self {
Self::Config(_) => ErrorKind::Config,
Self::Export { .. } => ErrorKind::Export,
Self::NotInstalled => ErrorKind::NotInstalled,
}
}
#[must_use]
pub const fn detail(&self) -> Option<&str> {
match self {
Self::Config(err) => Some(err.0.as_str()),
Self::Export { detail, .. } => Some(detail.as_str()),
Self::NotInstalled => None,
}
}
#[must_use]
pub const fn status(&self) -> StatusCode {
match self {
Self::Config(_) | Self::NotInstalled => StatusCode::INTERNAL_SERVER_ERROR,
Self::Export { .. } => StatusCode::SERVICE_UNAVAILABLE,
}
}
#[must_use]
pub fn into_autumn(self) -> AutumnError {
let message = format!("{self}");
match self {
Self::Export { .. } => AutumnError::service_unavailable_msg(message),
Self::Config(_) | Self::NotInstalled => AutumnError::internal_server_error_msg(message),
}
}
#[must_use]
pub fn export(detail: impl Into<String>) -> Self {
Self::Export {
kind: ErrorKind::Export,
detail: detail.into(),
}
}
}
impl std::fmt::Debug for OtelError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}
pub trait OtelResultExt<T> {
fn or_http(self) -> Result<T, AutumnError>;
}
impl<T> OtelResultExt<T> for Result<T, OtelError> {
fn or_http(self) -> Result<T, AutumnError> {
self.map_err(OtelError::into_autumn)
}
}
#[cfg(test)]
mod tests;