tracing_fluentd/
tracing.rs

1use tracing_subscriber::registry::{LookupSpan, SpanRef};
2use tracing_core::subscriber::Subscriber as Collect;
3use tracing_subscriber::layer::Context;
4use tracing_core::span::{Id, Attributes, Record};
5use tracing_core::{Event, Field};
6
7use crate::{Layer, FlattenFmt, NestedFmt, fluent, worker};
8
9use core::fmt;
10
11macro_rules! get_span {
12    ($ctx:ident[$id:ident]) => {
13        match $ctx.span($id) {
14            Some(span) => span,
15            None => return,
16        }
17    }
18}
19
20///Describes how compose event fields.
21pub trait FieldFormatter: 'static {
22    #[inline(always)]
23    ///Handler for when `Layer::new_span` is invoked.
24    ///
25    ///By default uses span's extensions to store `fluent::Map` containing attributes of the span.
26    fn on_new_span<C: Collect + for<'a> LookupSpan<'a>>(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, C>) {
27        let span = get_span!(ctx[id]);
28
29        if span.extensions().get::<fluent::Map>().is_none() {
30            let mut record = fluent::Map::new();
31            attrs.record(&mut record);
32
33            span.extensions_mut().insert(record);
34        }
35    }
36
37    #[inline(always)]
38    ///Handler for when `Layer::new_span` is invoked.
39    ///
40    ///By default uses span's extensions to store extra attributes of span within `fluent::Map`,
41    ///created by  new_span, if any.
42    fn on_record<C: Collect + for<'a> LookupSpan<'a>>(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, C>) {
43        let span = get_span!(ctx[id]);
44
45        let mut extensions = span.extensions_mut();
46        if let Some(record) = extensions.get_mut::<fluent::Map>() {
47            values.record(record);
48        }
49    }
50
51    ///Handler for when `Layer::on_event` is invoked.
52    ///
53    ///Given `record` must be filled with data, after exiting this method, `record` is sent to the
54    ///fluentd
55    fn on_event<'a, R: LookupSpan<'a>>(&self, record: &mut fluent::Record, event: &Event<'_>, current_span: Option<SpanRef<'a, R>>);
56}
57
58impl FieldFormatter for NestedFmt {
59    #[inline(always)]
60    fn on_event<'a, R: LookupSpan<'a>>(&self, event_record: &mut fluent::Record, event: &Event<'_>, current_span: Option<SpanRef<'a, R>>) {
61        use core::ops::DerefMut;
62
63        event.record(event_record.deref_mut());
64
65        if let Some(span) = current_span {
66            for span in span.scope() {
67                let extensions = span.extensions();
68                if let Some(record) = extensions.get::<fluent::Map>() {
69                    event_record.insert(span.name().into(), record.clone().into());
70                }
71            }
72        }
73
74        let mut metadata = fluent::Map::new();
75
76        if let Some(name) = event.metadata().file() {
77            metadata.insert("file".into(), name.into());
78        }
79        if let Some(line) = event.metadata().line() {
80            metadata.insert("line".into(), line.into());
81        }
82        metadata.insert("module".into(), event.metadata().target().into());
83        metadata.insert("level".into(), event.metadata().level().to_owned().into());
84
85        event_record.insert("metadata".into(), metadata.into());
86    }
87}
88
89impl FieldFormatter for FlattenFmt {
90    #[inline(always)]
91    fn on_event<'a, R: LookupSpan<'a>>(&self, event_record: &mut fluent::Record, event: &Event<'_>, current_span: Option<SpanRef<'a, R>>) {
92        use core::ops::DerefMut;
93
94        event.record(event_record.deref_mut());
95
96        if let Some(span) = current_span {
97            for span in span.scope() {
98                let extensions = span.extensions();
99                if let Some(record) = extensions.get::<fluent::Map>() {
100                    event_record.update(record);
101                }
102            }
103        }
104
105        if let Some(name) = event.metadata().file() {
106            event_record.insert("file".into(), name.into());
107        }
108        if let Some(line) = event.metadata().line() {
109            event_record.insert("line".into(), line.into());
110        }
111        event_record.insert("module".into(), event.metadata().target().into());
112        event_record.insert("level".into(), event.metadata().level().to_owned().into());
113    }
114}
115
116impl tracing_core::field::Visit for fluent::Map {
117    #[inline(always)]
118    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
119        let value = format!("{:?}", value);
120        self.insert(field.name().into(), value.into());
121    }
122
123    #[inline(always)]
124    fn record_i64(&mut self, field: &Field, value: i64) {
125        self.insert(field.name().into(), value.into());
126    }
127
128    #[inline(always)]
129    fn record_u64(&mut self, field: &Field, value: u64) {
130        self.insert(field.name().into(), value.into());
131    }
132
133    #[inline(always)]
134    fn record_f64(&mut self, field: &Field, value: f64) {
135        self.insert(field.name().into(), value.into());
136    }
137
138    #[inline(always)]
139    fn record_bool(&mut self, field: &Field, value: bool) {
140        self.insert(field.name().into(), value.into());
141    }
142
143    #[inline(always)]
144    fn record_str(&mut self, field: &Field, value: &str) {
145        self.insert(field.name().into(), value.to_owned().into());
146    }
147
148    #[inline(always)]
149    fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
150        let value = format!("{}", value);
151        self.insert(field.name().into(), value.into());
152    }
153}
154
155impl<F: FieldFormatter, W: worker::Consumer, C: Collect + for<'a> LookupSpan<'a>> tracing_subscriber::layer::Layer<C> for Layer<F, W> {
156    #[inline(always)]
157    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, C>) {
158        self.fmt.on_new_span(attrs, id, ctx);
159    }
160
161    #[inline(always)]
162    fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, C>) {
163        self.fmt.on_record(id, values, ctx);
164    }
165
166    #[inline(always)]
167    fn on_enter(&self, _id: &Id, _ctx: Context<'_, C>) {
168    }
169
170    #[inline(always)]
171    fn on_exit(&self, _id: &Id, _ctx: Context<'_, C>) {
172    }
173
174    #[inline(always)]
175    fn on_close(&self, _id: Id, _ctx: Context<'_, C>) {
176    }
177
178    #[inline]
179    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, C>) {
180        let mut record = fluent::Record::now();
181
182        self.fmt.on_event(&mut record, event, ctx.event_span(event));
183
184        self.consumer.record(record);
185    }
186}