From 70901db4a0c1f4e0bfae7e8d8c3db74c4c11e357 Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 29 Aug 2024 05:31:25 +0800 Subject: [PATCH] Respect local timezone when rotating files daily --- spdlog/src/sink/rotating_file_sink.rs | 172 ++++++++++++++++++++------ spdlog/src/test_utils/unit_test.rs | 2 +- 2 files changed, 134 insertions(+), 40 deletions(-) diff --git a/spdlog/src/sink/rotating_file_sink.rs b/spdlog/src/sink/rotating_file_sink.rs index 792c3294..fc7fec52 100644 --- a/spdlog/src/sink/rotating_file_sink.rs +++ b/spdlog/src/sink/rotating_file_sink.rs @@ -500,8 +500,8 @@ impl RotatorTimePoint { // constructor. #[must_use] fn next_rotation_time_point(time_point: TimePoint, now: SystemTime) -> SystemTime { - let now: DateTime = now.into(); - let mut rotation_time: DateTime = now; + let now: DateTime = now.into(); + let mut rotation_time = now; match time_point { TimePoint::Daily { hour, minute } => { @@ -806,12 +806,14 @@ impl RotatingFileSinkBuilder { #[cfg(test)] mod tests { + use chrono::FixedOffset; + use super::*; use crate::{prelude::*, test_utils::*, Level, Record}; static BASE_LOGS_PATH: Lazy = Lazy::new(|| { let path = TEST_LOGS_PATH.join("rotating_file_sink"); - fs::create_dir(&path).unwrap(); + _ = fs::create_dir(&path); path }); @@ -1040,6 +1042,29 @@ mod tests { path }); + const SECOND_1: Duration = Duration::from_secs(1); + const HOUR_1: Duration = Duration::from_secs(60 * 60); + const DAY_1: Duration = Duration::from_secs(60 * 60 * 24); + + #[track_caller] + fn assert_files_count(file_name_prefix: &str, expected: usize) { + let paths = fs::read_dir(LOGS_PATH.clone()).unwrap(); + + let actual = paths.fold(0_usize, |count, entry| { + if entry + .unwrap() + .file_name() + .to_string_lossy() + .starts_with(file_name_prefix) + { + count + 1 + } else { + count + } + }); + assert_eq!(actual, expected) + } + #[test] fn calc_file_path() { let system_time = Local.with_ymd_and_hms(2012, 3, 4, 5, 6, 7).unwrap().into(); @@ -1114,61 +1139,130 @@ mod tests { logger }; - let exist_files = |file_name_prefix| { - let paths = fs::read_dir(LOGS_PATH.clone()).unwrap(); - - paths.fold(0_usize, |count, entry| { - if entry - .unwrap() - .file_name() - .to_string_lossy() - .starts_with(file_name_prefix) - { - count + 1 - } else { - count - } - }) - }; - - let exist_hourly_files = || exist_files("hourly"); - let exist_daily_files = || exist_files("daily"); - - const SECOND_1: Duration = Duration::from_secs(1); - const HOUR_1: Duration = Duration::from_secs(60 * 60); - const DAY_1: Duration = Duration::from_secs(60 * 60 * 24); - { let logger = build(true); let mut record = Record::new(Level::Info, "test log message"); let initial_time = record.time(); - assert_eq!(exist_hourly_files(), 1); - assert_eq!(exist_daily_files(), 1); + assert_files_count("hourly", 1); + assert_files_count("daily", 1); logger.log(&record); - assert_eq!(exist_hourly_files(), 1); - assert_eq!(exist_daily_files(), 1); + assert_files_count("hourly", 1); + assert_files_count("daily", 1); record.set_time(record.time() + HOUR_1 + SECOND_1); logger.log(&record); - assert_eq!(exist_hourly_files(), 2); - assert_eq!(exist_daily_files(), 1); + assert_files_count("hourly", 2); + assert_files_count("daily", 1); record.set_time(record.time() + HOUR_1 + SECOND_1); logger.log(&record); - assert_eq!(exist_hourly_files(), 3); - assert_eq!(exist_daily_files(), 1); + assert_files_count("hourly", 3); + assert_files_count("daily", 1); record.set_time(record.time() + SECOND_1); logger.log(&record); - assert_eq!(exist_hourly_files(), 3); - assert_eq!(exist_daily_files(), 1); + assert_files_count("hourly", 3); + assert_files_count("daily", 1); record.set_time(initial_time + DAY_1 + SECOND_1); logger.log(&record); - assert_eq!(exist_hourly_files(), 4); - assert_eq!(exist_daily_files(), 2); + assert_files_count("hourly", 4); + assert_files_count("daily", 2); + } + } + + #[test] + fn respect_local_tz() { + let prefix = "respect_local_tz"; + + let logger = { + fs::remove_dir_all(LOGS_PATH.as_path()).unwrap(); + fs::create_dir(LOGS_PATH.as_path()).unwrap(); + + let daily_sink = RotatingFileSink::builder() + .base_path(LOGS_PATH.join(format!("{prefix}.log"))) + .rotation_policy(RotationPolicy::Daily { hour: 0, minute: 0 }) + .rotate_on_open(true) + .build() + .unwrap(); + + build_test_logger(|b| b.sink(Arc::new(daily_sink)).level_filter(LevelFilter::All)) + }; + + { + let mut record = Record::new(Level::Info, "test log message"); + let initial_time = FixedOffset::east_opt(8 * 3600) + .unwrap() + .with_ymd_and_hms(2024, 8, 29, 11, 45, 14) + .unwrap(); + + assert_files_count(prefix, 1); + + record.set_time(initial_time.to_utc().into()); + logger.log(&record); + assert_files_count(prefix, 1); + + record.set_time(record.time() + HOUR_1 + SECOND_1); + logger.log(&record); + assert_files_count(prefix, 1); + + record.set_time(record.time() + HOUR_1 + SECOND_1); + logger.log(&record); + assert_files_count(prefix, 1); + + record.set_time( + initial_time + .with_day(30) + .unwrap() + .with_hour(0) + .unwrap() + .with_minute(1) + .unwrap() + .to_utc() + .into(), + ); + logger.log(&record); + assert_files_count(prefix, 2); + + record.set_time(record.time() + HOUR_1 + SECOND_1); + logger.log(&record); + assert_files_count(prefix, 2); + + record.set_time( + initial_time + .with_day(30) + .unwrap() + .with_hour(8) + .unwrap() + .with_minute(2) + .unwrap() + .to_utc() + .into(), + ); + logger.log(&record); + assert_files_count(prefix, 2); + + record.set_time(record.time() + HOUR_1 + SECOND_1); + logger.log(&record); + assert_files_count(prefix, 2); + + record.set_time( + initial_time + .with_day(31) + .unwrap() + .with_hour(0) + .unwrap() + .to_utc() + .into(), + ); + logger.log(&record); + assert_files_count(prefix, 3); + + record.set_time(record.time() + HOUR_1 + SECOND_1); + logger.log(&record); + assert_files_count(prefix, 3); } } } diff --git a/spdlog/src/test_utils/unit_test.rs b/spdlog/src/test_utils/unit_test.rs index eb8980d8..ff39706e 100644 --- a/spdlog/src/test_utils/unit_test.rs +++ b/spdlog/src/test_utils/unit_test.rs @@ -12,6 +12,6 @@ use crate::sync::*; pub static TEST_LOGS_PATH: Lazy = Lazy::new(|| { let path = Path::new(env!("OUT_DIR")).join("test_logs"); - fs::create_dir(&path).unwrap(); + _ = fs::create_dir(&path); path });