Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions examples/rotate_custom_format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use flexi_logger::{
sort_by_creation_date, Age, Cleanup, Criterion, CustomFormatter, Duplicate, FileSorter,
FileSpec, FlexiLoggerError, LevelFilter, Logger, Naming,
};
use std::{thread::sleep, time::Duration};

fn format_infix(o_last_infix: Option<String>) -> String {
let id = match o_last_infix {
Some(infix) => {
let id: usize = infix.parse().unwrap();
id + 1
}
None => 0,
};
id.to_string()
}

fn main() -> Result<(), FlexiLoggerError> {
Logger::with(LevelFilter::Info)
.rotate(
Criterion::Age(Age::Second),
Naming::CustomFormat(CustomFormatter::new(format_infix)),
Cleanup::KeepLogFiles(4),
)
.log_to_file(
FileSpec::default()
.directory(std::env::current_dir().unwrap().join("log_files"))
.basename("app-log")
.suffix("txt")
.file_sorter(FileSorter::new(sort_by_creation_date)),
)
.duplicate_to_stdout(Duplicate::All)
.start()?;

log::info!("start");
for step in 0..30 {
log::info!("step {}", step);
sleep(Duration::from_millis(250));
}
log::info!("done");

Ok(())
}
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ pub use crate::{
log_specification::{LogSpecBuilder, LogSpecification, ModuleFilter},
logger::{Duplicate, ErrorChannel, Logger},
logger_handle::{LogfileSelector, LoggerHandle},
parameters::{Age, Cleanup, Criterion, FileSpec, Naming},
parameters::{
sort_by_creation_date, sort_by_default, Age, Cleanup, Criterion, CustomFormatter,
FileSorter, FileSpec, Naming,
},
write_mode::{WriteMode, DEFAULT_BUFFER_CAPACITY, DEFAULT_FLUSH_INTERVAL},
};

Expand Down
4 changes: 3 additions & 1 deletion src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ mod naming;
pub use age::Age;
pub use cleanup::Cleanup;
pub use criterion::Criterion;
pub use file_spec::FileSpec;
pub use file_spec::{sort_by_creation_date, sort_by_default};
pub use file_spec::{FileSorter, FileSpec};
pub use naming::CustomFormatter;
pub use naming::Naming;
57 changes: 55 additions & 2 deletions src/parameters/file_spec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::writers::file_log_writer::InfixFilter;
use crate::{DeferredNow, FlexiLoggerError};
use std::fs;
use std::{
ffi::{OsStr, OsString},
ops::Add,
Expand Down Expand Up @@ -51,6 +52,7 @@ pub struct FileSpec {
timestamp_cfg: TimestampCfg,
o_suffix: Option<String>,
pub(crate) use_utc: bool,
file_sorter: FileSorter,
}
impl Default for FileSpec {
/// Describes a file in the current folder,
Expand All @@ -65,6 +67,7 @@ impl Default for FileSpec {
timestamp_cfg: TimestampCfg::Default,
o_suffix: Some(String::from("log")),
use_utc: false,
file_sorter: FileSorter::default(),
}
}
}
Expand Down Expand Up @@ -108,6 +111,7 @@ impl FileSpec {
o_suffix: p.extension().map(|s| s.to_string_lossy().to_string()),
timestamp_cfg: TimestampCfg::No,
use_utc: false,
file_sorter: FileSorter::default(),
})
}
}
Expand Down Expand Up @@ -136,6 +140,11 @@ impl FileSpec {
self
}

///Basename getter
pub fn get_basename(&self) -> &str {
&self.basename
}

/// Specifies a folder for the log files.
///
/// If the specified folder does not exist, it will be created.
Expand Down Expand Up @@ -185,6 +194,12 @@ impl FileSpec {
self
}

/// Specifies file sorter
pub fn file_sorter(mut self, file_sorter: FileSorter) -> Self {
self.file_sorter = file_sorter;
self
}

/// Makes the logger not include the start time into the names of the log files
///
/// Equivalent to `use_timestamp(false)`.
Expand Down Expand Up @@ -368,8 +383,7 @@ impl FileSpec {
}
})
.collect::<Vec<PathBuf>>();
log_files.sort_unstable();
log_files.reverse();
self.file_sorter.sort(&mut log_files);
log_files
}

Expand Down Expand Up @@ -418,6 +432,45 @@ impl FileSpec {
}
}

/// File sorter stores and exposes interface to sorting strategy
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FileSorter {
sort_fn: fn(&mut [PathBuf]),
}

impl FileSorter {
/// Creates new FileSorter
pub fn new(sort_fn: fn(&mut [PathBuf])) -> Self {
Self { sort_fn }
}

fn sort(&self, files: &mut [PathBuf]) {
(self.sort_fn)(files)
}
}

impl Default for FileSorter {
fn default() -> Self {
Self::new(sort_by_default)
}
}

/// sorts log files by the creation date
pub fn sort_by_creation_date(files: &mut [PathBuf]) {
files.sort_by_key(|path| {
fs::metadata(path)
.and_then(|metadata| metadata.created())
.ok()
});
files.reverse();
}

/// default sorting algorithm
pub fn sort_by_default(files: &mut [PathBuf]) {
files.sort_unstable();
files.reverse();
}

const TS_USCORE_DASHES_USCORE_DASHES: &str = "%Y-%m-%d_%H-%M-%S";

#[derive(Debug, Clone, Eq, PartialEq)]
Expand Down
22 changes: 22 additions & 0 deletions src/parameters/naming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ pub enum Naming {
///
/// File rotation switches over to the next file.
NumbersDirect,

/// Allows to specify custom infix and treat each file with basename as log file
CustomFormat(CustomFormatter),
}

impl Naming {
pub(crate) fn writes_direct(self) -> bool {
matches!(
Expand All @@ -117,3 +121,21 @@ impl Naming {
)
}
}

/// Custom Formatter
#[derive(Copy, Clone, Debug)]
pub struct CustomFormatter {
format_fn: fn(Option<String>) -> String,
}

impl CustomFormatter {
/// Instantiate custom formatter
pub fn new(format_fn: fn(Option<String>) -> String) -> Self {
CustomFormatter { format_fn }
}

/// call custom formatter
pub fn call(&self, o_last_infix: Option<String>) -> String {
(self.format_fn)(o_last_infix)
}
}
2 changes: 1 addition & 1 deletion src/writers/file_log_writer/infix_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl InfixFilter {
#[cfg(test)]
InfixFilter::StartsWth(s) => infix.starts_with(s),
InfixFilter::Equls(s) => infix.eq(s),
InfixFilter::None => false,
InfixFilter::None => true,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emabee I was not sure about semantics of None variant, should it filter all or none? If former then I would create a new variant.

}
}
}
20 changes: 19 additions & 1 deletion src/writers/file_log_writer/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod list_and_cleanup;
mod numbers;
mod timestamps;

use list_and_cleanup::get_last_infix;
pub(crate) use timestamps::timestamp_from_ts_infix;

use super::{
Expand All @@ -12,7 +13,7 @@ use super::{
use crate::util::eprint_msg;
use crate::{
util::{eprint_err, ErrorCode},
Age, Cleanup, Criterion, FlexiLoggerError, LogfileSelector, Naming,
Age, Cleanup, Criterion, CustomFormatter, FlexiLoggerError, LogfileSelector, Naming,
};
use chrono::{DateTime, Datelike, Local, Timelike};
#[cfg(feature = "async")]
Expand Down Expand Up @@ -55,6 +56,9 @@ enum NamingState {

// contains the index of the current output file
NumbersDirect(u32),

// contains custom formatter and last infix
CustomFormat(CustomFormatter, String),
}
impl NamingState {
pub(crate) fn writes_direct(&self) -> bool {
Expand All @@ -77,6 +81,7 @@ impl NamingState {
infix_format,
} => InfixFilter::Timstmps(infix_format.clone()),
NamingState::NumbersDirect(_) | NamingState::NumbersRCurrent(_) => InfixFilter::Numbrs,
NamingState::CustomFormat(_, _) => InfixFilter::None,
}
}
}
Expand Down Expand Up @@ -403,6 +408,14 @@ impl State {
};
(NamingState::NumbersDirect(idx), numbers::number_infix(idx))
}
Naming::CustomFormat(ref formatter) => {
let o_last_infix: Option<String> = get_last_infix(&self.config.file_spec);
let current_infix = formatter.call(o_last_infix);
(
NamingState::CustomFormat(*formatter, current_infix.clone()),
current_infix,
)
}
};
let (write, path) = open_log_file(&self.config, Some(&infix))?;
let roll_state = RollState::new(rotate_config.criterion, self.config.append, &path)?;
Expand Down Expand Up @@ -494,6 +507,11 @@ impl State {
*idx_state += 1;
numbers::number_infix(*idx_state)
}
NamingState::CustomFormat(ref formatter, ref mut last_infix) => {
let infix = formatter.call(Some(last_infix.clone()));
*last_infix = infix.clone();
infix
}
};
let (new_write, new_path) = open_log_file(&self.config, Some(&infix))?;

Expand Down
13 changes: 13 additions & 0 deletions src/writers/file_log_writer/state/list_and_cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,16 @@ pub(super) fn start_cleanup_thread(
})?,
})
}

pub(super) fn get_last_infix(file_spec: &FileSpec) -> Option<String> {
let log_files =
super::list_and_cleanup::list_of_log_and_compressed_files(file_spec, &InfixFilter::None);
// ascending ordering
let last_log_file = log_files.first()?;
let last_log_name = last_log_file.file_stem().unwrap(/*ok*/).to_string_lossy();
Some(
last_log_name
.strip_prefix(&format!("{}_", file_spec.get_basename()))?
.to_owned(),
)
}