use std::{fmt::Display, path::PathBuf};
use serde::{Deserialize, Deserializer, Serialize};
use tracing_subscriber::{fmt::writer::BoxMakeWriter, EnvFilter};
use crate::LogFormat;
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub struct Log {
#[serde(default)]
pub level: LogLevel,
#[serde(default)]
pub outputs: Vec<LogOutput>,
#[serde(default)]
pub format: LogFormat,
}
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum LogLevel {
Trace,
Debug,
#[default]
Info,
Warn,
Error,
Fatal,
}
impl Display for LogLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let level = match self {
LogLevel::Trace => "trace",
LogLevel::Debug => "debug",
LogLevel::Info => "info",
LogLevel::Warn => "warn",
LogLevel::Error => "error",
LogLevel::Fatal => "fatal",
};
write!(f, "{level}")
}
}
impl From<LogLevel> for EnvFilter {
fn from(value: LogLevel) -> Self {
EnvFilter::new(format!(
"warn,prover={value},aggkit={value},agglayer={value},pessimistic_proof={value}"
))
}
}
#[derive(Serialize, Debug, Clone, Default, PartialEq, Eq)]
pub enum LogOutput {
#[default]
Stdout,
Stderr,
File(PathBuf),
}
impl<'de> Deserialize<'de> for LogOutput {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"stdout" => Ok(LogOutput::Stdout),
"stderr" => Ok(LogOutput::Stderr),
_ => Ok(LogOutput::File(PathBuf::from(s))),
}
}
}
impl LogOutput {
pub fn as_make_writer(&self) -> BoxMakeWriter {
match self {
LogOutput::Stdout => BoxMakeWriter::new(std::io::stdout),
LogOutput::Stderr => BoxMakeWriter::new(std::io::stderr),
LogOutput::File(path) => {
let appender = tracing_appender::rolling::never(".", path);
BoxMakeWriter::new(appender)
}
}
}
}