dcontext_tracing/
field_mapping.rs1use std::collections::HashMap;
2use std::fmt;
3
4use tracing_core::field::{Field, Visit};
5
6pub(crate) struct FieldMapping {
11 pub field_name: &'static str,
12 pub context_key: &'static str,
13 pub setter: Box<dyn FieldSetter>,
14}
15
16pub(crate) trait FieldSetter: Send + Sync {
18 fn set_from_str(&self, key: &'static str, value: &str);
20 fn set_from_u64(&self, key: &'static str, value: u64);
22 fn set_from_i64(&self, key: &'static str, value: i64);
24 fn set_from_bool(&self, key: &'static str, value: bool);
26}
27
28pub trait FromFieldValue: Clone + Default + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static {
48 fn from_str_value(s: &str) -> Option<Self> {
50 let _ = s;
51 None
52 }
53
54 fn from_u64_value(v: u64) -> Option<Self> {
56 let _ = v;
57 None
58 }
59
60 fn from_i64_value(v: i64) -> Option<Self> {
62 let _ = v;
63 None
64 }
65
66 fn from_bool_value(v: bool) -> Option<Self> {
68 let _ = v;
69 None
70 }
71}
72
73pub(crate) struct TypedFieldSetter<T> {
75 _marker: std::marker::PhantomData<T>,
76}
77
78impl<T> TypedFieldSetter<T> {
79 pub fn new() -> Self {
80 Self {
81 _marker: std::marker::PhantomData,
82 }
83 }
84}
85
86impl<T> FieldSetter for TypedFieldSetter<T>
87where
88 T: FromFieldValue,
89{
90 fn set_from_str(&self, key: &'static str, value: &str) {
91 if let Some(v) = T::from_str_value(value) {
92 dcontext::set_context(key, v);
93 }
94 }
95
96 fn set_from_u64(&self, key: &'static str, value: u64) {
97 if let Some(v) = T::from_u64_value(value) {
98 dcontext::set_context(key, v);
99 }
100 }
101
102 fn set_from_i64(&self, key: &'static str, value: i64) {
103 if let Some(v) = T::from_i64_value(value) {
104 dcontext::set_context(key, v);
105 }
106 }
107
108 fn set_from_bool(&self, key: &'static str, value: bool) {
109 if let Some(v) = T::from_bool_value(value) {
110 dcontext::set_context(key, v);
111 }
112 }
113}
114
115pub(crate) struct ExtractedFields {
119 pub string_values: HashMap<&'static str, String>,
120 pub u64_values: HashMap<&'static str, u64>,
121 pub i64_values: HashMap<&'static str, i64>,
122 pub bool_values: HashMap<&'static str, bool>,
123}
124
125impl ExtractedFields {
126 pub fn new() -> Self {
127 Self {
128 string_values: HashMap::new(),
129 u64_values: HashMap::new(),
130 i64_values: HashMap::new(),
131 bool_values: HashMap::new(),
132 }
133 }
134
135 pub fn is_empty(&self) -> bool {
136 self.string_values.is_empty()
137 && self.u64_values.is_empty()
138 && self.i64_values.is_empty()
139 && self.bool_values.is_empty()
140 }
141}
142
143pub(crate) struct FieldExtractor<'a> {
145 pub target_fields: &'a [&'static str],
147 pub extracted: ExtractedFields,
148}
149
150impl<'a> FieldExtractor<'a> {
151 pub fn new(target_fields: &'a [&'static str]) -> Self {
152 Self {
153 target_fields,
154 extracted: ExtractedFields::new(),
155 }
156 }
157
158 fn is_target(&self, field: &Field) -> Option<&'static str> {
159 self.target_fields.iter().find(|&&f| f == field.name()).copied()
160 }
161}
162
163impl<'a> Visit for FieldExtractor<'a> {
164 fn record_str(&mut self, field: &Field, value: &str) {
165 if let Some(key) = self.is_target(field) {
166 self.extracted.string_values.insert(key, value.to_string());
167 }
168 }
169
170 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
171 if let Some(key) = self.is_target(field) {
172 if !self.extracted.string_values.contains_key(key)
174 && !self.extracted.u64_values.contains_key(key)
175 && !self.extracted.i64_values.contains_key(key)
176 && !self.extracted.bool_values.contains_key(key)
177 {
178 self.extracted
179 .string_values
180 .insert(key, format!("{:?}", value));
181 }
182 }
183 }
184
185 fn record_u64(&mut self, field: &Field, value: u64) {
186 if let Some(key) = self.is_target(field) {
187 self.extracted.u64_values.insert(key, value);
188 }
189 }
190
191 fn record_i64(&mut self, field: &Field, value: i64) {
192 if let Some(key) = self.is_target(field) {
193 self.extracted.i64_values.insert(key, value);
194 }
195 }
196
197 fn record_bool(&mut self, field: &Field, value: bool) {
198 if let Some(key) = self.is_target(field) {
199 self.extracted.bool_values.insert(key, value);
200 }
201 }
202}