Skip to main content

axum_observability/
lib.rs

1//! Request correlation and structured terminal access logging for Axum.
2//!
3//! [`ObservabilityLayer`] validates or generates request IDs, accepts strict
4//! W3C trace context, installs a [`RequestContext`] extension, and emits one
5//! terminal access event after the response body completes or is abandoned.
6//! [`JsonLayer`] formats those records and application `tracing` events without
7//! installing a global subscriber.
8//!
9//! ```
10//! use axum::{Router, routing::get};
11//! use axum_observability::{ObservabilityConfig, ObservabilityLayer};
12//! use tracing_subscriber::prelude::*;
13//!
14//! let config = ObservabilityConfig::default();
15//! let subscriber = tracing_subscriber::registry()
16//!     .with(config.json_layer(std::io::sink));
17//! let app: Router = Router::new()
18//!     .route("/health", get(|| async { "ok" }))
19//!     .layer(ObservabilityLayer::new(config));
20//!
21//! # let _ = (subscriber, app);
22//! ```
23
24#![forbid(unsafe_code)]
25#![warn(clippy::print_stdout)]
26
27mod context;
28mod formatter;
29mod middleware;
30mod request_id;
31mod trace_context;
32
33pub use context::{MissingRequestContext, OperationId, RequestContext, TraceContext};
34pub use formatter::JsonLayer;
35pub use middleware::{ObservabilityConfig, ObservabilityLayer, ObservabilityService};
36pub use request_id::{InvalidRequestId, RequestId};
37
38/// W3C Trace Context level used for inbound validation and projection.
39#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
40pub enum TraceContextLevel {
41    /// W3C Trace Context Level 1. This is the default.
42    #[default]
43    Level1,
44    /// W3C Trace Context Level 2, including the random trace-ID flag.
45    Level2,
46}
47
48impl TraceContextLevel {
49    /// Returns the numeric W3C Trace Context level.
50    #[must_use]
51    pub const fn as_u8(self) -> u8 {
52        match self {
53            Self::Level1 => 1,
54            Self::Level2 => 2,
55        }
56    }
57}
58
59/// Structured logging field convention.
60#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
61#[non_exhaustive]
62pub enum FieldConvention {
63    /// Provider-neutral fields using `level`.
64    #[default]
65    Generic,
66    /// Google Cloud structured logging fields using `severity` and
67    /// `httpRequest`.
68    Gcp,
69    /// AWS-oriented fields, including an X-Ray-compatible trace identifier.
70    Aws,
71    /// Azure-oriented operation correlation fields.
72    Azure,
73}
74
75#[cfg(test)]
76mod tests {
77    use super::{FieldConvention, TraceContextLevel};
78
79    #[test]
80    fn generic_is_the_default_field_convention() {
81        assert_eq!(FieldConvention::default(), FieldConvention::Generic);
82    }
83
84    #[test]
85    fn level_one_is_the_default_trace_context_level() {
86        assert_eq!(TraceContextLevel::default(), TraceContextLevel::Level1);
87        assert_eq!(TraceContextLevel::Level1.as_u8(), 1);
88        assert_eq!(TraceContextLevel::Level2.as_u8(), 2);
89    }
90}