Skip to content

Commit

Permalink
[0.26.0] Extend LoggerHandle::reopen to all writers
Browse files Browse the repository at this point in the history
  • Loading branch information
emabee committed Sep 1, 2023
1 parent 721f8e2 commit 0d29cd4
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 54 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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
Expand Down
20 changes: 10 additions & 10 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "flexi_logger"
version = "0.25.6"
version = "0.26.0"
authors = ["emabee <meinolf.block@sap.com>"]
categories = ["development-tools::debugging"]
description = """
Expand Down Expand Up @@ -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 }
Expand All @@ -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 }
Expand Down
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -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"
```

Expand Down Expand Up @@ -69,15 +69,15 @@ 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"
```

or, to get the smallest footprint (and no colors), switch off even the default features:

```toml
[dependencies]
flexi_logger = { version = "0.25", default_features = false }
flexi_logger = { version = "0.26", default_features = false }
log = "0.4"
```

Expand Down
33 changes: 31 additions & 2 deletions src/log_specification.rs
Expand Up @@ -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,
Expand Down
25 changes: 19 additions & 6 deletions src/logger_handle.rs
Expand Up @@ -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
Expand All @@ -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.
Expand Down
10 changes: 6 additions & 4 deletions src/primary_writer.rs
Expand Up @@ -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 {
Expand Down
20 changes: 14 additions & 6 deletions src/primary_writer/multi_writer.rs
Expand Up @@ -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<Vec<PathBuf>, FlexiLoggerError> {
if let Some(fw) = self.o_file_writer.as_ref() {
Expand Down
3 changes: 0 additions & 3 deletions src/primary_writer/std_writer.rs
Expand Up @@ -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<Mutex<Cursor<Vec<u8>>>>,
Expand Down Expand Up @@ -105,7 +104,6 @@ impl StdWriter {
}
#[cfg(feature = "async")]
EffectiveWriteMode::AsyncWith {
bufsize,
pool_capa,
message_capa,
flush_interval,
Expand All @@ -117,7 +115,6 @@ impl StdWriter {
);
InnerStdWriter::Async(AsyncHandle::new(
stdstream,
bufsize,
pool_capa,
message_capa,
#[cfg(test)]
Expand Down
14 changes: 1 addition & 13 deletions src/write_mode.rs
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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),
Expand All @@ -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 {
Expand All @@ -230,7 +219,6 @@ impl WriteMode {
Self::BufferAndFlushWith(_, flush_interval) => *flush_interval,
#[cfg(feature = "async")]
Self::AsyncWith {
bufsize: _,
pool_capa: _,
message_capa: _,
flush_interval,
Expand Down
7 changes: 4 additions & 3 deletions src/writers/file_log_writer.rs
Expand Up @@ -45,7 +45,6 @@ impl FileLogWriter {

#[cfg(feature = "async")]
EffectiveWriteMode::AsyncWith {
bufsize: _,
pool_capa,
message_capa,
flush_interval: _,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down
1 change: 0 additions & 1 deletion src/writers/file_log_writer/builder.rs
Expand Up @@ -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: _,
Expand Down
15 changes: 14 additions & 1 deletion 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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 0d29cd4

Please sign in to comment.