diff --git a/CHANGELOG.md b/CHANGELOG.md index 18c1a73..89a01f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ 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.0] - 2023-08-30 + +Re-open output also for other writers (fixes #143). + +Rename method to re-open output from LoggerHandle (leads to version bump). + +Use `dep:` in Cargo.toml for references to most dependencies, in order to avoid implicit "features". + +Fix #145 (minor internal optimization). + ## [0.25.6] - 2023-07-28 Add methods diff --git a/Cargo.toml b/Cargo.toml index b06bb5c..3cab97d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flexi_logger" -version = "0.25.6" +version = "0.26.0" authors = ["emabee "] categories = ["development-tools::debugging"] description = """ @@ -29,15 +29,15 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["colors", "textfilter"] -async = ["crossbeam-channel", "crossbeam-queue"] -colors = ["nu-ansi-term", "is-terminal"] -compress = ["flate2"] +async = ["dep:crossbeam-channel", "dep:crossbeam-queue"] +colors = ["dep:nu-ansi-term", "is-terminal"] +compress = ["dep:flate2"] dont_minimize_extra_stacks = [] -specfile = ["specfile_without_notification", "notify-debouncer-mini"] -specfile_without_notification = ["serde", "toml", "serde_derive"] -syslog_writer = ["libc", "hostname"] -textfilter = ["regex"] -trc = ["async", "specfile", "tracing", "tracing-subscriber"] +specfile = ["specfile_without_notification", "dep:notify-debouncer-mini"] +specfile_without_notification = ["dep:serde", "dep:toml", "dep:serde_derive"] +syslog_writer = ["dep:libc", "dep:hostname"] +textfilter = ["dep:regex"] +trc = ["async", "specfile", "dep:tracing", "dep:tracing-subscriber"] [dependencies] is-terminal = { version = "0.4", optional = true } @@ -56,10 +56,10 @@ serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } thiserror = "1.0" toml = { version = "0.7", optional = true } +tracing = { version = "0.1.36", optional = true } tracing-subscriber = { version = "0.3", optional = true, features = [ "env-filter", ] } -tracing = { version = "0.1.36", optional = true } [target.'cfg(linux)'.dependencies] libc = { version = "^0.2.50", optional = true } diff --git a/README.md b/README.md index 810a7a2..f6360e1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ and you use the ```log``` macros to write log lines from your code): ```toml [dependencies] -flexi_logger = "0.25" +flexi_logger = "0.26" log = "0.4" ``` @@ -69,7 +69,7 @@ Make use of the non-default features by specifying them in your `Cargo.toml`, e. ```toml [dependencies] -flexi_logger = { version = "0.25", features = ["async", "specfile", "compress"] } +flexi_logger = { version = "0.26", features = ["async", "specfile", "compress"] } log = "0.4" ``` @@ -77,7 +77,7 @@ or, to get the smallest footprint (and no colors), switch off even the default f ```toml [dependencies] -flexi_logger = { version = "0.25", default_features = false } +flexi_logger = { version = "0.26", default_features = false } log = "0.4" ``` diff --git a/src/log_specification.rs b/src/log_specification.rs index e799498..dbbd5be 100644 --- a/src/log_specification.rs +++ b/src/log_specification.rs @@ -96,13 +96,42 @@ impl LogSpecification { Self::default() } - /// Returns a `LogSpecification` where the global tracelevel is set to info. + /// Returns a `LogSpecification` where the global tracelevel is set to `LevelFilter::Error`. + #[must_use] + pub fn error() -> Self { + Self::new_with(LevelFilter::Error) + } + + /// Returns a `LogSpecification` where the global tracelevel is set to `LevelFilter::Warn`. + #[must_use] + pub fn warn() -> Self { + Self::new_with(LevelFilter::Warn) + } + + /// Returns a `LogSpecification` where the global tracelevel is set to `LevelFilter::Info`. #[must_use] pub fn info() -> Self { + Self::new_with(LevelFilter::Info) + } + + /// Returns a `LogSpecification` where the global tracelevel is set to `LevelFilter::Debug`. + #[must_use] + pub fn debug() -> Self { + Self::new_with(LevelFilter::Debug) + } + + /// Returns a `LogSpecification` where the global tracelevel is set to `LevelFilter::Trace`. + #[must_use] + pub fn trace() -> Self { + Self::new_with(LevelFilter::Trace) + } + + #[must_use] + fn new_with(level_filter: LevelFilter) -> Self { Self { module_filters: vec![ModuleFilter { module_name: None, - level_filter: LevelFilter::Info, + level_filter, }], #[cfg(feature = "textfilter")] textfilter: None, diff --git a/src/logger_handle.rs b/src/logger_handle.rs index a742e44..2af9db1 100644 --- a/src/logger_handle.rs +++ b/src/logger_handle.rs @@ -238,6 +238,9 @@ impl LoggerHandle { /// such actions by calling this method. Otherwise `flexi_logger` will not stop /// writing to the renamed or even deleted file! /// + /// In more complex configurations, i.e. when more than one output stream is written to, + /// all of them will be attempted to be re-opened; only the first error will be reported. + /// /// # Example /// /// `logrotate` e.g. can be configured to send a `SIGHUP` signal to your program. You need to @@ -247,15 +250,25 @@ impl LoggerHandle { /// /// # Errors /// - /// `FlexiLoggerError::NoFileLogger` if no file log writer is configured. - /// /// `FlexiLoggerError::Poison` if some mutex is poisoned. - pub fn reopen_outputfile(&self) -> Result<(), FlexiLoggerError> { - if let PrimaryWriter::Multi(ref mw) = &*self.writers_handle.primary_writer { - mw.reopen_outputfile() + /// + /// Other variants of `FlexiLoggerError`, depending on the used writers. + pub fn reopen_output(&self) -> Result<(), FlexiLoggerError> { + let mut result = if let PrimaryWriter::Multi(ref mw) = &*self.writers_handle.primary_writer + { + mw.reopen_output() } else { - Err(FlexiLoggerError::NoFileLogger) + Ok(()) + }; + + for blw in self.writers_handle.other_writers.values() { + let result2 = blw.reopen_output(); + if result.is_ok() && result2.is_err() { + result = result2; + } } + + result } /// Shutdown all participating writers. diff --git a/src/primary_writer.rs b/src/primary_writer.rs index 5ac43e2..a33f654 100644 --- a/src/primary_writer.rs +++ b/src/primary_writer.rs @@ -16,13 +16,15 @@ use crate::{ use log::Record; use std::path::PathBuf; -// Writes either to stdout, or to stderr, -// or to a file (with optional duplication to stderr or stdout), -// or to nowhere (with optional "duplication" to stderr or stdout), -// or in simplified form using println! to stdout to enable capturing in tests. +// Primary writer +// +// all normal logging goes here pub(crate) enum PrimaryWriter { + // Writes to stdout or to stderr Std(StdWriter), + // Writes to a file or to nowhere, with optional "duplication" to stderr or stdout Multi(MultiWriter), + // Writes using println! to stdout, to enable capturing in tests Test(TestWriter), } impl PrimaryWriter { diff --git a/src/primary_writer/multi_writer.rs b/src/primary_writer/multi_writer.rs index 2018256..5d6af89 100644 --- a/src/primary_writer/multi_writer.rs +++ b/src/primary_writer/multi_writer.rs @@ -56,12 +56,20 @@ impl MultiWriter { .as_ref() .map_or(Err(FlexiLoggerError::NoFileLogger), |flw| flw.config()) } - pub(crate) fn reopen_outputfile(&self) -> Result<(), FlexiLoggerError> { - self.o_file_writer - .as_ref() - .map_or(Err(FlexiLoggerError::NoFileLogger), |flw| { - flw.reopen_outputfile() - }) + pub(crate) fn reopen_output(&self) -> Result<(), FlexiLoggerError> { + match (&self.o_file_writer, &self.o_other_writer) { + (None, None) => Ok(()), + (Some(ref w), None) => w.reopen_outputfile(), + (None, Some(w)) => w.reopen_output(), + (Some(w1), Some(w2)) => { + let r1 = w1.reopen_outputfile(); + let r2 = w2.reopen_output(); + match (r1, r2) { + (Ok(()), Ok(())) => Ok(()), + (Err(e), _) | (Ok(()), Err(e)) => Err(e), + } + } + } } pub(crate) fn existing_log_files(&self) -> Result, FlexiLoggerError> { if let Some(fw) = self.o_file_writer.as_ref() { diff --git a/src/primary_writer/std_writer.rs b/src/primary_writer/std_writer.rs index 2d3573a..0193fe2 100644 --- a/src/primary_writer/std_writer.rs +++ b/src/primary_writer/std_writer.rs @@ -50,7 +50,6 @@ struct AsyncHandle { impl AsyncHandle { fn new( stdstream: StdStream, - _bufsize: usize, pool_capa: usize, msg_capa: usize, #[cfg(test)] validation_buffer: &Arc>>>, @@ -105,7 +104,6 @@ impl StdWriter { } #[cfg(feature = "async")] EffectiveWriteMode::AsyncWith { - bufsize, pool_capa, message_capa, flush_interval, @@ -117,7 +115,6 @@ impl StdWriter { ); InnerStdWriter::Async(AsyncHandle::new( stdstream, - bufsize, pool_capa, message_capa, #[cfg(test)] diff --git a/src/write_mode.rs b/src/write_mode.rs index 4e1bd88..957f333 100644 --- a/src/write_mode.rs +++ b/src/write_mode.rs @@ -104,8 +104,6 @@ pub enum WriteMode { #[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg(feature = "async")] AsyncWith { - /// Size of the output buffer for the file. - bufsize: usize, /// Capacity of the pool for the message buffers. pool_capa: usize, /// Capacity of an individual message buffer. @@ -123,8 +121,6 @@ pub(crate) enum EffectiveWriteMode { #[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[cfg(feature = "async")] AsyncWith { - /// Size of the output buffer for the file. - bufsize: usize, /// Capacity of the pool for the message buffers. pool_capa: usize, /// Capacity of an individual message buffer. @@ -156,19 +152,16 @@ impl WriteMode { } #[cfg(feature = "async")] Self::Async => EffectiveWriteMode::AsyncWith { - bufsize: DEFAULT_BUFFER_CAPACITY, pool_capa: DEFAULT_POOL_CAPA, message_capa: DEFAULT_MESSAGE_CAPA, flush_interval: DEFAULT_FLUSH_INTERVAL, }, #[cfg(feature = "async")] Self::AsyncWith { - bufsize, pool_capa, message_capa, flush_interval, } => EffectiveWriteMode::AsyncWith { - bufsize, pool_capa, message_capa, flush_interval, @@ -185,19 +178,16 @@ impl WriteMode { Self::BufferAndFlushWith(bufsize, _) => Self::BufferDontFlushWith(*bufsize), #[cfg(feature = "async")] Self::Async => Self::AsyncWith { - bufsize: DEFAULT_BUFFER_CAPACITY, pool_capa: DEFAULT_POOL_CAPA, message_capa: DEFAULT_MESSAGE_CAPA, flush_interval: Duration::from_secs(0), }, #[cfg(feature = "async")] Self::AsyncWith { - bufsize, pool_capa, message_capa, flush_interval: _, } => Self::AsyncWith { - bufsize: *bufsize, pool_capa: *pool_capa, message_capa: *message_capa, flush_interval: Duration::from_secs(0), @@ -211,11 +201,10 @@ impl WriteMode { | EffectiveWriteMode::BufferDontFlushWith(bufsize) => Some(bufsize), #[cfg(feature = "async")] EffectiveWriteMode::AsyncWith { - bufsize, pool_capa: _, message_capa: _, flush_interval: _, - } => Some(bufsize), + } => None, } } pub(crate) fn get_flush_interval(&self) -> Duration { @@ -230,7 +219,6 @@ impl WriteMode { Self::BufferAndFlushWith(_, flush_interval) => *flush_interval, #[cfg(feature = "async")] Self::AsyncWith { - bufsize: _, pool_capa: _, message_capa: _, flush_interval, diff --git a/src/writers/file_log_writer.rs b/src/writers/file_log_writer.rs index a34360a..b998f43 100644 --- a/src/writers/file_log_writer.rs +++ b/src/writers/file_log_writer.rs @@ -45,7 +45,6 @@ impl FileLogWriter { #[cfg(feature = "async")] EffectiveWriteMode::AsyncWith { - bufsize: _, pool_capa, message_capa, flush_interval: _, @@ -162,6 +161,10 @@ impl LogWriter for FileLogWriter { self.max_log_level } + fn reopen_output(&self) -> Result<(), FlexiLoggerError> { + self.reopen_outputfile() + } + fn validate_logs(&self, expected: &[(&'static str, &'static str, &'static str)]) { self.state_handle.validate_logs(expected); } @@ -380,7 +383,6 @@ mod test { #[cfg(feature = "async")] let flwb = flwb.write_mode(WriteMode::AsyncWith { - bufsize: 5, pool_capa: 5, message_capa: 400, flush_interval: Duration::from_secs(0), @@ -437,7 +439,6 @@ mod test { let write_mode = WriteMode::BufferDontFlushWith(4); #[cfg(feature = "async")] let write_mode = WriteMode::AsyncWith { - bufsize: 6, pool_capa: 7, message_capa: 8, flush_interval: Duration::from_secs(0), diff --git a/src/writers/file_log_writer/builder.rs b/src/writers/file_log_writer/builder.rs index caec5c8..db46b1f 100644 --- a/src/writers/file_log_writer/builder.rs +++ b/src/writers/file_log_writer/builder.rs @@ -251,7 +251,6 @@ impl FileLogWriterBuilder { #[cfg(feature = "async")] let cleanup_in_background_thread = if let WriteMode::AsyncWith { - bufsize: _, pool_capa: _, message_capa: _, flush_interval: _, diff --git a/src/writers/log_writer.rs b/src/writers/log_writer.rs index fb5f83a..149d3e4 100644 --- a/src/writers/log_writer.rs +++ b/src/writers/log_writer.rs @@ -1,4 +1,4 @@ -use crate::{DeferredNow, FormatFunction}; +use crate::{DeferredNow, FlexiLoggerError, FormatFunction}; use log::Record; /// Writes to a single log output stream. @@ -39,6 +39,19 @@ pub trait LogWriter: Sync + Send { /// Cleanup open resources, if necessary. fn shutdown(&self) {} + /// Re-open the current output, if meaningful. + /// + /// This method is called from + /// [`LoggerHandle::reopen_output`](crate::LoggerHandle::reopen_output) + /// for all registered additional writers. + /// + /// # Errors + /// + /// Depend on registered writers. + fn reopen_output(&self) -> Result<(), FlexiLoggerError> { + Ok(()) + } + // Takes a vec with three patterns per line that represent the log line, // compares the written log with the expected lines, // and asserts that both are in sync. diff --git a/tests/test_external_delete.rs b/tests/test_external_delete.rs index 3af13e4..73de176 100644 --- a/tests/test_external_delete.rs +++ b/tests/test_external_delete.rs @@ -60,7 +60,7 @@ fn work(value: u8) { match std::fs::remove_file(file_path.clone()) { Ok(()) => { println!("Removed the log file {file_path:?}, which had {lines} lines"); - logger.reopen_outputfile().unwrap(); + logger.reopen_output().unwrap(); } Err(e) => { panic!("Cannot remove log file {file_path:?}, i = {i}, reason {e:?}") diff --git a/tests/test_external_rename.rs b/tests/test_external_rename.rs index 027f1a5..d0048df 100644 --- a/tests/test_external_rename.rs +++ b/tests/test_external_rename.rs @@ -67,7 +67,7 @@ fn work(value: u8) { match std::fs::rename(file_path.clone(), target_path.clone()) { Ok(()) => { println!("Renamed the log file {:?} to {:?}", file_path, &target_path); - logger.reopen_outputfile().unwrap(); + logger.reopen_output().unwrap(); } Err(e) => { panic!(