use std::io::Write;
use std::sync::Mutex;
use tracing::{Event, Subscriber};
use tracing_subscriber::field::Visit;
use tracing_subscriber::layer::Context;
use tracing_subscriber::Layer;
pub struct TelemetryLayer<W: Write + Send + 'static> {
writer: Mutex<W>,
}
impl<W: Write + Send + 'static> TelemetryLayer<W> {
pub fn new(writer: W) -> Self {
Self {
writer: Mutex::new(writer),
}
}
}
struct MessageVisitor {
message: Option<String>,
}
impl Visit for MessageVisitor {
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
if field.name() == "message" {
let debug = format!("{value:?}");
self.message = serde_json::from_str::<String>(&debug).ok();
}
}
}
impl<S, W> Layer<S> for TelemetryLayer<W>
where
S: Subscriber,
W: Write + Send + 'static,
{
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
if event.metadata().target() != "claw10_telemetry" {
return;
}
let mut visitor = MessageVisitor { message: None };
event.record(&mut visitor);
if let Some(msg) = visitor.message {
if let Ok(mut writer) = self.writer.lock() {
let _ = writeln!(writer, "{msg}");
}
}
}
}