Skip to content

Commit

Permalink
Introduce new Naming variants (without _rCURRENT)
Browse files Browse the repository at this point in the history
  - fixes #127
  - introduce LoggerHandle.trigger_rotation() (fixes #147)
  • Loading branch information
emabee committed Sep 19, 2023
1 parent 602d33f commit de3eb0c
Show file tree
Hide file tree
Showing 20 changed files with 1,192 additions and 602 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci_test.yml
Expand Up @@ -57,7 +57,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
rust: [ stable, 1.64.0 ]
rust: [ stable, 1.66.1 ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.26.1] - 2023-09-19

Introduce new naming variants that work without `_rCURRENT` files: `Naming::TimestampsDirect`
and `Naming::NumbersDirect` (fixes #127).

Improve documentation of filename handling.

Introduce `LoggerHandle.trigger_rotation()` (fixes #147).

## [0.26.0] - 2023-08-30

Re-open output also for other writers (fixes #143).
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "flexi_logger"
version = "0.26.0"
version = "0.26.1"
authors = ["emabee <meinolf.block@sap.com>"]
categories = ["development-tools::debugging"]
description = """
Expand All @@ -15,7 +15,7 @@ keywords = ["file", "logger"]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/emabee/flexi_logger"
rust-version = "1.64.0"
rust-version = "1.66.0"

[lib]
doctest = false
Expand Down Expand Up @@ -55,7 +55,7 @@ regex = { version = "1.1", optional = true }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
thiserror = "1.0"
toml = { version = "0.7", optional = true }
toml = { version = "0.8", optional = true }
tracing = { version = "0.1.36", optional = true }
tracing-subscriber = { version = "0.3", optional = true, features = [
"env-filter",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -60,7 +60,7 @@ See

## Minimal rust version

The minimal supported rust version is currently "1.64.0",
The minimal supported rust version is currently "1.66.0",
due to a change in a patch version of a dependency.

## Crate Features
Expand Down
1 change: 0 additions & 1 deletion scripts/cleanup.rs
Expand Up @@ -22,7 +22,6 @@ fn main() {
"./log_files/**/*.log",
"./log_files/**/*.seclog",
"./log_files/**/*.toml",
"./log_files/**/*.zip",
"./server/**/*.toml",
] {
for globresult in glob::glob(pattern).unwrap() {
Expand Down
6 changes: 3 additions & 3 deletions scripts/qualify.rs
Expand Up @@ -48,8 +48,8 @@ fn main() {

// Build in important variants
std::fs::remove_file("Cargo.lock").ok();
run_command!("cargo", "+1.64.0", "build", "--no-default-features");
run_command!("cargo", "+1.64.0", "build", "--all-features");
run_command!("cargo", "+1.66.1", "build", "--no-default-features");
run_command!("cargo", "+1.66.1", "build", "--all-features");

std::fs::remove_file("Cargo.lock").ok();
run_command!("cargo", "build");
Expand All @@ -67,7 +67,7 @@ fn main() {
run_command!("cargo", "+nightly", "clippy", "--all-targets", "--all-features", "--", "-D", "warnings");

// Run tests in important variants
run_command!("cargo", "+1.64.0", "test", "--all-features");
run_command!("cargo", "+1.66.1", "test", "--all-features");
run_command!("cargo", "test", "--release", "--all-features");
run_command!("cargo", "test", "--no-default-features");
run_command!("cargo", "test", "--release");
Expand Down
56 changes: 39 additions & 17 deletions src/file_spec.rs
Expand Up @@ -4,17 +4,29 @@ use std::path::{Path, PathBuf};

/// Builder object for specifying the name and path of the log output file.
///
/// ```rust
/// # use flexi_logger::FileSpec;
/// assert_eq!(
/// FileSpec::default()
/// .directory("/a/b/c")
/// .basename("foo")
/// .suppress_timestamp()
/// .suffix("bar"),
/// FileSpec::try_from("/a/b/c/foo.bar").unwrap()
/// );
/// ```
/// The filename is built from several partially optional components, using this pattern:
///
/// ```<basename>[_<discriminant>][_<date>_<time>][_infix][.<suffix>]```
///
/// The default filename pattern without rotation uses the program name as basename,
/// no discriminant, the timestamp of the program start, and the suffix `.log`,
/// e.g.
///
/// ```myprog_2015-07-08_10-44-11.log```.
///
/// This ensures that with every program start a new trace file is written that can easily
/// be associated with a concrete program run.
///
/// When the timestamp is suppressed with [`FileSpec::suppress_timestamp`],
/// you get a fixed output file.
/// It is then worth considering whether a new program start should discard
/// the content of an already existing outputfile or if it should append its new content to it
/// (see [`Logger::append`](crate::Logger::append)).
///
/// With rotation the timestamp is by default suppressed and instead the infix is used.
/// The infix always starts with "_r". For more details how its precise content can be influenced,
/// see [`Naming`](crate::Naming).
///
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FileSpec {
pub(crate) directory: PathBuf,
Expand Down Expand Up @@ -50,6 +62,17 @@ impl FileSpec {
/// If it exists, it must be a file, not a folder.
/// If necessary, parent folders will be created.
///
/// ```rust
/// # use flexi_logger::FileSpec;
/// assert_eq!(
/// FileSpec::default()
/// .directory("/a/b/c")
/// .basename("foo")
/// .suppress_timestamp()
/// .suffix("bar"),
/// FileSpec::try_from("/a/b/c/foo.bar").unwrap()
/// );
/// ```
/// # Errors
///
/// [`FlexiLoggerError::OutputBadFile`] if the given path exists and is a folder.
Expand Down Expand Up @@ -177,7 +200,7 @@ impl FileSpec {
self.directory.clone()
}

/// Creates a `PathBuf` to the described log file.
/// Derives a `PathBuf` from the spec and the given infix.
///
/// It is composed like this:
/// `<directory>/<basename>_<discr>_<timestamp><infix>.<suffix>`
Expand Down Expand Up @@ -206,8 +229,8 @@ impl FileSpec {
p_path
}

// <directory>/<basename>_<discr>_<timestamp><infix>.<suffix>
pub(crate) fn as_glob_pattern(&self, o_infix: Option<&str>, o_suffix: Option<&str>) -> String {
// <directory>/<basename>_<discr>_<timestamp><infix_pattern>.<suffix>
pub(crate) fn as_glob_pattern(&self, infix_pattern: &str, o_suffix: Option<&str>) -> String {
let mut filename = self.basename.clone();
filename.reserve(50);

Expand All @@ -218,9 +241,8 @@ impl FileSpec {
if let Some(timestamp) = &self.timestamp_cfg.get_timestamp() {
filename.push_str(timestamp);
}
if let Some(infix) = o_infix {
filename.push_str(infix);
};
filename.push_str(infix_pattern);

match o_suffix {
Some(s) => {
filename.push('.');
Expand Down
11 changes: 7 additions & 4 deletions src/logger.rs
Expand Up @@ -187,9 +187,7 @@ impl Logger {

/// Log is written to a file.
///
///
/// The default filename pattern is `<program_name>_<date>_<time>.<suffix>`,
/// e.g. `myprog_2015-07-08_10-44-11.log`.
/// See [`FileSpec`] for details about the filename pattern.
///
/// You can duplicate to stdout and stderr, and you can add additional writers.
#[must_use]
Expand Down Expand Up @@ -858,7 +856,7 @@ pub(crate) fn create_specfile_watcher<S: LogSpecSubscriber>(

let mut debouncer = new_debouncer(
std::time::Duration::from_millis(1000),
None,
None, // <--- goes away with notify-debouncer-mini version 0.4
move |res: DebounceEventResult| match res {
Ok(events) => events.iter().for_each(|e| {
if e.path
Expand Down Expand Up @@ -888,6 +886,11 @@ pub(crate) fn create_specfile_watcher<S: LogSpecSubscriber>(
&e,
);
}),
// Err(e) => eprint_err(
// ErrorCode::LogSpecFile,
// "error while watching the specfile",
// &e,
// ),
},
)
.unwrap();
Expand Down
17 changes: 17 additions & 0 deletions src/logger_handle.rs
Expand Up @@ -271,6 +271,23 @@ impl LoggerHandle {
result
}

/// Trigger an extra log file rotation.
///
/// Does nothing if rotation is not configured.
///
/// # Errors
///
/// `FlexiLoggerError::Poison` if some mutex is poisoned.
pub fn trigger_rotation(&self) -> Result<(), FlexiLoggerError> {
if let PrimaryWriter::Multi(ref mw) = &*self.writers_handle.primary_writer {
mw.trigger_rotation()?;
}
// for blw in self.writers_handle.other_writers.values() {
// let result2 = blw.trigger_rotation(); // todo is not (yet?) part of trait LogWriter
// }
Ok(())
}

/// Shutdown all participating writers.
///
/// This method is supposed to be called at the very end of your program, if
Expand Down
40 changes: 35 additions & 5 deletions src/parameters.rs
Expand Up @@ -71,17 +71,47 @@ pub enum Age {

/// The naming convention for rotated log files.
///
/// With file rotation, the logs are written to a file with infix `_rCURRENT`.
/// When rotation happens, the CURRENT log file will be renamed to a file with
/// another infix of the form `"_r..."`. `Naming` defines which other infix will be used.
/// Common rule for all variants is that the names of the current output file
/// and the rotated log files only differ in the infix.
///
/// See [`Logger::log_to_file`](crate::Logger::log_to_file)
/// for a description of how the filename is built, including the infix.
///
/// See the variants for how the infix is used by them.
///
/// Used in [`Logger::rotate`](crate::Logger::rotate).
#[derive(Copy, Clone, Debug)]
pub enum Naming {
/// File rotation rotates to files with a timestamp-infix, like `"r2020-01-27_14-41-08"`.
/// Logs are written to a file with infix `_rCURRENT`.
///
/// File rotation renames this file to a name with a timestamp-infix
/// like `"_r2023-01-27_14-41-08"`, logging continues with a fresh file with infix `_rCURRENT`.
///
/// If multiple rotations happen within the same second, extended infixes are used like
/// `"_r2023-01-27_14-41-08.restart-0001"`.
Timestamps,
/// File rotation rotates to files with a number-infix.

/// Logs are written to a file with a timestamp-infix,
/// like `"_r2023-01-27_14-41-08"`.
///
/// File rotation switches over to the next file.
///
/// If multiple rotations happen within the same second, extended infixes are used like
/// `"_r2023-01-27_14-41-08.restart-0001"`.
TimestampsDirect,

/// Logs are written to a file with infix `_rCURRENT`.
///
/// File rotation renames this file to a name with a number-infix
/// like `"_r00000"`, `"_r00001"`, etc.,
/// logging continues with a fresh file with infix `_rCURRENT`.
Numbers,

/// Logs are written to a file with a number-infix,
/// like `"_r00000"`, `"_r00001"`, etc.
///
/// File rotation switches over to the next file.
NumbersDirect,
}
/// Defines the strategy for handling older log files.
///
Expand Down
10 changes: 10 additions & 0 deletions src/primary_writer/multi_writer.rs
Expand Up @@ -93,6 +93,16 @@ impl MultiWriter {
fn duplication_to_stdout(&self) -> Duplicate {
Duplicate::from(self.duplicate_stdout.load(Ordering::Relaxed))
}

pub(crate) fn trigger_rotation(&self) -> Result<(), FlexiLoggerError> {
if let Some(ref w) = &self.o_file_writer {
w.trigger_rotation()?;
}
// if let Some(w) = &self.o_other_writer {
// w.trigger_rotation(); // todo is not (yet?) part of trait LogWriter
// }
Ok(())
}
}

impl LogWriter for MultiWriter {
Expand Down
19 changes: 11 additions & 8 deletions src/writers/file_log_writer.rs
Expand Up @@ -7,7 +7,6 @@ mod threads;

pub use self::builder::{ArcFileLogWriter, FileLogWriterBuilder, FileLogWriterHandle};
pub use self::config::FileLogWriterConfig;
pub(crate) use self::state::remove_or_compress_too_old_logfiles_impl;

use self::{config::RotationConfig, state::State, state_handle::StateHandle};
use crate::{
Expand Down Expand Up @@ -70,12 +69,6 @@ impl FileLogWriter {
self.state_handle.format_function()
}

#[must_use]
#[doc(hidden)]
pub fn current_filename(&self) -> PathBuf {
self.state_handle.current_filename()
}

pub(crate) fn plain_write(&self, buffer: &[u8]) -> std::result::Result<usize, std::io::Error> {
self.state_handle.plain_write(buffer)
}
Expand Down Expand Up @@ -132,10 +125,20 @@ impl FileLogWriter {
self.state_handle.reopen_outputfile()
}

/// Trigger an extra log file rotation.
///
/// Does nothing if rotation is not configured.
///
/// # Errors
///
/// `FlexiLoggerError::Poison` if some mutex is poisoned.
pub fn trigger_rotation(&self) -> Result<(), FlexiLoggerError> {
self.state_handle.force_rotation()
}

/// Returns the list of existing log files according to the current `FileSpec`.
///
/// The list includes the current log file and the compressed files, if they exist.
/// The list is empty if the logger is not configured for writing to files.
///
/// # Errors
///
Expand Down

0 comments on commit de3eb0c

Please sign in to comment.