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}