tracing_error/
layer.rs

1use std::any::{type_name, TypeId};
2use std::fmt;
3use std::marker::PhantomData;
4use tracing::{span, Dispatch, Metadata, Subscriber};
5use tracing_subscriber::fmt::format::{DefaultFields, FormatFields};
6use tracing_subscriber::{
7    fmt::FormattedFields,
8    layer::{self, Layer},
9    registry::LookupSpan,
10};
11
12/// A subscriber [`Layer`] that enables capturing [`SpanTrace`]s.
13///
14/// Optionally, this type may be constructed with a [field formatter] to use
15/// when formatting the fields of each span in a trace. When no formatter is
16/// provided, the [default format] is used instead.
17///
18/// [`Layer`]: tracing_subscriber::layer::Layer
19/// [`SpanTrace`]: super::SpanTrace
20/// [field formatter]: tracing_subscriber::fmt::FormatFields
21/// [default format]: tracing_subscriber::fmt::format::DefaultFields
22pub struct ErrorLayer<S, F = DefaultFields> {
23    format: F,
24
25    get_context: WithContext,
26    _subscriber: PhantomData<fn(S)>,
27}
28
29// this function "remembers" the types of the subscriber and the formatter,
30// so that we can downcast to something aware of them without knowing those
31// types at the callsite.
32pub(crate) struct WithContext(
33    fn(&Dispatch, &span::Id, f: &mut dyn FnMut(&'static Metadata<'static>, &str) -> bool),
34);
35
36impl<S, F> Layer<S> for ErrorLayer<S, F>
37where
38    S: Subscriber + for<'span> LookupSpan<'span>,
39    F: for<'writer> FormatFields<'writer> + 'static,
40{
41    /// Notifies this layer that a new span was constructed with the given
42    /// `Attributes` and `Id`.
43    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) {
44        let span = ctx.span(id).expect("span must already exist!");
45        if span.extensions().get::<FormattedFields<F>>().is_some() {
46            return;
47        }
48        let mut fields = FormattedFields::<F>::new(String::new());
49        if self.format.format_fields(fields.as_writer(), attrs).is_ok() {
50            span.extensions_mut().insert(fields);
51        }
52    }
53
54    unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
55        match id {
56            id if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()),
57            id if id == TypeId::of::<WithContext>() => {
58                Some(&self.get_context as *const _ as *const ())
59            }
60            _ => None,
61        }
62    }
63}
64
65impl<S, F> ErrorLayer<S, F>
66where
67    F: for<'writer> FormatFields<'writer> + 'static,
68    S: Subscriber + for<'span> LookupSpan<'span>,
69{
70    /// Returns a new `ErrorLayer` with the provided [field formatter].
71    ///
72    /// [field formatter]: tracing_subscriber::fmt::FormatFields
73    pub fn new(format: F) -> Self {
74        Self {
75            format,
76            get_context: WithContext(Self::get_context),
77            _subscriber: PhantomData,
78        }
79    }
80
81    fn get_context(
82        dispatch: &Dispatch,
83        id: &span::Id,
84        f: &mut dyn FnMut(&'static Metadata<'static>, &str) -> bool,
85    ) {
86        let subscriber = dispatch
87            .downcast_ref::<S>()
88            .expect("subscriber should downcast to expected type; this is a bug!");
89        let span = subscriber
90            .span(id)
91            .expect("registry should have a span for the current ID");
92        for span in span.scope() {
93            let cont = if let Some(fields) = span.extensions().get::<FormattedFields<F>>() {
94                f(span.metadata(), fields.fields.as_str())
95            } else {
96                f(span.metadata(), "")
97            };
98            if !cont {
99                break;
100            }
101        }
102    }
103}
104
105impl WithContext {
106    pub(crate) fn with_context(
107        &self,
108        dispatch: &Dispatch,
109        id: &span::Id,
110        mut f: impl FnMut(&'static Metadata<'static>, &str) -> bool,
111    ) {
112        (self.0)(dispatch, id, &mut f)
113    }
114}
115
116impl<S> Default for ErrorLayer<S>
117where
118    S: Subscriber + for<'span> LookupSpan<'span>,
119{
120    fn default() -> Self {
121        Self::new(DefaultFields::default())
122    }
123}
124
125impl<S, F: fmt::Debug> fmt::Debug for ErrorLayer<S, F> {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        f.debug_struct("ErrorLayer")
128            .field("format", &self.format)
129            .field("subscriber", &format_args!("{}", type_name::<S>()))
130            .finish()
131    }
132}