use crate::logging::ledger::seal_unsealed_logs;
use crate::logging::logger_trait::AuditLogger;
use crate::logging::schema::AuditLogEntry;
use chrono::Utc;
use serde_json;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::PathBuf;
pub struct JsonlLogger {
logs_dir: PathBuf,
}
impl JsonlLogger {
pub fn new(logs_dir: PathBuf) -> Self {
if !logs_dir.exists() {
fs::create_dir_all(&logs_dir).expect("cannot create logs directory");
}
Self { logs_dir }
}
pub fn default() -> Self {
Self::new(PathBuf::from("logs"))
}
fn today_log_path(&self) -> PathBuf {
let today = Utc::now().format("%Y-%m-%d").to_string();
let log_filename = format!("audit-{}.jsonl", today);
self.logs_dir.join(log_filename)
}
}
impl AuditLogger for JsonlLogger {
fn log_event(&self, entry: &AuditLogEntry) {
let log_path = self.today_log_path();
let json = serde_json::to_string(entry).expect("failed to serialize log entry");
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&log_path)
.expect("cannot open daily audit log file");
writeln!(file, "{}", json).expect("failed to write log entry");
let today = Utc::now().format("%Y-%m-%d").to_string();
seal_unsealed_logs(&self.logs_dir, &today);
}
fn log_and_print(&self, entry: &AuditLogEntry, console_msg: &str) {
self.log_event(entry);
println!("{}", console_msg);
}
}