Skip to content

Commit

Permalink
s/CountSuffix/AppendCount, s/TimestampSuffixScheme/AppendTimestamp
Browse files Browse the repository at this point in the history
- bump to v0.6.0 because of breaking change
- some changes to docs
  • Loading branch information
Ploppz committed Feb 4, 2022
1 parent 8e14ece commit eeafc74
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 51 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "file-rotate"
version = "0.5.3"
version = "0.6.0"
authors = ["Kevin Robert Stravers <macocio@gmail.com>", "Erlend Langseth <3rlendhl@gmail.com>"]
edition = "2018"
description = "Log rotation for files"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ Following are some supplementary examples to get started.
## Basic example

```rust
use file_rotate::{FileRotate, ContentLimit, suffix::CountSuffix};
use file_rotate::{FileRotate, ContentLimit, suffix::AppendCount};
use std::{fs, io::Write, path::PathBuf};

fn main() {
let mut log = FileRotate::new("logs/log", CountSuffix::new(2), ContentLimit::Lines(3));
let mut log = FileRotate::new("logs/log", AppendCount::new(2), ContentLimit::Lines(3));

// Write a bunch of lines
writeln!(log, "Line 1: Hello World!");
Expand Down Expand Up @@ -46,7 +46,7 @@ Line 10
```rust
let mut log = FileRotate::new(
"logs/log",
TimestampSuffix::default(FileLimit::MaxFiles(3)),
AppendTimestamp::default(FileLimit::MaxFiles(3)),
ContentLimit::Lines(3),
);

Expand Down
1 change: 1 addition & 0 deletions src/compression.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Compression - configuration and implementation
use flate2::write::GzEncoder;
use std::{
fs::{self, File, OpenOptions},
Expand Down
56 changes: 37 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! We can rotate log files with the amount of lines as a limit, by using [ContentLimit::Lines].
//!
//! ```
//! use file_rotate::{FileRotate, ContentLimit, suffix::CountSuffix, compression::Compression};
//! use file_rotate::{FileRotate, ContentLimit, suffix::AppendCount, compression::Compression};
//! use std::{fs, io::Write};
//!
//! // Create a new log writer. The first argument is anything resembling a path. The
Expand All @@ -24,7 +24,12 @@
//! # let directory = directory.path();
//! let log_path = directory.join("my-log-file");
//!
//! let mut log = FileRotate::new(log_path.clone(), CountSuffix::new(2), ContentLimit::Lines(3), Compression::None);
//! let mut log = FileRotate::new(
//! log_path.clone(),
//! AppendCount::new(2),
//! ContentLimit::Lines(3),
//! Compression::None
//! );
//!
//! // Write a bunch of lines
//! writeln!(log, "Line 1: Hello World!");
Expand All @@ -43,14 +48,19 @@
//! Another method of rotation is by bytes instead of lines, with [ContentLimit::Bytes].
//!
//! ```
//! use file_rotate::{FileRotate, ContentLimit, suffix::CountSuffix, compression::Compression};
//! use file_rotate::{FileRotate, ContentLimit, suffix::AppendCount, compression::Compression};
//! use std::{fs, io::Write};
//!
//! # let directory = tempdir::TempDir::new("rotation-doc-test").unwrap();
//! # let directory = directory.path();
//! let log_path = directory.join("my-log-file");
//!
//! let mut log = FileRotate::new("target/my-log-directory-bytes/my-log-file", CountSuffix::new(2), ContentLimit::Bytes(5), Compression::None);
//! let mut log = FileRotate::new(
//! "target/my-log-directory-bytes/my-log-file",
//! AppendCount::new(2),
//! ContentLimit::Bytes(5),
//! Compression::None
//! );
//!
//! writeln!(log, "Test file");
//!
Expand All @@ -67,20 +77,25 @@
//!
//! ## Basic count ##
//!
//! With [CountSuffix], when the limit is reached in the main log file, the file is moved with
//! With [AppendCount], when the limit is reached in the main log file, the file is moved with
//! suffix `.1`, and subsequently numbered files are moved in a cascade.
//!
//! Here's an example with 1 byte limits:
//!
//! ```
//! use file_rotate::{FileRotate, ContentLimit, suffix::CountSuffix, compression::Compression};
//! use file_rotate::{FileRotate, ContentLimit, suffix::AppendCount, compression::Compression};
//! use std::{fs, io::Write};
//!
//! # let directory = tempdir::TempDir::new("rotation-doc-test").unwrap();
//! # let directory = directory.path();
//! let log_path = directory.join("my-log-file");
//!
//! let mut log = FileRotate::new(log_path.clone(), CountSuffix::new(3), ContentLimit::Bytes(1), Compression::None);
//! let mut log = FileRotate::new(
//! log_path.clone(),
//! AppendCount::new(3),
//! ContentLimit::Bytes(1),
//! Compression::None
//! );
//!
//! write!(log, "A");
//! assert_eq!("A", fs::read_to_string(&log_path).unwrap());
Expand Down Expand Up @@ -109,12 +124,12 @@
//!
//! ## Timestamp suffix ##
//!
//! With [TimestampSuffixScheme], when the limit is reached in the main log file, the file is moved with
//! With [AppendTimestamp], when the limit is reached in the main log file, the file is moved with
//! suffix equal to the current timestamp (with the specified or a default format). If the
//! destination file name already exists, `.1` (and up) is appended.
//!
//! Note that this works somewhat different to `CountSuffix` because of lexical ordering concerns:
//! Higher numbers mean more recent logs, whereas `CountSuffix` works in the opposite way.
//! Note that this works somewhat different to `AppendCount` because of lexical ordering concerns:
//! Higher numbers mean more recent logs, whereas `AppendCount` works in the opposite way.
//! The reason for this is to keep the lexical ordering of log names consistent: Higher lexical value
//! means more recent.
//! This is of course all assuming that the format start with the year (or most significant
Expand All @@ -124,15 +139,20 @@
//! their timestamp ([FileLimit::Age]), or just maximum number of files ([FileLimit::MaxFiles]).
//!
//! ```
//! use file_rotate::{FileRotate, ContentLimit, suffix::{TimestampSuffixScheme, FileLimit},
//! use file_rotate::{FileRotate, ContentLimit, suffix::{AppendTimestamp, FileLimit},
//! compression::Compression};
//! use std::{fs, io::Write};
//!
//! # let directory = tempdir::TempDir::new("rotation-doc-test").unwrap();
//! # let directory = directory.path();
//! let log_path = directory.join("my-log-file");
//!
//! let mut log = FileRotate::new(log_path.clone(), TimestampSuffixScheme::default(FileLimit::MaxFiles(2)), ContentLimit::Bytes(1), Compression::None);
//! let mut log = FileRotate::new(
//! log_path.clone(),
//! AppendTimestamp::default(FileLimit::MaxFiles(2)),
//! ContentLimit::Bytes(1),
//! Compression::None
//! );
//!
//! write!(log, "A");
//! assert_eq!("A", fs::read_to_string(&log_path).unwrap());
Expand All @@ -155,8 +175,8 @@
//! If you use timestamps as suffix, you can also configure files to be removed as they reach a
//! certain age. For example:
//! ```rust
//! use file_rotate::suffix::{TimestampSuffixScheme, FileLimit};
//! TimestampSuffixScheme::default(FileLimit::Age(chrono::Duration::weeks(1)));
//! use file_rotate::suffix::{AppendTimestamp, FileLimit};
//! AppendTimestamp::default(FileLimit::Age(chrono::Duration::weeks(1)));
//! ```
//!
//! # Compression #
Expand All @@ -173,7 +193,7 @@
//!
//! let mut log = FileRotate::new(
//! "./log",
//! TimestampSuffixScheme::default(FileLimit::MaxFiles(4)),
//! AppendTimestamp::default(FileLimit::MaxFiles(4)),
//! ContentLimit::Bytes(1),
//! Compression::OnRotate(2),
//! );
Expand Down Expand Up @@ -204,7 +224,7 @@
//! # use std::path::Path;
//! println!(
//! "{:#?}",
//! TimestampSuffixScheme::default(FileLimit::MaxFiles(4)).scan_suffixes(Path::new("./log"))
//! AppendTimestamp::default(FileLimit::MaxFiles(4)).scan_suffixes(Path::new("./log"))
//! );
//! ```
//!
Expand Down Expand Up @@ -272,9 +292,7 @@ use std::{
};
use suffix::*;

/// Compression
pub mod compression;
/// Suffix scheme etc
pub mod suffix;
#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -443,7 +461,7 @@ impl<S: SuffixScheme> FileRotate<S> {
&mut self,
old_suffix_info: Option<SuffixInfo<S::Repr>>,
) -> io::Result<SuffixInfo<S::Repr>> {
// NOTE: this newest_suffix is there only because TimestampSuffixScheme specifically needs
// NOTE: this newest_suffix is there only because AppendTimestamp specifically needs
// it. Otherwise it might not be necessary to provide this to `rotate_file`. We could also
// have passed the internal BTreeMap itself, but it would require to make SuffixInfo `pub`.

Expand Down
42 changes: 25 additions & 17 deletions src/suffix.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! Suffix schemes determine the suffix of rotated files
//!
//! This behaviour is fully extensible through the [SuffixScheme] trait, and two behaviours are
//! provided: [AppendCount] and [AppendTimestamp]
//!
use crate::SuffixInfo;
#[cfg(feature = "chrono04")]
use chrono::{offset::Local, Duration, NaiveDateTime};
Expand Down Expand Up @@ -97,23 +102,24 @@ fn prepare_filename(path: &str) -> (&str, bool) {
.unwrap_or((path, false))
}

/// Rotated log files get a number as suffix. The greater the number, the older. The oldest files
/// are deleted.
pub struct CountSuffix {
/// Append a number when rotating the file.
/// The greater the number, the older. The oldest files are deleted.
pub struct AppendCount {
max_files: usize,
}

impl CountSuffix {
/// New suffix scheme, deleting files when the total number of files exceeds `max_files`.
/// For example, if max_files is 3, then the files `log`, `log.1`, `log.2`, `log.3` may exist
impl AppendCount {
/// New suffix scheme, deleting files when the number of rotated files (i.e. excluding the main
/// file) exceeds `max_files`.
/// For example, if `max_files` is 3, then the files `log`, `log.1`, `log.2`, `log.3` may exist
/// but not `log.4`. In other words, `max_files` determines the largest possible suffix number.
pub fn new(max_files: usize) -> Self {
Self { max_files }
}
}

impl Representation for usize {}
impl SuffixScheme for CountSuffix {
impl SuffixScheme for AppendCount {
type Repr = usize;
fn rotate_file(
&mut self,
Expand All @@ -134,33 +140,36 @@ impl SuffixScheme for CountSuffix {
}
}

/// Append current timestamp as suffix when rotating files.
/// If the timestamp already exists, an additional number is appended.
///
/// Current limitations:
/// - Neither `format` or the base filename can include the character `"."`.
/// - Neither `format` nor the base filename can include the character `"."`.
/// - The `format` should ensure that the lexical and chronological orderings are the same
#[cfg(feature = "chrono04")]
pub struct TimestampSuffixScheme {
pub struct AppendTimestamp {
/// The format of the timestamp suffix
pub format: &'static str,
/// The file limit, e.g. when to delete an old file - by age (given by suffix) or by number of files
pub file_limit: FileLimit,
}

#[cfg(feature = "chrono04")]
impl TimestampSuffixScheme {
impl AppendTimestamp {
/// With format `"%Y%m%dT%H%M%S"`
pub fn default(file_limit: FileLimit) -> Self {
Self {
format: "%Y%m%dT%H%M%S",
file_limit,
}
}
/// Create new TimestampSuffixScheme suffix scheme
/// Create new AppendTimestamp suffix scheme
pub fn with_format(format: &'static str, file_limit: FileLimit) -> Self {
Self { format, file_limit }
}
}

/// Structured representation of the suffixes of TimestampSuffixScheme.
/// Structured representation of the suffixes of AppendTimestamp.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TimestampSuffix {
/// The timestamp
Expand Down Expand Up @@ -194,7 +203,7 @@ impl std::fmt::Display for TimestampSuffix {
}

#[cfg(feature = "chrono04")]
impl SuffixScheme for TimestampSuffixScheme {
impl SuffixScheme for AppendTimestamp {
type Repr = TimestampSuffix;

fn rotate_file(
Expand Down Expand Up @@ -257,13 +266,12 @@ impl SuffixScheme for TimestampSuffixScheme {
}
}

/// How to determine if a file should be deleted, in the case of [TimestampSuffixScheme].
/// How to determine whether a file should be deleted, in the case of [AppendTimestamp].
#[cfg(feature = "chrono04")]
pub enum FileLimit {
/// Delete the oldest files if number of files is too high
MaxFiles(usize),
/// Delete files whose by their age, determined by the suffix (only works in the case that
/// [TimestampSuffixScheme] is used)
/// Delete files whose age exceeds the `Duration` - age is determined by the suffix of the file
Age(Duration),
}

Expand Down Expand Up @@ -297,7 +305,7 @@ mod test {
fn scan_suffixes() {
let working_dir = tempdir::TempDir::new("file-rotate").unwrap();
let working_dir = working_dir.path().join("dir");
let suffix_scheme = TimestampSuffixScheme::default(FileLimit::Age(Duration::weeks(1)));
let suffix_scheme = AppendTimestamp::default(FileLimit::Age(Duration::weeks(1)));

// Test `scan_suffixes` for different possible paths given to it
// (it used to have a bug taking e.g. "log".parent() --> panic)
Expand Down
Loading

0 comments on commit eeafc74

Please sign in to comment.