Skip to content

Commit

Permalink
Add methods
Browse files Browse the repository at this point in the history
`LoggerHandle::adapt_duplication_to_stderr` and  `LoggerHandle::adapt_duplication_to_stdout`
- (realizes issue #142).

And:
- Extend docu on providing custom format.
- Use rust-script instead of cargo-script for qualification scripts.
- Update dependencies.
  • Loading branch information
emabee committed Jul 28, 2023
1 parent 0f4bbd9 commit 721f8e2
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 27 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ 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.25.6] - 2023-07-28

Add methods
`LoggerHandle::adapt_duplication_to_stderr` and `LoggerHandle::adapt_duplication_to_stdout`
(realizes issue #142).

Extend docu on providing custom format.

Use rust-script instead of cargo-script for qualification scripts.

Update dependencies.

## [0.25.5] - 2023-05-25

Use display (rather than debug) formatting for thread names
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "flexi_logger"
version = "0.25.5"
version = "0.25.6"
authors = ["emabee <[email protected]>"]
categories = ["development-tools::debugging"]
description = """
Expand Down Expand Up @@ -41,7 +41,7 @@ trc = ["async", "specfile", "tracing", "tracing-subscriber"]

[dependencies]
is-terminal = { version = "0.4", optional = true }
nu-ansi-term = { version = "0.47", optional = true }
nu-ansi-term = { version = "0.49", optional = true }
chrono = { version = "0.4.22", default-features = false, features = ["clock"] }
crossbeam-channel = { version = "0.5", optional = true }
crossbeam-queue = { version = "0.3", optional = true }
Expand Down
32 changes: 32 additions & 0 deletions examples/entry_numbers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use flexi_logger::{DeferredNow, FlexiLoggerError, Logger};
use log::*;
use std::sync::atomic::{AtomicU32, Ordering};

// Produces
// 1 INFO [entry_numbers] first
// 2 WARN [entry_numbers] second
// 3 ERROR [entry_numbers] third
fn main() -> Result<(), FlexiLoggerError> {
Logger::try_with_str("info")?.format(my_format).start()?;

info!("first");
warn!("second");
error!("third");
Ok(())
}

pub fn my_format(
w: &mut dyn std::io::Write,
_now: &mut DeferredNow,
record: &Record,
) -> Result<(), std::io::Error> {
static LINE: AtomicU32 = AtomicU32::new(1);
write!(
w,
"{:>6} {} [{}] {}",
LINE.fetch_add(1, Ordering::Relaxed),
record.level(),
record.module_path().unwrap_or("<unnamed>"),
record.args()
)
}
1 change: 1 addition & 0 deletions scripts/check.rs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env rust-script
//! ```cargo
//! [dependencies]
//! yansi = "0.5"
Expand Down
1 change: 1 addition & 0 deletions scripts/cleanup.rs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env rust-script
//! Cleans up all files and folders that were produced by test runs.
//!
//! ```cargo
Expand Down
1 change: 1 addition & 0 deletions scripts/qualify.rs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env rust-script
//! ```cargo
//! [dependencies]
//! yansi = "0.5"
Expand Down
5 changes: 4 additions & 1 deletion scripts/qualify_fast.rs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env rust-script
//! ```cargo
//! [dependencies]
//! yansi = "0.5"
Expand Down Expand Up @@ -54,5 +55,7 @@ fn main() {
run_command!("cargo", "doc", "--all-features", "--no-deps", "--open");

// say goodbye
println!("\n> fast qualification is done :-) Looks like you're ready to do the full qualification?");
println!(
"\n> fast qualification is done :-) Looks like you're ready to do the full qualification?"
);
}
23 changes: 22 additions & 1 deletion src/code_examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,28 @@ With [`Logger::format`](crate::Logger::format)
you set the format for all used output channels of `flexi_logger`.

`flexi_logger` provides a couple of format functions, and you can also create and use your own,
e.g. by copying and modifying one of the provided format functions.
e.g. by copying and modifying one of the provided format functions (see [formats.rs](https://github.com/emabee/flexi_logger/blob/master/src/formats.rs)).

Here's an example that you could create somewhere in your code.
It also illustrates the signature the format function must have.

```rust,ignore
pub fn my_own_format(
w: &mut dyn std::io::Write,
now: &mut DeferredNow,
record: &Record,
) -> Result<(), std::io::Error> {
let level = record.level();
write!(
w,
"{} [Thread {}] Severity {}, Message: {}",
now.format(TS_DASHES_BLANK_COLONS_DOT_BLANK),
thread::current().name().unwrap_or("<unnamed>"),
record.level(),
&record.args()
)
}
```

Depending on the configuration, `flexi_logger` can write logs to multiple channels
(stdout, stderr, files, or additional writers)
Expand Down
4 changes: 4 additions & 0 deletions src/flexi_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ pub enum FlexiLoggerError {
#[error("Chosen reset not possible")]
Reset,

/// Method not possible because duplication is not possible.
#[error("Method not possible because duplication is not possible")]
NoDuplication,

/// Method not possible because no file logger is configured.
#[error("Method not possible because no file logger is configured")]
NoFileLogger,
Expand Down
28 changes: 21 additions & 7 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,19 +966,33 @@ pub(crate) fn log_spec_string_from_file<P: AsRef<Path>>(
#[derive(Debug, Clone, Copy)]
pub enum Duplicate {
/// No messages are duplicated.
None,
None = 0,
/// Only error messages are duplicated.
Error,
Error = 1,
/// Error and warn messages are duplicated.
Warn,
Warn = 2,
/// Error, warn, and info messages are duplicated.
Info,
Info = 3,
/// Error, warn, info, and debug messages are duplicated.
Debug,
Debug = 4,
/// All messages are duplicated.
Trace,
Trace = 5,
/// All messages are duplicated.
All,
All = 6,
}
impl From<u8> for Duplicate {
fn from(val: u8) -> Self {
match val {
0 => Duplicate::None,
1 => Duplicate::Error,
2 => Duplicate::Warn,
3 => Duplicate::Info,
4 => Duplicate::Debug,
5 => Duplicate::Trace,
6 => Duplicate::All,
_ => unreachable!(),
}
}
}

impl From<LevelFilter> for Duplicate {
Expand Down
32 changes: 31 additions & 1 deletion src/logger_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
primary_writer::PrimaryWriter,
util::{eprint_err, ErrorCode},
writers::{FileLogWriterBuilder, FileLogWriterConfig, LogWriter},
{FlexiLoggerError, LogSpecification},
Duplicate, FlexiLoggerError, LogSpecification,
};
use std::{
collections::HashMap,
Expand Down Expand Up @@ -290,6 +290,36 @@ impl LoggerHandle {
Ok(log_files)
}

/// Allows re-configuring duplication to stderr.
///
/// # Errors
///
/// `FlexiLoggerError::NoDuplication`
/// if `FlexiLogger` was initialized without duplication support
pub fn adapt_duplication_to_stderr(&mut self, dup: Duplicate) -> Result<(), FlexiLoggerError> {
if let PrimaryWriter::Multi(ref mw) = &*self.writers_handle.primary_writer {
mw.adapt_duplication_to_stderr(dup);
Ok(())
} else {
Err(FlexiLoggerError::NoFileLogger)
}
}

/// Allows re-configuring duplication to stdout.
///
/// # Errors
///
/// `FlexiLoggerError::NoDuplication`
/// if `FlexiLogger` was initialized without duplication support
pub fn adapt_duplication_to_stdout(&mut self, dup: Duplicate) -> Result<(), FlexiLoggerError> {
if let PrimaryWriter::Multi(ref mw) = &*self.writers_handle.primary_writer {
mw.adapt_duplication_to_stdout(dup);
Ok(())
} else {
Err(FlexiLoggerError::NoFileLogger)
}
}

// Allows checking the logs written so far to the writer
#[doc(hidden)]
pub fn validate_logs(&self, expected: &[(&'static str, &'static str, &'static str)]) {
Expand Down
37 changes: 28 additions & 9 deletions src/primary_writer/multi_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ use crate::{
{DeferredNow, FlexiLoggerError, FormatFunction},
};
use log::Record;
use std::{io::Write, path::PathBuf};
use std::{
io::Write,
path::PathBuf,
sync::atomic::{AtomicU8, Ordering},
};

// The `MultiWriter` writes logs to a FileLogWriter and/or another Writer,
// and can duplicate messages to stderr or stdout.
pub(crate) struct MultiWriter {
duplicate_stderr: Duplicate,
duplicate_stdout: Duplicate,
duplicate_stderr: AtomicU8,
duplicate_stdout: AtomicU8,
support_capture: bool,
format_for_stderr: FormatFunction,
format_for_stdout: FormatFunction,
Expand All @@ -30,8 +34,8 @@ impl MultiWriter {
o_other_writer: Option<Box<dyn LogWriter>>,
) -> Self {
MultiWriter {
duplicate_stderr,
duplicate_stdout,
duplicate_stderr: AtomicU8::new(duplicate_stderr as u8),
duplicate_stdout: AtomicU8::new(duplicate_stdout as u8),
support_capture,
format_for_stderr,
format_for_stdout,
Expand Down Expand Up @@ -66,6 +70,21 @@ impl MultiWriter {
Ok(Vec::new())
}
}

pub(crate) fn adapt_duplication_to_stderr(&self, dup: Duplicate) {
self.duplicate_stderr.store(dup as u8, Ordering::Relaxed);
}

pub(crate) fn adapt_duplication_to_stdout(&self, dup: Duplicate) {
self.duplicate_stdout.store(dup as u8, Ordering::Relaxed);
}

fn duplication_to_stderr(&self) -> Duplicate {
Duplicate::from(self.duplicate_stderr.load(Ordering::Relaxed))
}
fn duplication_to_stdout(&self) -> Duplicate {
Duplicate::from(self.duplicate_stdout.load(Ordering::Relaxed))
}
}

impl LogWriter for MultiWriter {
Expand All @@ -79,7 +98,7 @@ impl LogWriter for MultiWriter {
}

fn write(&self, now: &mut DeferredNow, record: &Record) -> std::io::Result<()> {
if match self.duplicate_stderr {
if match self.duplication_to_stderr() {
Duplicate::Error => record.level() == log::Level::Error,
Duplicate::Warn => record.level() <= log::Level::Warn,
Duplicate::Info => record.level() <= log::Level::Info,
Expand All @@ -104,7 +123,7 @@ impl LogWriter for MultiWriter {
}
}

if match self.duplicate_stdout {
if match self.duplication_to_stdout() {
Duplicate::Error => record.level() == log::Level::Error,
Duplicate::Warn => record.level() <= log::Level::Warn,
Duplicate::Info => record.level() <= log::Level::Info,
Expand Down Expand Up @@ -163,10 +182,10 @@ impl LogWriter for MultiWriter {
writer.flush()?;
}

if !matches!(self.duplicate_stderr, Duplicate::None) {
if !matches!(self.duplication_to_stderr(), Duplicate::None) {
std::io::stderr().flush()?;
}
if !matches!(self.duplicate_stdout, Duplicate::None) {
if !matches!(self.duplication_to_stdout(), Duplicate::None) {
std::io::stdout().flush()?;
}
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/writers/file_log_writer/state_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl std::fmt::Debug for SyncHandle {
.field("am_state", &self.am_state)
.field("format", &"<..>")
.field("line_ending", &self.line_ending)
.finish()
.finish_non_exhaustive()
}
}

Expand Down Expand Up @@ -128,7 +128,7 @@ impl std::fmt::Debug for AsyncHandle {
.field("message_capa", &self.message_capa)
.field("format", &"<..>")
.field("line_ending", &self.line_ending)
.finish()
.finish_non_exhaustive()
}
}

Expand Down
8 changes: 4 additions & 4 deletions tests/test_reconfigure_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ fn test_reconfigure_methods() {
.start()
.unwrap_or_else(|e| panic!("Logger initialization failed with {e}"));

test_parse_new_spec(&mut logger);
test_parse_new_spec(&logger);
test_push_new_spec(&mut logger);
validate_logs(&mut logger);
validate_logs(&logger);
}

fn test_parse_new_spec(logger: &mut LoggerHandle) {
fn test_parse_new_spec(logger: &LoggerHandle) {
error!("1-error message");
warn!("1-warning");
info!("1-info message");
Expand Down Expand Up @@ -83,7 +83,7 @@ fn test_push_new_spec(logger: &mut LoggerHandle) {
logger.pop_temp_spec(); // should be a no-op
}

fn validate_logs(logger: &mut LoggerHandle) {
fn validate_logs(logger: &LoggerHandle) {
logger.validate_logs(&[
("ERROR", "test_reconfigure_methods", "1-error"),
("WARN", "test_reconfigure_methods", "1-warning"),
Expand Down

0 comments on commit 721f8e2

Please sign in to comment.