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
73impl FromFieldValue for String {
84 fn from_str_value(s: &str) -> Option<Self> {
85 Some(s.to_string())
86 }
87}
88
89pub(crate) struct TypedFieldSetter<T> {
91 _marker: std::marker::PhantomData<T>,
92}
93
94impl<T> TypedFieldSetter<T> {
95 pub fn new() -> Self {
96 Self {
97 _marker: std::marker::PhantomData,
98 }
99 }
100}
101
102impl<T> FieldSetter for TypedFieldSetter<T>
103where
104 T: FromFieldValue,
105{
106 fn set_from_str(&self, key: &'static str, value: &str) {
107 if let Some(v) = T::from_str_value(value) {
108 dcontext::set_context(key, v);
109 }
110 }
111
112 fn set_from_u64(&self, key: &'static str, value: u64) {
113 if let Some(v) = T::from_u64_value(value) {
114 dcontext::set_context(key, v);
115 }
116 }
117
118 fn set_from_i64(&self, key: &'static str, value: i64) {
119 if let Some(v) = T::from_i64_value(value) {
120 dcontext::set_context(key, v);
121 }
122 }
123
124 fn set_from_bool(&self, key: &'static str, value: bool) {
125 if let Some(v) = T::from_bool_value(value) {
126 dcontext::set_context(key, v);
127 }
128 }
129}
130
131pub(crate) struct ExtractedFields {
135 pub string_values: HashMap<&'static str, String>,
136 pub u64_values: HashMap<&'static str, u64>,
137 pub i64_values: HashMap<&'static str, i64>,
138 pub bool_values: HashMap<&'static str, bool>,
139}
140
141impl ExtractedFields {
142 pub fn new() -> Self {
143 Self {
144 string_values: HashMap::new(),
145 u64_values: HashMap::new(),
146 i64_values: HashMap::new(),
147 bool_values: HashMap::new(),
148 }
149 }
150
151 pub fn is_empty(&self) -> bool {
152 self.string_values.is_empty()
153 && self.u64_values.is_empty()
154 && self.i64_values.is_empty()
155 && self.bool_values.is_empty()
156 }
157}
158
159pub(crate) struct FieldExtractor<'a> {
161 pub target_fields: &'a [&'static str],
163 pub extracted: ExtractedFields,
164}
165
166impl<'a> FieldExtractor<'a> {
167 pub fn new(target_fields: &'a [&'static str]) -> Self {
168 Self {
169 target_fields,
170 extracted: ExtractedFields::new(),
171 }
172 }
173
174 fn is_target(&self, field: &Field) -> Option<&'static str> {
175 self.target_fields.iter().find(|&&f| f == field.name()).copied()
176 }
177}
178
179impl<'a> Visit for FieldExtractor<'a> {
180 fn record_str(&mut self, field: &Field, value: &str) {
181 if let Some(key) = self.is_target(field) {
182 self.extracted.string_values.insert(key, value.to_string());
183 }
184 }
185
186 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
187 if let Some(key) = self.is_target(field) {
188 if !self.extracted.string_values.contains_key(key)
190 && !self.extracted.u64_values.contains_key(key)
191 && !self.extracted.i64_values.contains_key(key)
192 && !self.extracted.bool_values.contains_key(key)
193 {
194 self.extracted
195 .string_values
196 .insert(key, format!("{:?}", value));
197 }
198 }
199 }
200
201 fn record_u64(&mut self, field: &Field, value: u64) {
202 if let Some(key) = self.is_target(field) {
203 self.extracted.u64_values.insert(key, value);
204 }
205 }
206
207 fn record_i64(&mut self, field: &Field, value: i64) {
208 if let Some(key) = self.is_target(field) {
209 self.extracted.i64_values.insert(key, value);
210 }
211 }
212
213 fn record_bool(&mut self, field: &Field, value: bool) {
214 if let Some(key) = self.is_target(field) {
215 self.extracted.bool_values.insert(key, value);
216 }
217 }
218}