From 7f4d965803a75c98400d298a127455a7fc528c39 Mon Sep 17 00:00:00 2001 From: LaoLittle Date: Sat, 14 Jan 2023 13:41:20 +0800 Subject: [PATCH] log config --- default_config/log.toml | 6 +++++ src/config/log.rs | 39 ++++++++++++++++++++++++++++ src/config/service.rs | 57 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/service/log.rs | 28 ++++++++++++++------ 5 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 default_config/log.toml create mode 100644 src/config/log.rs create mode 100644 src/config/service.rs diff --git a/default_config/log.toml b/default_config/log.toml new file mode 100644 index 0000000..3054e2f --- /dev/null +++ b/default_config/log.toml @@ -0,0 +1,6 @@ +# 日志输出最大等级 +# 等级由低至高分别为: Error, Warn, Info, Debug, Tracing +max_level = 'Info' +# 日志时间的输出格式 +# 详见'https://time-rs.github.io/book/api/format-description.html' +time_format = '[year]-[month]-[day] [hour]:[minute]:[second]' \ No newline at end of file diff --git a/src/config/log.rs b/src/config/log.rs new file mode 100644 index 0000000..c42ed95 --- /dev/null +++ b/src/config/log.rs @@ -0,0 +1,39 @@ +use serde::{Deserialize, Serialize}; + +pub static DEFAULT_CONFIG: &[u8] = include_bytes!("../../default_config/log.toml"); + +#[derive(Serialize, Deserialize, Debug)] +pub struct LogConfig { + pub max_level: Level, + pub time_format: String, +} + +impl Default for LogConfig { + fn default() -> Self { + Self { + max_level: Level::Info, + time_format: "[year]-[month]-[day] [hour]:[minute]:[second]".into(), + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum Level { + Trace, + Debug, + Info, + Warn, + Error, +} + +impl Level { + pub fn as_tracing_level(&self) -> tracing::Level { + match self { + Level::Trace => tracing::Level::TRACE, + Level::Debug => tracing::Level::DEBUG, + Level::Info => tracing::Level::INFO, + Level::Warn => tracing::Level::WARN, + Level::Error => tracing::Level::ERROR, + } + } +} diff --git a/src/config/service.rs b/src/config/service.rs new file mode 100644 index 0000000..4419f21 --- /dev/null +++ b/src/config/service.rs @@ -0,0 +1,57 @@ +use crate::config::service_config_dir_path; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::marker::PhantomData; +use std::path::PathBuf; +use tracing::error; + +pub struct ServiceConfig { + path: PathBuf, + service_name: &'static str, + default_config: &'static [u8], + _mark: PhantomData, +} + +impl ServiceConfig +where + for<'a> T: Serialize + Deserialize<'a>, + T: Default, +{ + pub fn new(name: &'static str, default: &'static [u8]) -> Self { + Self { + path: service_config_dir_path().join(format!("{name}.toml")), + default_config: default, + service_name: name, + _mark: PhantomData, + } + } + + pub fn read(&self) -> T { + if self.path.is_file() { + match fs::read(&self.path) { + Ok(file) => toml::from_slice(&file).unwrap_or_else(|e| { + error!("{e}"); + let mut path = self.path.clone(); + path.pop(); + let mut name = self.service_name.to_owned(); + name.push_str(".toml.bak"); + path.push(name); + let _ = fs::copy(&self.path, path); + self.write_default() + }), + Err(e) => { + error!("{e}"); + self.write_default() + } + } + } else { + self.write_default() + } + } + + fn write_default(&self) -> T { + let default = T::default(); + let _ = fs::write(&self.path, self.default_config); + default + } +} diff --git a/src/lib.rs b/src/lib.rs index a17b2a6..98563e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![feature(once_cell)] +#![feature(string_leak)] use dashmap::DashMap; use ricq::msg::elem::Text; diff --git a/src/service/log.rs b/src/service/log.rs index c0982d4..e538fad 100644 --- a/src/service/log.rs +++ b/src/service/log.rs @@ -1,3 +1,5 @@ +use crate::config::log::LogConfig; +use crate::config::service::ServiceConfig; use crate::terminal::buffer::{INPUT_BUFFER, TERMINAL_CLOSED}; use crate::terminal::PROMPT; use std::io; @@ -11,16 +13,23 @@ use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; pub fn init_logger() -> [WorkerGuard; 3] { + let config = ServiceConfig::::new("log", crate::config::log::DEFAULT_CONFIG).read(); + let local_offset = time::UtcOffset::current_local_offset(); - let time_format = - time::format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]").unwrap(); + let mut errors = Vec::with_capacity(2); + let time_format = time::format_description::parse(config.time_format.leak()) + .or_else(|e| { + errors.push(format!("日志时间格式错误: {e}, 将使用默认时间格式")); + time::format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]") + }) + .unwrap(); let (s, s_guard) = tracing_appender::non_blocking(LogStdoutWriter); let stdout_layer = tracing_subscriber::fmt::layer() .with_target(false) - .with_writer(s.with_max_level(Level::DEBUG)); + .with_writer(s.with_max_level(config.max_level.as_tracing_level())); let file_writer = tracing_appender::rolling::daily("log", "atri_bot.log"); let (f, f_guard) = tracing_appender::non_blocking(file_writer); @@ -38,9 +47,12 @@ pub fn init_logger() -> [WorkerGuard; 3] { .with_ansi(false) .with_writer(f_err.with_max_level(Level::ERROR)); - let (offset, err) = match local_offset { - Ok(ofs) => (ofs, None), - Err(e) => (time::UtcOffset::from_hms(8, 0, 0).unwrap(), Some(e)), + let offset = match local_offset { + Ok(ofs) => ofs, + Err(e) => { + errors.push(format!("初始化日志时间错误: {e}, 将使用默认时区UTC+8")); + time::UtcOffset::from_hms(8, 0, 0).unwrap() + } }; let timer = OffsetTime::new(offset, time_format); @@ -56,8 +68,8 @@ pub fn init_logger() -> [WorkerGuard; 3] { .with(file_error_layer) .init(); - if let Some(e) = err { - warn!("初始化日志时间错误: {}, 使用默认时区UTC+8", e); + for error in errors { + warn!("{error}"); } [s_guard, f_guard, f_err_guard]