Skip to main content

prover_logger/
log.rs

1use std::{fmt::Display, path::PathBuf};
2
3use serde::{Deserialize, Deserializer, Serialize};
4use tracing_subscriber::{fmt::writer::BoxMakeWriter, EnvFilter};
5
6use crate::LogFormat;
7
8/// The log configuration.
9#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
10#[serde(rename_all = "kebab-case")]
11pub struct Log {
12    /// The `RUST_LOG` environment variable will take precedence over the
13    /// configuration log level.
14    #[serde(default)]
15    pub level: LogLevel,
16    #[serde(default)]
17    pub outputs: Vec<LogOutput>,
18    #[serde(default)]
19    pub format: LogFormat,
20}
21
22/// The log level.
23#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
24#[serde(rename_all = "lowercase")]
25pub enum LogLevel {
26    Trace,
27    Debug,
28    #[default]
29    Info,
30    Warn,
31    Error,
32    Fatal,
33}
34
35impl Display for LogLevel {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        let level = match self {
38            LogLevel::Trace => "trace",
39            LogLevel::Debug => "debug",
40            LogLevel::Info => "info",
41            LogLevel::Warn => "warn",
42            LogLevel::Error => "error",
43            LogLevel::Fatal => "fatal",
44        };
45
46        write!(f, "{level}")
47    }
48}
49
50impl From<LogLevel> for EnvFilter {
51    fn from(value: LogLevel) -> Self {
52        EnvFilter::new(format!(
53            "warn,prover={value},aggkit={value},agglayer={value},pessimistic_proof={value}"
54        ))
55    }
56}
57
58/// The log output.
59///
60/// This can be either `stdout`, `stderr`, or a file path.
61///
62/// The [`Deserialize`] implementation allows for the configuration file to
63/// specify the output location as a string, which is then parsed into the
64/// appropriate enum variant. If the string is not recognized to be either
65/// `stdout` or `stderr`, it is assumed to be a file path.
66#[derive(Serialize, Debug, Clone, Default, PartialEq, Eq)]
67pub enum LogOutput {
68    #[default]
69    Stdout,
70    Stderr,
71    File(PathBuf),
72}
73
74impl<'de> Deserialize<'de> for LogOutput {
75    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76    where
77        D: Deserializer<'de>,
78    {
79        let s = String::deserialize(deserializer)?;
80        // If the string is not recognized to be either `stdout` or `stderr`,
81        // it is assumed to be a file path.
82        match s.as_str() {
83            "stdout" => Ok(LogOutput::Stdout),
84            "stderr" => Ok(LogOutput::Stderr),
85            _ => Ok(LogOutput::File(PathBuf::from(s))),
86        }
87    }
88}
89
90impl LogOutput {
91    /// Get a [`BoxMakeWriter`] for the log output.
92    ///
93    /// This can be used to plug the log output into the tracing subscriber.
94    pub fn as_make_writer(&self) -> BoxMakeWriter {
95        match self {
96            LogOutput::Stdout => BoxMakeWriter::new(std::io::stdout),
97            LogOutput::Stderr => BoxMakeWriter::new(std::io::stderr),
98            LogOutput::File(path) => {
99                let appender = tracing_appender::rolling::never(".", path);
100                BoxMakeWriter::new(appender)
101            }
102        }
103    }
104}