use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use tracing_log::LogTracer;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{fmt, EnvFilter};
lazy_static::lazy_static! {
static ref ERROR_BUFFER: Arc<Mutex<VecDeque<String>>> = Arc::new(Mutex::new(VecDeque::with_capacity(100)));
}
pub fn init_logging() -> Result<(), Box<dyn std::error::Error>> {
static INIT: std::sync::Once = std::sync::Once::new();
let mut result = Ok(());
INIT.call_once(|| {
if let Err(e) = LogTracer::init() {
eprintln!("Warning: Failed to initialize LogTracer: {}", e);
}
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
let error_capture_layer = ErrorCaptureLayer;
let subscriber = tracing_subscriber::registry()
.with(filter)
.with(fmt::layer().with_target(false))
.with(error_capture_layer);
if let Err(e) = tracing::subscriber::set_global_default(subscriber) {
result = Err(Box::new(e) as Box<dyn std::error::Error>);
}
});
result
}
pub fn get_error_buffer() -> Vec<String> {
ERROR_BUFFER.lock().unwrap().iter().cloned().collect()
}
pub fn clear_error_buffer() {
ERROR_BUFFER.lock().unwrap().clear();
}
struct ErrorCaptureLayer;
impl<S> tracing_subscriber::Layer<S> for ErrorCaptureLayer
where
S: tracing::Subscriber,
{
fn on_event(
&self,
event: &tracing::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) {
if event.metadata().level() == &tracing::Level::ERROR {
let mut visitor = ErrorVisitor::default();
event.record(&mut visitor);
if let Some(message) = visitor.message {
let mut buffer = ERROR_BUFFER.lock().unwrap();
if buffer.len() >= 100 {
buffer.pop_front();
}
let timestamp = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%.3f");
buffer.push_back(format!("[{}] {}", timestamp, message));
}
}
}
}
#[derive(Default)]
struct ErrorVisitor {
message: Option<String>,
}
impl tracing::field::Visit for ErrorVisitor {
fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
if field.name() == "message" {
self.message = Some(value.to_string());
}
}
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
if field.name() == "message" {
self.message = Some(format!("{:?}", value));
}
}
}