tracing_tower/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/logo-type.png",
4    issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
5)]
6#![warn(
7    missing_debug_implementations,
8    // missing_docs, // TODO: add documentation!
9    rust_2018_idioms,
10    unreachable_pub,
11    bad_style,
12    dead_code,
13    improper_ctypes,
14    non_shorthand_field_patterns,
15    no_mangle_generic_items,
16    overflowing_literals,
17    path_statements,
18    patterns_in_fns_without_body,
19    private_interfaces,
20    private_bounds,
21    unconditional_recursion,
22    unused,
23    unused_allocation,
24    unused_comparisons,
25    unused_parens,
26    while_true
27)]
28
29use std::fmt;
30use tower_service::Service;
31use tracing::Level;
32
33pub mod request_span;
34pub mod service_span;
35
36#[cfg(feature = "http")]
37#[cfg_attr(docsrs, doc(cfg(feature = "http")))]
38pub mod http;
39
40pub type InstrumentedService<S, R> = service_span::Service<request_span::Service<S, R>>;
41
42pub trait InstrumentableService<Request>
43where
44    Self: Service<Request> + Sized,
45{
46    fn instrument<G>(self, svc_span: G) -> InstrumentedService<Self, Request>
47    where
48        G: GetSpan<Self>,
49        Request: fmt::Debug,
50    {
51        let req_span: fn(&Request) -> tracing::Span =
52            |request| tracing::span!(Level::TRACE, "request", ?request);
53        let svc_span = svc_span.span_for(&self);
54        self.trace_requests(req_span).trace_service(svc_span)
55    }
56
57    fn trace_requests<G>(self, get_span: G) -> request_span::Service<Self, Request, G>
58    where
59        G: GetSpan<Request> + Clone,
60    {
61        request_span::Service::new(self, get_span)
62    }
63
64    fn trace_service<G>(self, get_span: G) -> service_span::Service<Self>
65    where
66        G: GetSpan<Self>,
67    {
68        let span = get_span.span_for(&self);
69        service_span::Service::new(self, span)
70    }
71}
72
73impl<S, R> InstrumentableService<R> for S where S: Service<R> + Sized {}
74
75pub trait GetSpan<T>: crate::sealed::Sealed<T> {
76    fn span_for(&self, target: &T) -> tracing::Span;
77}
78
79impl<T, F> crate::sealed::Sealed<T> for F where F: Fn(&T) -> tracing::Span {}
80
81impl<T, F> GetSpan<T> for F
82where
83    F: Fn(&T) -> tracing::Span,
84{
85    #[inline]
86    fn span_for(&self, target: &T) -> tracing::Span {
87        (self)(target)
88    }
89}
90
91impl<T> crate::sealed::Sealed<T> for tracing::Span {}
92
93impl<T> GetSpan<T> for tracing::Span {
94    #[inline]
95    fn span_for(&self, _: &T) -> tracing::Span {
96        self.clone()
97    }
98}
99
100mod sealed {
101    pub trait Sealed<T = ()> {}
102}