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`]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/layer/trait.Layer.html
19/// [`SpanTrace`]: ../struct.SpanTrace.html
20/// [field formatter]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/trait.FormatFields.html
21/// [default format]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/format/struct.DefaultFields.html
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: SpanRef<'_, S> = ctx.span(id).expect(msg:"span must already exist!");
45 if span.extensions().get::<FormattedFields<F>>().is_some() {
46 return;
47 }
48 let mut fields: FormattedFields = FormattedFields::<F>::new(fields:String::new());
49 if self.format.format_fields(fields.as_writer(), fields:attrs).is_ok() {
50 span.extensions_mut().insert(val:fields);
51 }
52 }
53
54 unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
55 match id {
56 id: TypeId if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()),
57 id: TypeId 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]: https://docs.rs/tracing-subscriber/0.2.10/tracing_subscriber/fmt/trait.FormatFields.html
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<'a>(
107 &self,
108 dispatch: &'a 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(format: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&mut DebugStruct<'_, '_>.debug_struct("ErrorLayer")
128 .field("format", &self.format)
129 .field(name:"subscriber", &format_args!("{}", type_name::<S>()))
130 .finish()
131 }
132}
133