refactor: remove loco-rs deps
This commit is contained in:
38
apps/recorder/src/logger/config.rs
Normal file
38
apps/recorder/src/logger/config.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
LogRotation,
|
||||
core::{LogFormat, LogLevel},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||
pub struct LoggerConfig {
|
||||
pub enable: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub pretty_backtrace: bool,
|
||||
|
||||
pub level: LogLevel,
|
||||
|
||||
pub format: LogFormat,
|
||||
|
||||
pub filter: Option<String>,
|
||||
|
||||
pub override_filter: Option<String>,
|
||||
|
||||
pub file_appender: Option<LoggerFileAppender>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||
pub struct LoggerFileAppender {
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub non_blocking: bool,
|
||||
pub level: LogLevel,
|
||||
pub format: LogFormat,
|
||||
pub rotation: LogRotation,
|
||||
pub dir: Option<String>,
|
||||
pub filename_prefix: Option<String>,
|
||||
pub filename_suffix: Option<String>,
|
||||
pub max_log_files: usize,
|
||||
}
|
||||
49
apps/recorder/src/logger/core.rs
Normal file
49
apps/recorder/src/logger/core.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_variant::to_variant_name;
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
pub 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 std::fmt::Display for LogLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
to_variant_name(self).expect("only enum supported").fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
pub enum LogFormat {
|
||||
#[serde(rename = "compact")]
|
||||
#[default]
|
||||
Compact,
|
||||
#[serde(rename = "pretty")]
|
||||
Pretty,
|
||||
#[serde(rename = "json")]
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
pub enum LogRotation {
|
||||
#[serde(rename = "minutely")]
|
||||
Minutely,
|
||||
#[serde(rename = "hourly")]
|
||||
#[default]
|
||||
Hourly,
|
||||
#[serde(rename = "daily")]
|
||||
Daily,
|
||||
#[serde(rename = "never")]
|
||||
Never,
|
||||
}
|
||||
8
apps/recorder/src/logger/mod.rs
Normal file
8
apps/recorder/src/logger/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod config;
|
||||
pub mod core;
|
||||
pub mod service;
|
||||
|
||||
pub use core::{LogFormat, LogLevel, LogRotation};
|
||||
|
||||
pub use config::{LoggerConfig, LoggerFileAppender};
|
||||
pub use service::LoggerService;
|
||||
162
apps/recorder/src/logger/service.rs
Normal file
162
apps/recorder/src/logger/service.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{
|
||||
EnvFilter, Layer, Registry,
|
||||
fmt::{self, MakeWriter},
|
||||
layer::SubscriberExt,
|
||||
util::SubscriberInitExt,
|
||||
};
|
||||
|
||||
use super::{LogFormat, LogLevel, LogRotation, LoggerConfig};
|
||||
use crate::errors::{RError, RResult};
|
||||
|
||||
// Function to initialize the logger based on the provided configuration
|
||||
const MODULE_WHITELIST: &[&str] = &["sea_orm_migration", "tower_http", "sqlx::query", "sidekiq"];
|
||||
|
||||
// Keep nonblocking file appender work guard
|
||||
static NONBLOCKING_WORK_GUARD_KEEP: OnceLock<WorkerGuard> = OnceLock::new();
|
||||
|
||||
pub struct LoggerService {}
|
||||
|
||||
impl LoggerService {
|
||||
pub fn init_layer<W2>(
|
||||
make_writer: W2,
|
||||
format: &LogFormat,
|
||||
ansi: bool,
|
||||
) -> Box<dyn Layer<Registry> + Sync + Send>
|
||||
where
|
||||
W2: for<'writer> MakeWriter<'writer> + Sync + Send + 'static,
|
||||
{
|
||||
match format {
|
||||
LogFormat::Compact => fmt::Layer::default()
|
||||
.with_ansi(ansi)
|
||||
.with_writer(make_writer)
|
||||
.compact()
|
||||
.boxed(),
|
||||
LogFormat::Pretty => fmt::Layer::default()
|
||||
.with_ansi(ansi)
|
||||
.with_writer(make_writer)
|
||||
.pretty()
|
||||
.boxed(),
|
||||
LogFormat::Json => fmt::Layer::default()
|
||||
.with_ansi(ansi)
|
||||
.with_writer(make_writer)
|
||||
.json()
|
||||
.boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_env_filter(override_filter: Option<&String>, level: &LogLevel) -> EnvFilter {
|
||||
EnvFilter::try_from_default_env()
|
||||
.or_else(|_| {
|
||||
// user wanted a specific filter, don't care about our internal whitelist
|
||||
// or, if no override give them the default whitelisted filter (most common)
|
||||
override_filter.map_or_else(
|
||||
|| {
|
||||
EnvFilter::try_new(
|
||||
MODULE_WHITELIST
|
||||
.iter()
|
||||
.map(|m| format!("{m}={level}"))
|
||||
.chain(std::iter::once(format!(
|
||||
"{}={}",
|
||||
env!("CARGO_CRATE_NAME"),
|
||||
level
|
||||
)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
)
|
||||
},
|
||||
EnvFilter::try_new,
|
||||
)
|
||||
})
|
||||
.expect("logger initialization failed")
|
||||
}
|
||||
|
||||
pub async fn from_config(config: LoggerConfig) -> RResult<Self> {
|
||||
let mut layers: Vec<Box<dyn Layer<Registry> + Sync + Send>> = Vec::new();
|
||||
|
||||
if let Some(file_appender_config) = config.file_appender.as_ref() {
|
||||
if file_appender_config.enable {
|
||||
let dir = file_appender_config
|
||||
.dir
|
||||
.as_ref()
|
||||
.map_or_else(|| "./logs".to_string(), ToString::to_string);
|
||||
|
||||
let mut rolling_builder = tracing_appender::rolling::Builder::default()
|
||||
.max_log_files(file_appender_config.max_log_files);
|
||||
|
||||
rolling_builder = match file_appender_config.rotation {
|
||||
LogRotation::Minutely => {
|
||||
rolling_builder.rotation(tracing_appender::rolling::Rotation::MINUTELY)
|
||||
}
|
||||
LogRotation::Hourly => {
|
||||
rolling_builder.rotation(tracing_appender::rolling::Rotation::HOURLY)
|
||||
}
|
||||
LogRotation::Daily => {
|
||||
rolling_builder.rotation(tracing_appender::rolling::Rotation::DAILY)
|
||||
}
|
||||
LogRotation::Never => {
|
||||
rolling_builder.rotation(tracing_appender::rolling::Rotation::NEVER)
|
||||
}
|
||||
};
|
||||
|
||||
let file_appender = rolling_builder
|
||||
.filename_prefix(
|
||||
file_appender_config
|
||||
.filename_prefix
|
||||
.as_ref()
|
||||
.map_or_else(String::new, ToString::to_string),
|
||||
)
|
||||
.filename_suffix(
|
||||
file_appender_config
|
||||
.filename_suffix
|
||||
.as_ref()
|
||||
.map_or_else(String::new, ToString::to_string),
|
||||
)
|
||||
.build(dir)?;
|
||||
|
||||
let file_appender_layer = if file_appender_config.non_blocking {
|
||||
let (non_blocking_file_appender, work_guard) =
|
||||
tracing_appender::non_blocking(file_appender);
|
||||
NONBLOCKING_WORK_GUARD_KEEP
|
||||
.set(work_guard)
|
||||
.map_err(|_| RError::CustomMessageStr("cannot lock for appender"))?;
|
||||
Self::init_layer(
|
||||
non_blocking_file_appender,
|
||||
&file_appender_config.format,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
Self::init_layer(file_appender, &file_appender_config.format, false)
|
||||
};
|
||||
layers.push(file_appender_layer);
|
||||
}
|
||||
}
|
||||
|
||||
if config.enable {
|
||||
let stdout_layer = Self::init_layer(std::io::stdout, &config.format, true);
|
||||
layers.push(stdout_layer);
|
||||
}
|
||||
|
||||
if !layers.is_empty() {
|
||||
let env_filter = Self::init_env_filter(config.override_filter.as_ref(), &config.level);
|
||||
tracing_subscriber::registry()
|
||||
.with(layers)
|
||||
.with(env_filter)
|
||||
.init();
|
||||
}
|
||||
|
||||
if config.pretty_backtrace {
|
||||
unsafe {
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
}
|
||||
tracing::warn!(
|
||||
"pretty backtraces are enabled (this is great for development but has a runtime \
|
||||
cost for production. disable with `logger.pretty_backtrace` in your config yaml)"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user