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 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}