use crate::{
model::LogEvent,
subscriber::{processor::EventProcessor, visitor::LogEventFieldVisitor},
};
use std::sync::Arc;
use tracing::{Event, Subscriber};
use tracing_subscriber::{
layer::{Context, Layer},
registry::LookupSpan,
};
#[derive(Clone)]
pub struct DispatchLayer {
processor: Arc<EventProcessor>,
}
impl DispatchLayer {
pub(crate) fn new(processor: Arc<EventProcessor>) -> Self {
Self { processor }
}
fn build_log_event<S>(&self, event: &Event<'_>, ctx: Context<'_, S>) -> LogEvent
where
S: Subscriber + for<'span> LookupSpan<'span>,
{
let metadata = event.metadata();
let mut log_event = LogEvent::new(
*metadata.level(),
metadata.target().to_string(),
metadata.name().to_string(),
None,
);
let mut visitor = LogEventFieldVisitor::new(&mut log_event);
event.record(&mut visitor);
if let Some(span_ref) = ctx.lookup_current() {
log_event.span_id = Some(format!("{:?}", span_ref.id()));
if let Some(parent_ref) = span_ref.parent() {
log_event.parent_id = Some(format!("{:?}", parent_ref.id()));
}
}
THREAD_INFO.with(|(id, name)| {
log_event.thread_id = Some(id.clone());
log_event.thread_name = name.clone();
});
log_event
}
}
thread_local! {
static THREAD_INFO: (String, Option<String>) = {
let current_thread = std::thread::current();
let debug_id = format!("{:?}", current_thread.id());
let id = debug_id
.strip_prefix("ThreadId(")
.and_then(|s| s.strip_suffix(')'))
.unwrap_or(&debug_id) .to_string();
(id, current_thread.name().map(str::to_string))
};
}
impl<S> Layer<S> for DispatchLayer
where
S: Subscriber + for<'span> LookupSpan<'span>,
{
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
let log_event = self.build_log_event(event, ctx);
self
.processor
.process_event(log_event, event.metadata());
}
fn enabled(&self, metadata: &tracing::Metadata<'_>, _ctx: Context<'_, S>) -> bool {
if !metadata.is_event() {
return true;
}
self.processor.event_enabled(metadata)
}
fn max_level_hint(&self) -> Option<tracing_core::metadata::LevelFilter> {
Some(self.processor.max_level())
}
}