use crate::config::Configurable;
use schemars::JsonSchema;
use serde::Deserialize;
use std::fmt::Display;
impl Configurable for LoggerConfig {
fn config_prefix() -> &'static str {
"logger"
}
}
crate::submit_inventory! {
crate::config::ConfigSchema {
prefix: "logger",
schema: || crate::config::schema_for!(LoggerConfig),
}
}
#[derive(Debug, Clone, JsonSchema, Deserialize)]
pub(crate) struct LoggerConfig {
#[serde(default = "default_true")]
pub enable: bool,
#[serde(default)]
pub pretty_backtrace: bool,
#[serde(default)]
pub level: LogLevel,
#[serde(default)]
pub format: Format,
#[serde(default)]
pub time_style: TimeStyle,
#[serde(default)]
pub time_pattern: ChronoTimePattern,
#[serde(default)]
pub with_fields: Vec<WithFields>,
pub override_filter: Option<String>,
#[serde(rename = "file")]
pub file_appender: Option<LoggerFileAppender>,
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
pub(crate) enum LogLevel {
#[serde(rename = "off")]
Off,
#[serde(rename = "trace")]
Trace,
#[serde(rename = "debug")]
Debug,
#[serde(rename = "info")]
#[default]
Info,
#[serde(rename = "warn")]
Warn,
#[serde(rename = "error")]
Error,
}
impl Display for LogLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Off => "off",
Self::Trace => "trace",
Self::Debug => "debug",
Self::Info => "info",
Self::Warn => "warn",
Self::Error => "error",
}
)
}
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
pub(crate) enum Format {
#[serde(rename = "compact")]
#[default]
Compact,
#[serde(rename = "pretty")]
Pretty,
#[serde(rename = "json")]
Json,
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
pub(crate) enum TimeStyle {
#[serde(rename = "system")]
SystemTime,
#[serde(rename = "uptime")]
Uptime,
#[default]
#[serde(rename = "local")]
ChronoLocal,
#[serde(rename = "utc")]
ChronoUtc,
#[serde(rename = "none")]
None,
}
#[derive(Debug, Clone, JsonSchema, Deserialize)]
#[serde(transparent)]
pub(crate) struct ChronoTimePattern(String);
impl Default for ChronoTimePattern {
fn default() -> Self {
Self("%Y-%m-%dT%H:%M:%S".to_string())
}
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for ChronoTimePattern {
fn to_string(&self) -> String {
self.0.to_string()
}
}
#[derive(Debug, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum WithFields {
File,
LineNumber,
ThreadId,
ThreadName,
InternalErrors,
}
#[derive(Debug, Clone, JsonSchema, Deserialize)]
pub(crate) struct LoggerFileAppender {
pub enable: bool,
#[serde(default = "default_true")]
pub non_blocking: bool,
#[serde(default)]
pub format: Format,
#[serde(default)]
pub rotation: Rotation,
#[serde(default = "default_dir")]
pub dir: String,
#[serde(default = "default_prefix")]
pub filename_prefix: String,
#[serde(default = "default_suffix")]
pub filename_suffix: String,
#[serde(default = "default_max_log_files")]
pub max_log_files: usize,
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
pub(crate) enum Rotation {
#[serde(rename = "minutely")]
Minutely,
#[serde(rename = "hourly")]
Hourly,
#[serde(rename = "daily")]
#[default]
Daily,
#[serde(rename = "never")]
Never,
}
fn default_dir() -> String {
"./logs".to_string()
}
fn default_prefix() -> String {
"app".to_string()
}
fn default_suffix() -> String {
"log".to_string()
}
fn default_max_log_files() -> usize {
365
}
fn default_true() -> bool {
true
}
#[allow(clippy::from_over_into)]
impl Into<tracing_appender::rolling::Rotation> for Rotation {
fn into(self) -> tracing_appender::rolling::Rotation {
match self {
Self::Minutely => tracing_appender::rolling::Rotation::MINUTELY,
Self::Hourly => tracing_appender::rolling::Rotation::HOURLY,
Self::Daily => tracing_appender::rolling::Rotation::DAILY,
Self::Never => tracing_appender::rolling::Rotation::NEVER,
}
}
}