datadog_formatting_layer/
fields.rs

1use std::{cmp::Ordering, collections::HashMap};
2use tracing::{field::Visit, span::Attributes, Event, Subscriber};
3use tracing_subscriber::{
4    layer::Context,
5    registry::{LookupSpan, Scope},
6};
7
8#[derive(Debug, Clone)]
9pub struct FieldStore {
10    pub fields: Vec<FieldPair>,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct FieldPair {
15    pub name: String,
16    pub value: String,
17}
18
19impl PartialOrd for FieldPair {
20    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
21        Some(self.name.cmp(&other.name))
22    }
23}
24
25impl Ord for FieldPair {
26    fn cmp(&self, other: &Self) -> Ordering {
27        self.name.cmp(&other.name)
28    }
29}
30
31pub fn from_attributes(attrs: &Attributes<'_>) -> Vec<FieldPair> {
32    let mut visitor = Visitor::default();
33    attrs.values().record(&mut visitor);
34
35    visitor
36        .fields
37        .into_iter()
38        .map(|(key, value)| FieldPair { name: key, value })
39        .collect()
40}
41
42pub fn from_event(event: &Event<'_>) -> Vec<FieldPair> {
43    let mut visitor = Visitor::default();
44    event.record(&mut visitor);
45
46    visitor
47        .fields
48        .into_iter()
49        .map(|(key, value)| FieldPair { name: key, value })
50        .collect()
51}
52
53pub fn from_spans<S: Subscriber + for<'a> LookupSpan<'a>>(
54    ctx: &Context<'_, S>,
55    event: &Event<'_>,
56) -> Vec<FieldPair> {
57    ctx.event_scope(event)
58        .into_iter()
59        .flat_map(Scope::from_root)
60        .flat_map(|span| {
61            #[allow(clippy::expect_used)]
62            let fields_from_span = span
63                .extensions()
64                .get::<FieldStore>()
65                .expect("No Fields found in span extensions")
66                .clone();
67
68            fields_from_span.fields
69        })
70        .collect()
71}
72
73#[derive(Default)]
74struct Visitor {
75    fields: HashMap<String, String>,
76}
77
78impl Visit for Visitor {
79    fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
80        self.fields
81            .insert(field.name().to_string(), format!("{value:?}"));
82    }
83}