| { | ||
| "git": { | ||
| "sha1": "2e8e8d58814ebd01371138475a9da123ef21fcd7" | ||
| "sha1": "ebd7cd3938bafd14ea194ecdf881e474f5d5e4b0" | ||
| }, | ||
| "path_in_vcs": "" | ||
| } |
+1
-1
@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "doe" | ||
| version = "1.1.76" | ||
| version = "1.1.77" | ||
| authors = ["Andrew <dnrops@outlook.com>"] | ||
@@ -18,0 +18,0 @@ build = false |
+0
-0
@@ -0,0 +0,0 @@ doe v1.1.66 (/mnt/e/CODE/gitlab_code/doe_gitlink) |
+457
-123
| /// logger mod | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ## Basic usage | ||
| /// ```ignore | ||
| /// fn main() { | ||
| /// use doe::logger::*; | ||
| /// doe::logger::init(); | ||
| /// debug!("hello world"); | ||
| /// info!("hello world"); | ||
| /// warn!("hello world"); | ||
| /// } | ||
| /// use doe::logger::*; | ||
| /// doe::logger::init(); | ||
| /// debug!("hello world"); | ||
| /// info!("hello world"); | ||
| /// warn!("hello world"); | ||
| /// ``` | ||
| /// | ||
| /// | ||
| /// ## Using builder pattern (fluent interface) | ||
| /// ```ignore | ||
| /// use doe::logger::*; | ||
| /// | ||
| /// // Custom configuration with fluent interface | ||
| /// LoggerBuilder::init() | ||
| /// .with("debug") | ||
| /// .log_dir("logs") | ||
| /// .filename_prefix("myapp") | ||
| /// .filename_suffix("log") | ||
| /// .file_appender_rotation(doe::logger::tracing_appender::rolling::Rotation::DAILY) | ||
| /// .with_console(true) | ||
| /// .with_file(true) | ||
| /// .retention_days(30) | ||
| /// .build(); | ||
| /// | ||
| /// info!("Logger initialized with custom configuration"); | ||
| /// ``` | ||
| /// | ||
| /// ## Console only | ||
| /// ```ignore | ||
| /// use doe::logger::*; | ||
| /// | ||
| /// LoggerBuilder::init() | ||
| /// .with("info") | ||
| /// .with_console(true) | ||
| /// .with_file(false) | ||
| /// .build(); | ||
| /// | ||
| /// info!("Only console logging enabled"); | ||
| /// ``` | ||
| /// | ||
| /// ## File only | ||
| /// ```ignore | ||
| /// use doe::logger::*; | ||
| /// | ||
| /// LoggerBuilder::init() | ||
| /// .with("debug") | ||
| /// .log_dir("logs") | ||
| /// .with_console(false) | ||
| /// .with_file(true) | ||
| /// .build(); | ||
| /// | ||
| /// info!("Only file logging enabled"); | ||
| /// ``` | ||
| #[allow(warnings)] | ||
| #[cfg(feature = "logger")] | ||
| pub mod logger { | ||
| use chrono::{Local, NaiveDate, TimeDelta, TimeZone}; | ||
| use std::fs; | ||
| use std::path::{Path, PathBuf}; | ||
| use time::{format_description::parse, UtcOffset}; | ||
| use tracing_appender::{non_blocking, rolling}; | ||
| use tracing_error::ErrorLayer; | ||
| use tracing_subscriber::{ | ||
| filter::EnvFilter, | ||
| fmt, | ||
| fmt::time::OffsetTime, | ||
| layer::SubscriberExt, | ||
| registry::Registry, | ||
| util::SubscriberInitExt, | ||
| }; | ||
| // 重新导出tracing的宏,保持原有使用方式 | ||
| pub use tracing::*; | ||
| pub use tracing_appender::*; | ||
| pub use tracing_appender; | ||
| pub use tracing_subscriber::*; | ||
| pub use tracing_subscriber; | ||
| pub use tracing_error::*; | ||
| pub use tracing_error; | ||
| /// 默认日志保留天数 | ||
| const DEFAULT_LOG_RETENTION_DAYS: u64 = 14; | ||
| /// 初始化debug级别的日志系统 | ||
| /// 自动清理超过14天的旧日志文件 | ||
| pub fn init_debug() { | ||
| // 导入tracing_subscriber库中的模块,用于日志过滤和格式化 | ||
| use tracing_subscriber::{filter::EnvFilter, fmt, layer::SubscriberExt, Registry}; | ||
| // 清理旧日志文件 | ||
| if let Err(e) = clean_old_logs("log", "app", "log", rolling::Rotation::DAILY, DEFAULT_LOG_RETENTION_DAYS) { | ||
| eprintln!("Warning: Failed to clean old logs: {}", e); | ||
| } | ||
| // 尝试从环境变量中解析日志级别过滤器,如果失败则默认为"info"级别 | ||
| let env_filter = | ||
| EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("debug")); | ||
| use chrono::Local; | ||
| use time::UtcOffset; | ||
| use tracing_subscriber::fmt::time::OffsetTime; | ||
| let offset = UtcOffset::current_local_offset().expect("should get local offset!"); | ||
| let time_format = | ||
| time::format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]") | ||
| .expect("format string should be valid!"); | ||
| let timer = OffsetTime::new(offset, time_format); | ||
| // 创建一个格式化日志层,使用本地时间格式化日志,并将日志输出到标准错误流 | ||
| // 初始化日志配置 | ||
| let env_filter = EnvFilter::try_from_default_env() | ||
| .unwrap_or_else(|_| EnvFilter::new("debug")); | ||
| let timer = create_local_timer(); | ||
| // 控制台日志层 | ||
| let formatting_layer = fmt::layer() | ||
@@ -38,16 +109,10 @@ .with_timer(timer.clone()) | ||
| // 导入滚动日志文件追加器,用于创建日志文件 | ||
| use tracing_appender::rolling::{RollingFileAppender, Rotation}; | ||
| // 创建一个滚动日志文件追加器,日志文件名基于日期旋转,但在这里设置为从不旋转 | ||
| let file_appender = RollingFileAppender::builder() | ||
| .rotation(Rotation::DAILY) | ||
| // 文件日志层 | ||
| let file_appender = rolling::RollingFileAppender::builder() | ||
| .rotation(rolling::Rotation::DAILY) | ||
| .filename_prefix("app") | ||
| .filename_suffix("log") | ||
| .build("log") | ||
| .expect("initializing rolling file appender failed"); | ||
| let stdout = std::io::stdout.with_max_level(tracing::Level::INFO); | ||
| // 创建一个文件日志层,禁用ANSI颜色,并使用非阻塞模式写入日志文件 | ||
| .expect("Failed to create rolling file appender"); | ||
| let file_layer = fmt::layer() | ||
@@ -58,39 +123,35 @@ .with_ansi(false) | ||
| // 将默认的Registry与环境变量过滤器、格式化日志层和文件日志层组合,并初始化 | ||
| let registy = Registry::default() | ||
| // 组合并初始化日志系统 | ||
| if let Err(e) = Registry::default() | ||
| .with(env_filter) | ||
| .with(formatting_layer) | ||
| .with(file_layer); | ||
| registy.max_level_hint(); | ||
| let _ = tracing::subscriber::set_global_default(registy); | ||
| .with(file_layer) | ||
| .try_init() | ||
| { | ||
| eprintln!("Failed to initialize debug logger: {}", e); | ||
| } | ||
| } | ||
| /// 初始化info级别的日志系统 | ||
| /// 自动清理超过14天的旧日志文件 | ||
| pub fn init_info() { | ||
| // 清理旧日志文件 | ||
| if let Err(e) = clean_old_logs("log", "app", "log", rolling::Rotation::DAILY, DEFAULT_LOG_RETENTION_DAYS) { | ||
| eprintln!("Warning: Failed to clean old logs: {}", e); | ||
| } | ||
| pub fn init_info() { | ||
| use tracing_subscriber::{filter::EnvFilter, fmt, layer::SubscriberExt, Registry}; | ||
| use chrono::Local; | ||
| use time::UtcOffset; | ||
| use tracing_subscriber::fmt::time::OffsetTime; | ||
| // 从环境变量中解析日志级别过滤器,默认为 "info" | ||
| let env_filter = | ||
| EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); | ||
| // 设置本地时间格式 | ||
| let offset = UtcOffset::current_local_offset().expect("should get local offset!"); | ||
| let time_format = | ||
| time::format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]") | ||
| .expect("format string should be valid!"); | ||
| let timer = OffsetTime::new(offset, time_format); | ||
| // 创建一个滚动日志文件追加器 | ||
| use tracing_appender::rolling::{RollingFileAppender, Rotation}; | ||
| let file_appender = RollingFileAppender::builder() | ||
| .rotation(Rotation::DAILY) | ||
| // 初始化日志配置 | ||
| let env_filter = EnvFilter::try_from_default_env() | ||
| .unwrap_or_else(|_| EnvFilter::new("info")); | ||
| let timer = create_local_timer(); | ||
| // 文件日志层 | ||
| let file_appender = rolling::RollingFileAppender::builder() | ||
| .rotation(rolling::Rotation::DAILY) | ||
| .filename_prefix("app") | ||
| .filename_suffix("log") | ||
| .build("log") | ||
| .expect("initializing rolling file appender failed"); | ||
| // 创建一个文件日志层,禁用ANSI颜色,并使用非阻塞模式写入日志文件 | ||
| .expect("Failed to create rolling file appender"); | ||
| let file_layer = fmt::layer() | ||
@@ -100,80 +161,353 @@ .with_ansi(false) | ||
| .with_writer(file_appender); | ||
| // 控制台日志层 | ||
| let formatting_layer = fmt::layer() | ||
| .with_timer(timer.clone()) | ||
| .pretty() | ||
| .with_writer(std::io::stdout); | ||
| .with_timer(timer) | ||
| .pretty() | ||
| .with_writer(std::io::stdout); | ||
| // 将默认的Registry与环境变量过滤器、控制台日志层和文件日志层组合,并初始化 | ||
| // 将默认的Registry与环境变量过滤器、格式化日志层和文件日志层组合,并初始化 | ||
| let registy = Registry::default() | ||
| // 组合并初始化日志系统 | ||
| if let Err(e) = Registry::default() | ||
| .with(env_filter) | ||
| .with(formatting_layer) | ||
| .with(file_layer); | ||
| registy.max_level_hint(); | ||
| let _ = tracing::subscriber::set_global_default(registy); | ||
| .with(file_layer) | ||
| .try_init() | ||
| { | ||
| eprintln!("Failed to initialize info logger: {}", e); | ||
| } | ||
| } | ||
| use tracing_appender::{non_blocking, rolling}; | ||
| use tracing_error::ErrorLayer; | ||
| use tracing_subscriber::fmt::writer::MakeWriterExt; | ||
| use tracing_subscriber::{ | ||
| filter::EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt, Registry, | ||
| }; | ||
| /// Initializes the logger with the given configuration. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `log_level` - The log level to use. Defaults to "info" if not provided. | ||
| /// * `log_file_path` - The path to the log file. If `None`, logs will only go to stdout. | ||
| /// * `pretty_print` - Whether to use pretty printing for logs. Defaults to `false`. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// ```rust | ||
| /// logger::init_with_option(Some("debug"), Some("logs/app.log")); | ||
| /// ``` | ||
| pub fn init_with_option(log_level: Option<&str>, log_file_path: Option<&str>) { | ||
| let env_filter = EnvFilter::try_from_default_env() | ||
| .unwrap_or_else(|_| EnvFilter::new(log_level.unwrap_or("info"))); | ||
| /// Logger 构建器,提供 fluent interface | ||
| pub struct LoggerBuilder { | ||
| log_level: String, | ||
| log_dir: String, | ||
| filename_prefix: String, | ||
| filename_suffix: String, | ||
| rotation: Option<rolling::Rotation>, | ||
| console_enabled: bool, | ||
| file_enabled: bool, | ||
| retention_days: u64, | ||
| } | ||
| // Create a formatting layer for stderr | ||
| let formatting_layer = fmt::layer() | ||
| .with_timer(tracing_subscriber::fmt::time::time()) | ||
| .with_level(true) | ||
| .with_file(true) | ||
| .with_writer(std::io::stderr); | ||
| impl Default for LoggerBuilder { | ||
| fn default() -> Self { | ||
| Self { | ||
| log_level: "info".to_string(), | ||
| log_dir: "log".to_string(), | ||
| filename_prefix: "app".to_string(), | ||
| filename_suffix: "log".to_string(), | ||
| rotation: Some(rolling::Rotation::DAILY), | ||
| console_enabled: true, | ||
| file_enabled: true, | ||
| retention_days: DEFAULT_LOG_RETENTION_DAYS, | ||
| } | ||
| } | ||
| } | ||
| let formatting_layer = formatting_layer.pretty(); | ||
| impl LoggerBuilder { | ||
| /// 创建一个新的 Logger 构建器 | ||
| pub fn init() -> Self { | ||
| Self::default() | ||
| } | ||
| let subscriber = Registry::default() | ||
| .with(env_filter) | ||
| .with(ErrorLayer::default()) | ||
| .with(formatting_layer); | ||
| /// 设置日志级别 | ||
| pub fn with(mut self, level: &str) -> Self { | ||
| self.log_level = level.to_string(); | ||
| self | ||
| } | ||
| if let Some(path) = log_file_path { | ||
| let file_appender = rolling::never("logs", path); | ||
| let (non_blocking_appender, guard) = non_blocking(file_appender); | ||
| /// 设置日志目录 | ||
| pub fn log_dir(mut self, dir: &str) -> Self { | ||
| self.log_dir = dir.to_string(); | ||
| self | ||
| } | ||
| let file_layer = fmt::layer() | ||
| .with_ansi(false) | ||
| .with_writer(non_blocking_appender); | ||
| /// 设置文件名前缀 | ||
| pub fn filename_prefix(mut self, prefix: &str) -> Self { | ||
| self.filename_prefix = prefix.to_string(); | ||
| self | ||
| } | ||
| let subscriber = subscriber.with(file_layer); | ||
| /// 设置文件名后缀 | ||
| pub fn filename_suffix(mut self, suffix: &str) -> Self { | ||
| self.filename_suffix = suffix.to_string(); | ||
| self | ||
| } | ||
| // Initialize the subscriber | ||
| tracing::subscriber::set_global_default(subscriber) | ||
| .expect("Failed to set global subscriber"); | ||
| /// 设置日志轮转策略 | ||
| pub fn file_appender_rotation(mut self, rotation: rolling::Rotation) -> Self { | ||
| self.rotation = Some(rotation); | ||
| self | ||
| } | ||
| // Ensure all logs are flushed before the application exits | ||
| std::mem::drop(guard); | ||
| } else { | ||
| // Initialize the subscriber without file logging | ||
| tracing::subscriber::set_global_default(subscriber) | ||
| .expect("Failed to set global subscriber"); | ||
| /// 启用或禁用控制台输出 | ||
| pub fn with_console(mut self, enabled: bool) -> Self { | ||
| self.console_enabled = enabled; | ||
| self | ||
| } | ||
| /// 启用或禁用文件输出 | ||
| pub fn with_file(mut self, enabled: bool) -> Self { | ||
| self.file_enabled = enabled; | ||
| self | ||
| } | ||
| /// 设置日志保留天数 | ||
| pub fn retention_days(mut self, days: u64) -> Self { | ||
| self.retention_days = days; | ||
| self | ||
| } | ||
| /// 构建并初始化日志系统 | ||
| pub fn build(self) { | ||
| // 清理旧日志文件 | ||
| if self.file_enabled { | ||
| let rotation = self.rotation.as_ref().unwrap_or(&rolling::Rotation::NEVER); | ||
| if let Err(e) = clean_old_logs( | ||
| &self.log_dir, | ||
| &self.filename_prefix, | ||
| &self.filename_suffix, | ||
| rotation.clone(), | ||
| self.retention_days | ||
| ) { | ||
| eprintln!("Warning: Failed to clean old logs: {}", e); | ||
| } | ||
| } | ||
| // 创建环境过滤器 | ||
| let env_filter = EnvFilter::try_from_default_env() | ||
| .unwrap_or_else(|_| EnvFilter::new(&self.log_level)); | ||
| let timer = create_local_timer(); | ||
| // 根据配置构建不同的 subscriber | ||
| match (self.console_enabled, self.file_enabled) { | ||
| (true, true) => { | ||
| // 控制台和文件都启用 | ||
| let file_appender = if let Some(rotation) = self.rotation { | ||
| rolling::RollingFileAppender::builder() | ||
| .rotation(rotation) | ||
| .filename_prefix(&self.filename_prefix) | ||
| .filename_suffix(&self.filename_suffix) | ||
| .build(&self.log_dir) | ||
| .expect("Failed to create rolling file appender") | ||
| } else { | ||
| let file_path = format!("{}/{}.{}", self.log_dir, self.filename_prefix, self.filename_suffix); | ||
| rolling::never(&self.log_dir, &file_path) | ||
| }; | ||
| let console_layer = fmt::layer() | ||
| .with_timer(timer.clone()) | ||
| .pretty() | ||
| .with_writer(std::io::stdout); | ||
| let file_layer = fmt::layer() | ||
| .with_ansi(false) | ||
| .with_timer(timer) | ||
| .with_writer(file_appender); | ||
| if let Err(e) = Registry::default() | ||
| .with(env_filter) | ||
| .with(console_layer) | ||
| .with(file_layer) | ||
| .try_init() | ||
| { | ||
| eprintln!("Failed to initialize logger: {}", e); | ||
| } | ||
| } | ||
| (true, false) => { | ||
| // 只启用控制台 | ||
| let console_layer = fmt::layer() | ||
| .with_timer(timer) | ||
| .pretty() | ||
| .with_writer(std::io::stdout); | ||
| if let Err(e) = Registry::default() | ||
| .with(env_filter) | ||
| .with(console_layer) | ||
| .try_init() | ||
| { | ||
| eprintln!("Failed to initialize logger: {}", e); | ||
| } | ||
| } | ||
| (false, true) => { | ||
| // 只启用文件 | ||
| let file_appender = if let Some(rotation) = self.rotation { | ||
| rolling::RollingFileAppender::builder() | ||
| .rotation(rotation) | ||
| .filename_prefix(&self.filename_prefix) | ||
| .filename_suffix(&self.filename_suffix) | ||
| .build(&self.log_dir) | ||
| .expect("Failed to create rolling file appender") | ||
| } else { | ||
| let file_path = format!("{}/{}.{}", self.log_dir, self.filename_prefix, self.filename_suffix); | ||
| rolling::never(&self.log_dir, &file_path) | ||
| }; | ||
| let file_layer = fmt::layer() | ||
| .with_ansi(false) | ||
| .with_timer(timer) | ||
| .with_writer(file_appender); | ||
| if let Err(e) = Registry::default() | ||
| .with(env_filter) | ||
| .with(file_layer) | ||
| .try_init() | ||
| { | ||
| eprintln!("Failed to initialize logger: {}", e); | ||
| } | ||
| } | ||
| (false, false) => { | ||
| eprintln!("Warning: Both console and file logging are disabled"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| /// 创建本地时间格式化器(完全兼容版) | ||
| fn create_local_timer() -> OffsetTime<time::format_description::OwnedFormatItem> { | ||
| let offset = UtcOffset::current_local_offset() | ||
| .expect("Failed to get local time offset"); | ||
| // 使用 parse 函数替代宏,兼容所有 time 库版本 | ||
| let time_format = parse("[year]-[month]-[day] [hour]:[minute]:[second]") | ||
| .expect("Invalid time format string"); | ||
| // 将 Vec<FormatItem> 转换为 OwnedFormatItem 以满足静态生命周期要求 | ||
| let time_format = time::format_description::OwnedFormatItem::from(time_format); | ||
| OffsetTime::new(offset, time_format) | ||
| } | ||
| /// 清理指定目录下超过指定天数的日志文件 | ||
| /// | ||
| /// # 参数 | ||
| /// - `log_dir`: 日志文件所在目录 | ||
| /// - `filename_prefix`: 日志文件名前缀 | ||
| /// - `filename_suffix`: 日志文件名后缀 | ||
| /// - `file_appender_rotation`: 日志轮转策略 | ||
| /// - `retention_days`: 保留的最大天数,超过该天数的文件将被删除 | ||
| /// | ||
| /// # 返回值 | ||
| /// - Result<(), std::io::Error>: 成功返回Ok(()),失败返回错误信息 | ||
| pub fn clean_old_logs( | ||
| log_dir: &str, | ||
| filename_prefix: &str, | ||
| filename_suffix: &str, | ||
| file_appender_rotation: rolling::Rotation, | ||
| retention_days: u64, | ||
| ) -> Result<(), std::io::Error> { | ||
| // 检查日志目录是否存在 | ||
| let log_dir_path = Path::new(log_dir); | ||
| if !log_dir_path.exists() { | ||
| return Ok(()); | ||
| } | ||
| // 计算过期时间点 | ||
| let cutoff_datetime = Local::now() - TimeDelta::days(retention_days as i64); | ||
| // 遍历日志目录下的所有文件 | ||
| for entry in fs::read_dir(log_dir_path)? { | ||
| let entry = entry?; | ||
| let path = entry.path(); | ||
| // 只处理文件(跳过目录) | ||
| if path.is_file() { | ||
| // 获取文件名 | ||
| if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { | ||
| // 检查是否匹配前缀和后缀 | ||
| let has_correct_prefix = file_name.starts_with(&format!("{}.", filename_prefix)); | ||
| let has_correct_suffix = file_name.ends_with(&format!(".{}", filename_suffix)); | ||
| if !has_correct_prefix || !has_correct_suffix { | ||
| continue; | ||
| } | ||
| // 根据轮转策略判断文件是否过期 | ||
| let is_expired = match file_appender_rotation { | ||
| rolling::Rotation::NEVER => { | ||
| // 不轮转,直接比较文件修改时间 | ||
| if let Ok(metadata) = fs::metadata(&path) { | ||
| if let Ok(modified) = metadata.modified() { | ||
| let modified_datetime = chrono::DateTime::<chrono::Local>::from(modified); | ||
| modified_datetime < cutoff_datetime | ||
| } else { | ||
| false | ||
| } | ||
| } else { | ||
| false | ||
| } | ||
| } | ||
| rolling::Rotation::HOURLY => { | ||
| // 每小时轮转,文件名格式: prefix.YYYY-MM-DD-HH.suffix | ||
| match extract_datetime_from_filename(file_name, &format!("{}.", filename_prefix), &format!(".{}", filename_suffix), "%Y-%m-%d-%H") { | ||
| Some(file_datetime) => file_datetime < cutoff_datetime, | ||
| None => false, | ||
| } | ||
| } | ||
| rolling::Rotation::DAILY => { | ||
| // 每天轮转,文件名格式: prefix.YYYY-MM-DD.suffix | ||
| match extract_datetime_from_filename(file_name, &format!("{}.", filename_prefix), &format!(".{}", filename_suffix), "%Y-%m-%d") { | ||
| Some(file_datetime) => file_datetime < cutoff_datetime, | ||
| None => false, | ||
| } | ||
| } | ||
| rolling::Rotation::MINUTELY => { | ||
| // 每分钟轮转,文件名格式: prefix.YYYY-MM-DD-HH-MM.suffix | ||
| match extract_datetime_from_filename(file_name, &format!("{}.", filename_prefix), &format!(".{}", filename_suffix), "%Y-%m-%d-%H-%M") { | ||
| Some(file_datetime) => file_datetime < cutoff_datetime, | ||
| None => false, | ||
| } | ||
| } | ||
| rolling::Rotation::WEEKLY => { | ||
| // 每周轮转,使用文件修改时间 | ||
| if let Ok(metadata) = fs::metadata(&path) { | ||
| if let Ok(modified) = metadata.modified() { | ||
| let modified_datetime = chrono::DateTime::<chrono::Local>::from(modified); | ||
| modified_datetime < cutoff_datetime | ||
| } else { | ||
| false | ||
| } | ||
| } else { | ||
| false | ||
| } | ||
| } | ||
| }; | ||
| if is_expired { | ||
| println!("Deleting old log file: {}", path.display()); | ||
| fs::remove_file(&path)?; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
| /// 从文件名中提取日期时间 | ||
| fn extract_datetime_from_filename( | ||
| file_name: &str, | ||
| prefix: &str, | ||
| suffix: &str, | ||
| format_str: &str, | ||
| ) -> Option<chrono::DateTime<Local>> { | ||
| // 移除前缀和后缀 | ||
| let datetime_str = file_name.strip_prefix(prefix)?.strip_suffix(suffix)?; | ||
| // 尝试解析日期时间 | ||
| match NaiveDate::parse_from_str(datetime_str, format_str) { | ||
| Ok(date) => Some(date.and_hms_opt(0, 0, 0)?.and_local_timezone(Local).unwrap()), | ||
| Err(_) => None, | ||
| } | ||
| } | ||
| /// 简化的初始化函数(兼容原有接口) | ||
| pub fn init() { | ||
| init_info(); | ||
| } | ||
| } | ||
| #[cfg(feature = "logger")] | ||
| pub use logger::*; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet