datadog_formatting_layer/
fields.rs1use 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}