Skip to content

Commit

Permalink
Rotate file if exceeds max file size config (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjardoo authored Sep 16, 2024
1 parent 3a9af57 commit 86f22a5
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ You can set the following configuration options:

- `.datetime_format("%Y-%m-%d %H:%M:%S.3f")` to set the datetime format
- `.timezone(ftail::Tz::UTC)` to set the timezone [requires feature `timezone`]
- `.max_file_size(100)` to set the maximum file size in MB (will move older logs to .old{N})

## Drivers

Expand Down
1 change: 1 addition & 0 deletions examples/single_file/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use log::LevelFilter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
Ftail::new()
.single_file("logs/demo.log", true, LevelFilter::Trace)
.max_file_size(10)
.init()?;

log::trace!("This is a trace message");
Expand Down
11 changes: 8 additions & 3 deletions src/drivers/daily_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ use log::Log;
use std::{
fs::File,
io::{LineWriter, Write},
path::PathBuf,
sync::Mutex,
};

use crate::{
error::FtailError,
formatters::{default::DefaultFormatter, Formatter},
helpers::rotate_if_exceeds_max_file_size,
Config,
};

/// A logger that logs messages to a daily log file.
pub struct DailyFileLogger {
file: Mutex<LineWriter<File>>,
file_path: PathBuf,
dir: String,
current_date: Mutex<String>,
config: Config,
Expand All @@ -27,7 +30,7 @@ impl DailyFileLogger {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.open(&path)
.map_err(FtailError::IoError)?;

let md = std::fs::metadata(dir).map_err(FtailError::IoError)?;
Expand All @@ -38,13 +41,14 @@ impl DailyFileLogger {

Ok(DailyFileLogger {
file: Mutex::new(LineWriter::new(file)),
file_path: PathBuf::from(path),
dir: dir.to_string(),
current_date: Mutex::new(today),
config,
})
}

fn rotate_file_if_needed(&self) {
fn rotate_daily_file(&self) {
let today = chrono::Local::now().format("%Y-%m-%d").to_string();
let mut current_date = self.current_date.lock().unwrap();

Expand All @@ -71,7 +75,8 @@ impl Log for DailyFileLogger {
}

fn log(&self, record: &log::Record) {
self.rotate_file_if_needed();
rotate_if_exceeds_max_file_size(&self.file, self.file_path.clone(), &self.config);
self.rotate_daily_file();

let formatter = DefaultFormatter::new(record, &self.config);

Expand Down
6 changes: 6 additions & 0 deletions src/drivers/single_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ use log::Log;
use std::{
fs::File,
io::{LineWriter, Write},
path::PathBuf,
sync::Mutex,
};

use crate::{
error::FtailError,
formatters::{default::DefaultFormatter, Formatter},
helpers::rotate_if_exceeds_max_file_size,
Config,
};

/// A logger that logs messages to a single log file.
pub struct SingleFileLogger {
file: Mutex<LineWriter<File>>,
file_path: PathBuf,
config: Config,
}

Expand All @@ -34,6 +37,7 @@ impl SingleFileLogger {

Ok(SingleFileLogger {
file: Mutex::new(LineWriter::new(file)),
file_path: PathBuf::from(path),
config,
})
}
Expand All @@ -45,6 +49,8 @@ impl Log for SingleFileLogger {
}

fn log(&self, record: &log::Record) {
rotate_if_exceeds_max_file_size(&self.file, self.file_path.clone(), &self.config);

let formatter = DefaultFormatter::new(record, &self.config);

let mut file = self.file.lock().unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/formatters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl Config {
datetime_format: "%Y-%m-%d %H:%M:%S".to_string(),
#[cfg(feature = "timezone")]
timezone: chrono_tz::Tz::UTC,
max_file_size: None,
}
}
}
Expand Down
34 changes: 34 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::{fs::File, io::LineWriter, path::PathBuf, sync::Mutex};

use crate::Config;

pub(crate) fn rotate_if_exceeds_max_file_size(
file: &Mutex<LineWriter<File>>,
file_path: PathBuf,
config: &Config,
) {
if config.max_file_size.is_none() {
return;
}

let mut file = file.lock().unwrap();

let md = file.get_ref().metadata().unwrap();

if md.len() > config.max_file_size.unwrap() {
let path = file_path.to_str().unwrap();

let mut new_path = format!("{}.old", path);

let mut counter = 1;
while std::fs::metadata(&new_path).is_ok() {
new_path = format!("{}.old{}", path, counter);
counter += 1;
}

std::fs::rename(path, &new_path).unwrap();

let new_file = std::fs::File::create(path).unwrap();
*file = LineWriter::new(new_file);
}
}
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
//!
//! - `.datetime_format("%Y-%m-%d %H:%M:%S.3f")` to set the datetime format
//! - `.timezone(ftail::Tz::UTC)` to set the timezone [requires feature `timezone`]
//! - `.max_file_size(100)` to set the maximum file size in MB (will move older logs to .old{N})
//!
//! ## Drivers
//!
Expand Down Expand Up @@ -191,6 +192,7 @@ pub mod drivers;
/// Module containing the error type.
pub mod error;
mod formatters;
mod helpers;
mod writer;

/// The main struct for configuring the logger.
Expand Down Expand Up @@ -219,6 +221,7 @@ pub struct Config {
pub datetime_format: String,
#[cfg(feature = "timezone")]
pub timezone: chrono_tz::Tz,
pub max_file_size: Option<u64>,
}

impl Ftail {
Expand Down Expand Up @@ -246,6 +249,13 @@ impl Ftail {
self
}

/// Set the maximum file size for the logger.
pub fn max_file_size(mut self, max_file_size_in_mb: u64) -> Self {
self.config.max_file_size = Some(max_file_size_in_mb * 1024 * 1024);

self
}

fn add_driver<F>(mut self, constructor: F, level: log::LevelFilter) -> Self
where
F: Fn(Config) -> Box<dyn Log + Send + Sync> + 'static,
Expand Down

0 comments on commit 86f22a5

Please sign in to comment.