Skip to content

Commit

Permalink
refactor: move TimeRotation into one separate module and add test for it
Browse files Browse the repository at this point in the history
  • Loading branch information
1996fanrui committed Aug 10, 2024
1 parent d2db4c7 commit 421de63
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 70 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ serde_json = { version = "1.0", optional = true }
time = { version = "0.3", features = [
"formatting",
"parsing",
"macros",
], optional = true }

## Fastrace dependencies
Expand Down
4 changes: 2 additions & 2 deletions examples/rolling_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use log::LevelFilter;
use logforth::append::rolling_file::NonBlockingBuilder;
use logforth::append::rolling_file::RollingFile;
use logforth::append::rolling_file::RollingFileWriter;
use logforth::append::rolling_file::Rotation;
use logforth::append::rolling_file::TimeRotation;
use logforth::append::Stdout;
use logforth::layout::JsonLayout;
use logforth::layout::TextLayout;
Expand All @@ -25,7 +25,7 @@ use logforth::Logger;

fn main() {
let rolling = RollingFileWriter::builder()
.rotation(Rotation::Minutely)
.rotation(TimeRotation::Minutely)
.filename_prefix("example")
.filename_suffix("log")
.max_log_files(10)
Expand Down
3 changes: 2 additions & 1 deletion src/append/rolling_file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ pub use non_blocking::NonBlockingBuilder;
pub use non_blocking::WorkerGuard;
pub use rolling::RollingFileWriter;
pub use rolling::RollingFileWriterBuilder;
pub use rolling::Rotation;
pub use rotation::TimeRotation;

mod append;
mod non_blocking;
mod rolling;
mod rotation;
mod worker;

#[derive(Debug)]
Expand Down
76 changes: 9 additions & 67 deletions src/append/rolling_file/rolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

use crate::append::rolling_file::TimeRotation;
use anyhow::Context;
use parking_lot::RwLock;
use time::format_description;
use time::Date;
use time::Duration;
use time::OffsetDateTime;
use time::Time;

/// A file writer with the ability to rotate log files at a fixed schedule.
#[derive(Debug)]
Expand Down Expand Up @@ -73,7 +72,7 @@ impl Write for RollingFileWriter {
/// A builder for [`RollingFileWriter`].
#[derive(Debug)]
pub struct RollingFileWriterBuilder {
rotation: Rotation,
rotation: TimeRotation,
prefix: Option<String>,
suffix: Option<String>,
max_size: usize,
Expand All @@ -90,7 +89,7 @@ impl RollingFileWriterBuilder {
#[must_use]
pub const fn new() -> Self {
Self {
rotation: Rotation::Never,
rotation: TimeRotation::Never,
prefix: None,
suffix: None,
max_size: usize::MAX,
Expand All @@ -99,7 +98,7 @@ impl RollingFileWriterBuilder {
}

#[must_use]
pub fn rotation(mut self, rotation: Rotation) -> Self {
pub fn rotation(mut self, rotation: TimeRotation) -> Self {
self.rotation = rotation;
self
}
Expand Down Expand Up @@ -162,7 +161,7 @@ struct State {
log_filename_prefix: Option<String>,
log_filename_suffix: Option<String>,
date_format: Vec<format_description::FormatItem<'static>>,
rotation: Rotation,
rotation: TimeRotation,
current_date: OffsetDateTime,
current_count: usize,
current_filesize: usize,
Expand All @@ -174,7 +173,7 @@ struct State {
impl State {
fn new(
now: OffsetDateTime,
rotation: Rotation,
rotation: TimeRotation,
dir: impl AsRef<Path>,
log_filename_prefix: Option<String>,
log_filename_suffix: Option<String>,
Expand Down Expand Up @@ -218,11 +217,11 @@ impl State {
&self.log_filename_prefix,
&self.log_filename_suffix,
) {
(&Rotation::Never, Some(filename), None) => format!("{filename}.{cnt}"),
(&Rotation::Never, Some(filename), Some(suffix)) => {
(&TimeRotation::Never, Some(filename), None) => format!("{filename}.{cnt}"),
(&TimeRotation::Never, Some(filename), Some(suffix)) => {
format!("{filename}.{cnt}.{suffix}")
}
(&Rotation::Never, None, Some(suffix)) => format!("{cnt}.{suffix}"),
(&TimeRotation::Never, None, Some(suffix)) => format!("{cnt}.{suffix}"),
(_, Some(filename), Some(suffix)) => format!("{filename}.{date}.{cnt}.{suffix}"),
(_, Some(filename), None) => format!("{filename}.{date}.{cnt}"),
(_, None, Some(suffix)) => format!("{date}.{cnt}.{suffix}"),
Expand Down Expand Up @@ -338,60 +337,3 @@ impl State {
self.next_date_timestamp = self.rotation.next_date_timestamp(&now);
}
}

/// Defines a fixed period for rolling of a log file.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Rotation {
/// Minutely Rotation
Minutely,
/// Hourly Rotation
Hourly,
/// Daily Rotation
Daily,
/// No Rotation
Never,
}

impl Rotation {
fn next_date_timestamp(&self, current_date: &OffsetDateTime) -> Option<usize> {
let next_date = match *self {
Rotation::Minutely => *current_date + Duration::minutes(1),
Rotation::Hourly => *current_date + Duration::hours(1),
Rotation::Daily => *current_date + Duration::days(1),
Rotation::Never => return None,
};

Some(self.round_date(&next_date).unix_timestamp() as usize)
}

fn round_date(&self, date: &OffsetDateTime) -> OffsetDateTime {
match *self {
Rotation::Minutely => {
let time = Time::from_hms(date.hour(), date.minute(), 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
Rotation::Hourly => {
let time = Time::from_hms(date.hour(), 0, 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
Rotation::Daily => {
let time = Time::from_hms(0, 0, 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
Rotation::Never => unreachable!("Rotation::Never is impossible to round."),
}
}

fn date_format(&self) -> Vec<format_description::FormatItem<'static>> {
match *self {
Rotation::Minutely => format_description::parse("[year]-[month]-[day]-[hour]-[minute]"),
Rotation::Hourly => format_description::parse("[year]-[month]-[day]-[hour]"),
Rotation::Daily => format_description::parse("[year]-[month]-[day]"),
Rotation::Never => format_description::parse("[year]-[month]-[day]"),
}
.expect("failed to create a formatter; this is a bug in logforth rolling file appender")
}
}
102 changes: 102 additions & 0 deletions src/append/rolling_file/rotation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2024 tison <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use time::format_description;
use time::Duration;
use time::OffsetDateTime;
use time::Time;

/// Defines a fixed period for rolling of a log file.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum TimeRotation {
/// Minutely Rotation
Minutely,
/// Hourly Rotation
Hourly,
/// Daily Rotation
Daily,
/// No Time Rotation
Never,
}

impl TimeRotation {
pub fn next_date_timestamp(&self, current_date: &OffsetDateTime) -> Option<usize> {
let next_date = match *self {
TimeRotation::Minutely => *current_date + Duration::minutes(1),
TimeRotation::Hourly => *current_date + Duration::hours(1),
TimeRotation::Daily => *current_date + Duration::days(1),
TimeRotation::Never => return None,
};

Some(self.round_date(&next_date).unix_timestamp() as usize)
}

fn round_date(&self, date: &OffsetDateTime) -> OffsetDateTime {
match *self {
TimeRotation::Minutely => {
let time = Time::from_hms(date.hour(), date.minute(), 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
TimeRotation::Hourly => {
let time = Time::from_hms(date.hour(), 0, 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
TimeRotation::Daily => {
let time = Time::from_hms(0, 0, 0)
.expect("invalid time; this is a bug in logforth rolling file appender");
date.replace_time(time)
}
TimeRotation::Never => unreachable!("Rotation::Never is impossible to round."),
}
}

pub fn date_format(&self) -> Vec<format_description::FormatItem<'static>> {
match *self {
TimeRotation::Minutely => {
format_description::parse("[year]-[month]-[day]-[hour]-[minute]")
}
TimeRotation::Hourly => format_description::parse("[year]-[month]-[day]-[hour]"),
TimeRotation::Daily => format_description::parse("[year]-[month]-[day]"),
TimeRotation::Never => format_description::parse("[year]-[month]-[day]"),
}
.expect("failed to create a formatter; this is a bug in logforth rolling file appender")
}
}

#[cfg(test)]
mod tests {
use super::TimeRotation;
use time::macros::datetime;

#[test]
fn test_next_date_timestamp() {
let current_date = datetime!(2024-08-10 17:12:52 +8);

assert_eq!(
TimeRotation::Minutely.next_date_timestamp(&current_date),
Some(datetime!(2024-08-10 17:13:00 +8).unix_timestamp() as usize)
);
assert_eq!(
TimeRotation::Hourly.next_date_timestamp(&current_date),
Some(datetime!(2024-08-10 18:00:00 +8).unix_timestamp() as usize)
);
assert_eq!(
TimeRotation::Daily.next_date_timestamp(&current_date),
Some(datetime!(2024-08-11 00:00:00 +8).unix_timestamp() as usize)
);
assert_eq!(TimeRotation::Never.next_date_timestamp(&current_date), None);
}
}

0 comments on commit 421de63

Please sign in to comment.