use commonware_utils::sync::Mutex;
use std::sync::Arc;
use tracing_subscriber::fmt::MakeWriter;
pub struct Writer {
logs: Arc<Mutex<Vec<String>>>,
}
impl Writer {
pub const fn new(logs: Arc<Mutex<Vec<String>>>) -> Self {
Self { logs }
}
fn add_to_log_message(key: &str, value: &serde_json::Value, log_message: &mut String) {
if let serde_json::Value::Object(map) = value {
for (key, value) in map {
Self::add_to_log_message(key, value, log_message);
}
} else if !key.is_empty()
&& key != "level"
&& key != "timestamp"
&& key != "target"
&& key != "message"
{
log_message.push_str(&format!("{key}={value} "));
}
}
}
impl std::io::Write for Writer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let json_str = String::from_utf8_lossy(buf);
let json: serde_json::Value = serde_json::from_str(&json_str).unwrap();
let level = json["level"].as_str().unwrap();
let timestamp = json["timestamp"].as_str().unwrap();
let target = json["target"].as_str().unwrap();
let msg = json["fields"]["message"].as_str().unwrap();
let mut log_message = format!(
"[{}|{}] {} => {} (",
chrono::NaiveDateTime::parse_from_str(timestamp, "%Y-%m-%dT%H:%M:%S%.6fZ")
.unwrap()
.format("%m/%d %H:%M:%S"),
level,
target,
msg,
);
Self::add_to_log_message("", &json, &mut log_message);
let log_message = format!("{})", log_message.trim_end());
let log_message = log_message.replace("()", "");
let mut logs = self.logs.lock();
logs.push(log_message.trim_end().to_string());
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<'a> MakeWriter<'a> for Writer {
type Writer = Self;
fn make_writer(&'a self) -> Self::Writer {
Self {
logs: Arc::clone(&self.logs),
}
}
}