tracing_actix_web/root_span.rs
1use actix_web::{dev::Payload, HttpMessage};
2use actix_web::{FromRequest, HttpRequest, ResponseError};
3use std::future::{ready, Ready};
4use tracing::Span;
5
6#[derive(Clone)]
7/// The root span associated to the in-flight current request.
8///
9/// It can be used to populate additional properties using values computed or retrieved in the request
10/// handler - see the crate-level documentation for more details.
11///
12/// Extracting a `RootSpan` when the `TracingLogger` middleware is not registered will result in
13/// an internal server error.
14///
15/// # Usage
16/// ```rust
17/// use actix_web::get;
18/// use tracing_actix_web::RootSpan;
19/// use uuid::Uuid;
20///
21/// #[get("/")]
22/// async fn index(root_span: RootSpan) -> String {
23/// root_span.record("route", &"/");
24/// # "Hello".to_string()
25/// }
26/// ```
27pub struct RootSpan(Span);
28
29impl RootSpan {
30 pub(crate) fn new(span: Span) -> Self {
31 Self(span)
32 }
33}
34
35impl std::ops::Deref for RootSpan {
36 type Target = Span;
37
38 fn deref(&self) -> &Self::Target {
39 &self.0
40 }
41}
42
43impl From<RootSpan> for Span {
44 fn from(r: RootSpan) -> Self {
45 r.0
46 }
47}
48
49impl FromRequest for RootSpan {
50 type Error = RootSpanExtractionError;
51 type Future = Ready<Result<Self, Self::Error>>;
52
53 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
54 ready(
55 req.extensions()
56 .get::<RootSpan>()
57 .cloned()
58 .ok_or(RootSpanExtractionError { _priv: () }),
59 )
60 }
61}
62
63#[derive(Debug)]
64/// Error returned by the [`RootSpan`] extractor when it fails to retrieve
65/// the root span from request-local storage.
66///
67/// It only happens if you try to extract the root span without having
68/// registered [`TracingLogger`] as a middleware for your application.
69///
70/// [`TracingLogger`]: crate::TracingLogger
71pub struct RootSpanExtractionError {
72 // It turns out that a unit struct has a public constructor!
73 // Therefore adding fields to it (either public or private) later on
74 // is an API breaking change.
75 // Therefore we are adding a dummy private field that the compiler is going
76 // to optimise away to make sure users cannot construct this error
77 // manually in their own code.
78 _priv: (),
79}
80
81impl ResponseError for RootSpanExtractionError {}
82
83impl std::fmt::Display for RootSpanExtractionError {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(
86 f,
87 "Failed to retrieve the root span from request-local storage."
88 )
89 }
90}
91
92impl std::error::Error for RootSpanExtractionError {}