#[cfg(feature = "ahash")]
use ahash::AHashMap as HashMap;
use jiff::Timestamp;
use serde::{Serialize, Serializer, ser::SerializeMap};
#[cfg(not(feature = "ahash"))]
use std::collections::HashMap;
use std::{borrow::Cow, fmt::Debug};
use tracing_core::{Field, Level, field::Visit};
pub(crate) struct Log {
pub timestamp: Timestamp,
pub level: Level,
pub message: String,
pub trace_context: Option<(u128, u64)>,
pub fields: HashMap<Cow<'static, str>, String>,
}
impl Serialize for Log {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("timestamp", &self.timestamp)?;
map.serialize_entry("level", &self.level.as_str())?;
map.serialize_entry("message", &self.message)?;
if let Some((trace_id, span_id)) = &self.trace_context {
map.serialize_entry("dd.trace_id", &trace_id)?;
map.serialize_entry("dd.span_id", &span_id)?;
}
for (key, value) in &self.fields {
map.serialize_entry(&format!("fields.{key}"), value)?;
}
map.end()
}
}
#[derive(Default)]
pub(crate) struct FieldVisitor {
fields: HashMap<Cow<'static, str>, String>,
}
impl FieldVisitor {
pub(crate) fn finish(self) -> HashMap<Cow<'static, str>, String> {
self.fields
}
}
impl Visit for FieldVisitor {
fn record_str(&mut self, field: &Field, value: &str) {
self.fields.insert(field.name().into(), value.to_string());
}
fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
self.fields
.insert(field.name().into(), format!("{value:?}"));
}
}