use std::sync::{Arc, Mutex};
use tracing::field::{Field, Visit};
use tracing::{Event, Level, Subscriber};
use tracing_subscriber::layer::Context;
use tracing_subscriber::Layer;
use crate::client::Client;
use crate::logs::{AttrValue, LogLevel, LogRecord};
#[derive(Debug, Clone)]
pub struct TermwrightLayer {
client: Arc<Mutex<Client>>,
}
impl TermwrightLayer {
pub fn new(client: Arc<Mutex<Client>>) -> Self {
Self { client }
}
}
pub fn level_for(level: &Level) -> LogLevel {
match *level {
Level::TRACE => LogLevel::Trace,
Level::DEBUG => LogLevel::Debug,
Level::INFO => LogLevel::Info,
Level::WARN => LogLevel::Warn,
Level::ERROR => LogLevel::Error,
}
}
#[derive(Default)]
struct RecordVisitor {
message: String,
attrs: Vec<(String, AttrValue)>,
}
impl Visit for RecordVisitor {
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == "message" {
self.message = value.to_owned();
} else {
self.attrs
.push((field.name().to_owned(), AttrValue::Text(value.to_owned())));
}
}
fn record_bool(&mut self, field: &Field, value: bool) {
self.attrs
.push((field.name().to_owned(), AttrValue::Bool(value)));
}
fn record_i64(&mut self, field: &Field, value: i64) {
self.attrs
.push((field.name().to_owned(), AttrValue::Int(value)));
}
fn record_u64(&mut self, field: &Field, value: u64) {
self.attrs
.push((field.name().to_owned(), AttrValue::from(value)));
}
fn record_f64(&mut self, field: &Field, value: f64) {
self.attrs
.push((field.name().to_owned(), AttrValue::from(value)));
}
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
self.attrs
.push((field.name().to_owned(), AttrValue::Text(value.to_string())));
}
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
let rendered = format!("{value:?}");
if field.name() == "message" {
self.message = rendered;
} else {
self.attrs
.push((field.name().to_owned(), AttrValue::Text(rendered)));
}
}
}
impl<S: Subscriber> Layer<S> for TermwrightLayer {
fn on_event(&self, event: &Event<'_>, _context: Context<'_, S>) {
let mut visitor = RecordVisitor::default();
event.record(&mut visitor);
let metadata = event.metadata();
let mut record = LogRecord::new(level_for(metadata.level()), visitor.message)
.with_logger(metadata.target());
for (key, value) in visitor.attrs {
record.attrs.insert(key, value);
}
if let Ok(mut client) = self.client.lock() {
client.log(record);
}
}
}