// ===========================
// File: src/logger.rs (NEW)
// ===========================
use serde_json::Value;
use std::fs::{create_dir_all, OpenOptions};
use std::io::Write;
use chrono::Utc;
/// Универсальный JSONL-логгер.
/// Пишет все события в папку сессии:
/// logs/<session>/monitor.jsonl
/// logs/<session>/live.jsonl
/// logs/<session>/system.jsonl
/// logs/<session>/actions.jsonl
pub struct Logger {
base_dir: String,
session_dir: String,
}
impl Logger {
pub fn new(base: &str, session_id: &str) -> std::io::Result<Self> {
let session_dir = format!("{}/{}", base, session_id);
create_dir_all(&session_dir)?;
Ok(Self {
base_dir: base.to_string(),
session_dir,
})
}
/// Пишем событие в файл `<type>.jsonl`
fn write_jsonl(
&mut self,
file: &str,
message: &str,
data: Option<&Value>,
) -> std::io::Result<()> {
let path = format!("{}/{}.jsonl", self.session_dir, file);
let mut f = OpenOptions::new()
.create(true)
.append(true)
.open(path)?;
let ts = Utc::now().timestamp();
let mut obj = serde_json::Map::new();
obj.insert("ts".into(), ts.into());
obj.insert("message".into(), message.into());
if let Some(v) = data {
obj.insert("data".into(), v.clone());
}
let json = serde_json::Value::Object(obj).to_string();
writeln!(f, "{}", json)?;
Ok(())
}
// ===========================
// Разделы логов
// ===========================
pub fn log_monitor(
&mut self,
message: &str,
data: Option<&Value>,
) -> std::io::Result<()> {
self.write_jsonl("monitor", message, data)
}
pub fn log_system(
&mut self,
level: &str,
module: &str,
message: &str,
) -> std::io::Result<()> {
let obj = serde_json::json!({ "level": level, "module": module });
self.write_jsonl("system", message, Some(&obj))
}
pub fn log_live(
&mut self,
message: &str,
data: Option<&Value>,
) -> std::io::Result<()> {
self.write_jsonl("live", message, data)
}
pub fn log_action(
&mut self,
action: &str,
price: f64,
qty: f64,
reason: &str,
) -> std::io::Result<()> {
let val = serde_json::json!({
"action": action,
"price": price,
"qty": qty,
"reason": reason
});
self.write_jsonl("actions", "ACTION", Some(&val))
}
}