diff --git a/CHANGELOG.md b/CHANGELOG.md index cd955c6..555c92c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.4] - 2023-05-05 + +Add `LoggerHandle::existing_log_files()`. + ## [0.25.3] - 2023-03-04 Introduce additional `WriteMode` variant `SupportCapture`. diff --git a/Cargo.toml b/Cargo.toml index 0c48805..8f320ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flexi_logger" -version = "0.25.3" +version = "0.25.4" authors = ["emabee "] categories = ["development-tools::debugging"] description = """ @@ -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.60.0" +rust-version = "1.64.0" [lib] doctest = false diff --git a/scripts/qualify.rs b/scripts/qualify.rs index b5fc682..2805659 100644 --- a/scripts/qualify.rs +++ b/scripts/qualify.rs @@ -47,8 +47,8 @@ fn main() { // Build in important variants std::fs::remove_file("Cargo.lock").ok(); - run_command!("cargo", "+1.60", "build", "--no-default-features"); - run_command!("cargo", "+1.60", "build", "--all-features"); + run_command!("cargo", "+1.64.0", "build", "--no-default-features"); + run_command!("cargo", "+1.64.0", "build", "--all-features"); std::fs::remove_file("Cargo.lock").ok(); run_command!("cargo", "build"); @@ -66,7 +66,7 @@ fn main() { run_command!("cargo", "+nightly", "clippy", "--all-targets", "--all-features", "--", "-D", "warnings"); // Run tests in important variants - run_command!("cargo", "+1.60", "test", "--all-features"); + run_command!("cargo", "+1.64.0", "test", "--all-features"); run_command!("cargo", "test", "--release", "--all-features"); run_command!("cargo", "test", "--no-default-features"); run_command!("cargo", "test", "--release"); diff --git a/src/logger.rs b/src/logger.rs index 5b29082..1fdf200 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -556,9 +556,10 @@ impl Logger { /// so under normal circumstances no single message shuld appear. /// /// By default these error messages are printed to `stderr`. -#[derive(Debug)] +#[derive(Debug, Default)] pub enum ErrorChannel { /// Write `flexi_logger`'s own error messages to `stderr`. + #[default] StdErr, /// Write `flexi_logger`'s own error messages to `stdout`. StdOut, @@ -567,11 +568,6 @@ pub enum ErrorChannel { /// Don't write `flexi_logger`'s own error messages. DevNull, } -impl Default for ErrorChannel { - fn default() -> Self { - ErrorChannel::StdErr - } -} /// Alternative set of methods to control the behavior of the Logger. /// Use these methods when you want to control the settings flexibly, diff --git a/src/logger_handle.rs b/src/logger_handle.rs index b5aba2e..7e27d07 100644 --- a/src/logger_handle.rs +++ b/src/logger_handle.rs @@ -1,12 +1,17 @@ #[cfg(feature = "specfile")] use notify_debouncer_mini::{notify::RecommendedWatcher, Debouncer}; -use crate::primary_writer::PrimaryWriter; -use crate::util::{eprint_err, ErrorCode}; -use crate::writers::{FileLogWriterBuilder, FileLogWriterConfig, LogWriter}; -use crate::{FlexiLoggerError, LogSpecification}; -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; +use crate::{ + primary_writer::PrimaryWriter, + util::{eprint_err, ErrorCode}, + writers::{FileLogWriterBuilder, FileLogWriterConfig, LogWriter}, + {FlexiLoggerError, LogSpecification}, +}; +use std::{ + collections::HashMap, + path::PathBuf, + sync::{Arc, RwLock}, +}; /// Allows reconfiguring the logger while the program is running, and /// **shuts down the logger when it is dropped**. @@ -271,6 +276,20 @@ impl LoggerHandle { } } + /// 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 + /// + /// `FlexiLoggerError::Poison` if some mutex is poisoned. + pub fn existing_log_files(&self) -> Result, FlexiLoggerError> { + let mut log_files = self.writers_handle.primary_writer.existing_log_files()?; + log_files.sort(); + Ok(log_files) + } + // Allows checking the logs written so far to the writer #[doc(hidden)] pub fn validate_logs(&self, expected: &[(&'static str, &'static str, &'static str)]) { diff --git a/src/primary_writer.rs b/src/primary_writer.rs index c6c7830..5ac43e2 100644 --- a/src/primary_writer.rs +++ b/src/primary_writer.rs @@ -11,9 +11,10 @@ use crate::{ filter::LogLineWriter, logger::Duplicate, writers::{FileLogWriter, LogWriter}, - {DeferredNow, FormatFunction, WriteMode}, + DeferredNow, FlexiLoggerError, FormatFunction, WriteMode, }; 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), @@ -111,6 +112,13 @@ impl PrimaryWriter { } } } + + pub fn existing_log_files(&self) -> Result, FlexiLoggerError> { + match self { + Self::Multi(multi_writer) => multi_writer.existing_log_files(), + _ => Ok(Vec::new()), + } + } } impl LogLineWriter for PrimaryWriter { diff --git a/src/primary_writer/multi_writer.rs b/src/primary_writer/multi_writer.rs index 30d88cc..5fda53d 100644 --- a/src/primary_writer/multi_writer.rs +++ b/src/primary_writer/multi_writer.rs @@ -5,7 +5,7 @@ use crate::{ {DeferredNow, FlexiLoggerError, FormatFunction}, }; use log::Record; -use std::io::Write; +use std::{io::Write, path::PathBuf}; // The `MultiWriter` writes logs to a FileLogWriter and/or another Writer, // and can duplicate messages to stderr or stdout. @@ -59,6 +59,13 @@ impl MultiWriter { flw.reopen_outputfile() }) } + pub(crate) fn existing_log_files(&self) -> Result, FlexiLoggerError> { + if let Some(fw) = self.o_file_writer.as_ref() { + fw.existing_log_files() + } else { + Ok(Vec::new()) + } + } } impl LogWriter for MultiWriter { diff --git a/src/writers/file_log_writer.rs b/src/writers/file_log_writer.rs index 68659d2..a34360a 100644 --- a/src/writers/file_log_writer.rs +++ b/src/writers/file_log_writer.rs @@ -132,6 +132,18 @@ impl FileLogWriter { pub fn reopen_outputfile(&self) -> Result<(), FlexiLoggerError> { self.state_handle.reopen_outputfile() } + + /// 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 + /// + /// `FlexiLoggerError::Poison` if some mutex is poisoned. + pub fn existing_log_files(&self) -> Result, FlexiLoggerError> { + self.state_handle.existing_log_files() + } } impl LogWriter for FileLogWriter { diff --git a/src/writers/file_log_writer/state.rs b/src/writers/file_log_writer/state.rs index 4e2d1ea..6cfe8e1 100644 --- a/src/writers/file_log_writer/state.rs +++ b/src/writers/file_log_writer/state.rs @@ -403,6 +403,13 @@ impl State { Ok(()) } + pub fn existing_log_files(&self) -> Vec { + let mut list: Vec = + list_of_log_and_compressed_files(&self.config.file_spec).collect(); + list.push(self.config.file_spec.as_pathbuf(Some(CURRENT_INFIX))); + list + } + pub fn validate_logs(&mut self, expected: &[(&'static str, &'static str, &'static str)]) { if let Inner::Initial(_, _) = self.inner { self.initialize().expect("validate_logs: initialize failed"); @@ -487,7 +494,7 @@ fn open_log_file( ) -> Result<(Box, DateTime, PathBuf), std::io::Error> { let path = config .file_spec - .as_pathbuf(with_rotation.then(|| CURRENT_INFIX)); + .as_pathbuf(with_rotation.then_some(CURRENT_INFIX)); if config.print_message { println!("Log is written to {}", &path.display()); diff --git a/src/writers/file_log_writer/state_handle.rs b/src/writers/file_log_writer/state_handle.rs index 0a038ea..71fb47d 100644 --- a/src/writers/file_log_writer/state_handle.rs +++ b/src/writers/file_log_writer/state_handle.rs @@ -4,10 +4,13 @@ use crate::util::{buffer_with, eprint_err, io_err, ErrorCode}; use crate::util::{ASYNC_FLUSH, ASYNC_SHUTDOWN}; use crate::{DeferredNow, FlexiLoggerError, FormatFunction}; use log::Record; -use std::io::Write; -use std::sync::{Arc, Mutex}; #[cfg(feature = "async")] use std::thread::JoinHandle; +use std::{ + io::Write, + path::PathBuf, + sync::{Arc, Mutex}, +}; #[cfg(feature = "async")] use {crossbeam_channel::Sender, crossbeam_queue::ArrayQueue}; @@ -289,6 +292,17 @@ impl StateHandle { Ok(state.config().clone()) } + pub(super) fn existing_log_files(&self) -> Result, FlexiLoggerError> { + let state = match self { + StateHandle::Sync(handle) => handle.am_state.lock(), + #[cfg(feature = "async")] + StateHandle::Async(handle) => handle.am_state.lock(), + } + .map_err(|_| FlexiLoggerError::Poison)?; + + Ok(state.existing_log_files()) + } + pub(super) fn validate_logs(&self, expected: &[(&'static str, &'static str, &'static str)]) { match self { StateHandle::Sync(handle) => handle.am_state.lock(), diff --git a/tests/test_multi_threaded_cleanup_use_utc.rs b/tests/test_multi_threaded_cleanup_use_utc.rs index 1ea7b56..3cc856b 100644 --- a/tests/test_multi_threaded_cleanup_use_utc.rs +++ b/tests/test_multi_threaded_cleanup_use_utc.rs @@ -53,6 +53,12 @@ mod d { logger.set_new_spec(new_spec); wait_for_workers_to_close(worker_handles); + + let log_files = logger.existing_log_files().unwrap(); + assert_eq!(log_files.len(), NO_OF_LOG_FILES + NO_OF_GZ_FILES + 1); + for f in log_files { + debug!("Existing log file: {f:?}"); + } } verify_logs(&directory.display().to_string()); } diff --git a/tests/test_multi_threaded_numbers.rs b/tests/test_multi_threaded_numbers.rs index c897c72..6ac6317 100644 --- a/tests/test_multi_threaded_numbers.rs +++ b/tests/test_multi_threaded_numbers.rs @@ -62,6 +62,13 @@ fn multi_threaded() { }) .unwrap(); wait_for_workers_to_close(worker_handles); + + let log_files = logger.existing_log_files().unwrap(); + assert_eq!(log_files.len(), 17); + logger.parse_new_spec("info").unwrap(); + for f in log_files { + trace!("Existing log file: {f:?}"); + } } verify_logs(&directory.display().to_string()); }