use std::collections::{HashMap, HashSet};
use std::fmt;
use tracing_core::field::{Field, Visit};
pub(crate) struct ExtractedFields {
pub string_values: HashMap<&'static str, String>,
pub u64_values: HashMap<&'static str, u64>,
pub i64_values: HashMap<&'static str, i64>,
pub bool_values: HashMap<&'static str, bool>,
pub user_set_fields: HashSet<&'static str>,
}
impl ExtractedFields {
pub fn new() -> Self {
Self {
string_values: HashMap::new(),
u64_values: HashMap::new(),
i64_values: HashMap::new(),
bool_values: HashMap::new(),
user_set_fields: HashSet::new(),
}
}
pub fn is_empty(&self) -> bool {
self.string_values.is_empty()
&& self.u64_values.is_empty()
&& self.i64_values.is_empty()
&& self.bool_values.is_empty()
}
pub fn mark_user_set(&mut self, field: &'static str) {
self.user_set_fields.insert(field);
}
}
pub(crate) struct FieldExtractor<'a> {
pub target_fields: &'a [&'static str],
pub extracted: ExtractedFields,
}
impl<'a> FieldExtractor<'a> {
pub fn new(target_fields: &'a [&'static str]) -> Self {
Self {
target_fields,
extracted: ExtractedFields::new(),
}
}
fn is_target(&self, field: &Field) -> Option<&'static str> {
self.target_fields
.iter()
.find(|&&f| f == field.name())
.copied()
}
}
impl<'a> Visit for FieldExtractor<'a> {
fn record_str(&mut self, field: &Field, value: &str) {
if let Some(key) = self.is_target(field) {
self.extracted.string_values.insert(key, value.to_string());
}
}
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
if let Some(key) = self.is_target(field) {
if !self.extracted.string_values.contains_key(key)
&& !self.extracted.u64_values.contains_key(key)
&& !self.extracted.i64_values.contains_key(key)
&& !self.extracted.bool_values.contains_key(key)
{
self.extracted
.string_values
.insert(key, format!("{:?}", value));
}
}
}
fn record_u64(&mut self, field: &Field, value: u64) {
if let Some(key) = self.is_target(field) {
self.extracted.u64_values.insert(key, value);
}
}
fn record_i64(&mut self, field: &Field, value: i64) {
if let Some(key) = self.is_target(field) {
self.extracted.i64_values.insert(key, value);
}
}
fn record_bool(&mut self, field: &Field, value: bool) {
if let Some(key) = self.is_target(field) {
self.extracted.bool_values.insert(key, value);
}
}
}