From bbfad0e0673cf379a62aedc3db5e64e773bc66ea Mon Sep 17 00:00:00 2001 From: Dirreke Date: Sun, 7 Jul 2024 21:48:08 +0800 Subject: [PATCH] fix #370 --- Cargo.toml | 6 +- ..._to_file_with_rolling_and_size_trigger.rs} | 0 ...g_to_file_with_rolling_and_time_trigger.rs | 113 ++++++++++++++++++ .../policy/compound/trigger/time.rs | 12 +- 4 files changed, 127 insertions(+), 4 deletions(-) rename examples/{log_to_file_with_rolling.rs => log_to_file_with_rolling_and_size_trigger.rs} (100%) create mode 100644 examples/log_to_file_with_rolling_and_time_trigger.rs diff --git a/Cargo.toml b/Cargo.toml index fbc77abd..2cbf3995 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,9 +105,13 @@ name = "compile_time_config" required-features = ["yaml_format", "config_parsing"] [[example]] -name = "log_to_file_with_rolling" +name = "log_to_file_with_rolling_and_size_trigger" required-features = ["file_appender", "rolling_file_appender", "size_trigger"] +[[example]] +name = "log_to_file_with_rolling_and_time_trigger" +required-features = ["file_appender", "rolling_file_appender", "time_trigger"] + [[example]] name = "multi_logger_config" required-features = ["yaml_format", "config_parsing"] diff --git a/examples/log_to_file_with_rolling.rs b/examples/log_to_file_with_rolling_and_size_trigger.rs similarity index 100% rename from examples/log_to_file_with_rolling.rs rename to examples/log_to_file_with_rolling_and_size_trigger.rs diff --git a/examples/log_to_file_with_rolling_and_time_trigger.rs b/examples/log_to_file_with_rolling_and_time_trigger.rs new file mode 100644 index 00000000..89c32a1f --- /dev/null +++ b/examples/log_to_file_with_rolling_and_time_trigger.rs @@ -0,0 +1,113 @@ +//! Example showing how to use logging with a rolling trigger based on time +//! +//! NB: The interval used in the example is intentionally short so multiple file +//! will be created in the 6 seconds that the example is set to run and is not +//! intended for practical for usage + +/// This is the time config after which a new file should be created. For the demo +/// it is set to 2s which is very short and only for demo purposes +const TIME_TRIGGER_CONFIG: TimeTriggerConfig = TimeTriggerConfig { + interval: TimeTriggerInterval::Second(2), + max_random_delay: 0, + modulate: false, +}; + +/// Delay between log messages for demo purposes +const TIME_BETWEEN_LOG_MESSAGES: Duration = Duration::from_millis(10); + +/// Number of archive log files to keep +const LOG_FILE_COUNT: u32 = 3; + +/// Time demo is set to run for (Set to be long enough for multiple files to be created) +const RUN_TIME: Duration = Duration::from_secs(6); + +/// Location where logs will be written to +const FILE_PATH: &str = "/tmp/foo.log"; + +/// Location where log archives will be moved to +/// For Pattern info See: +/// https://docs.rs/log4rs/*/log4rs/append/rolling_file/policy/compound/roll/fixed_window/struct.FixedWindowRollerBuilder.html#method.build +const ARCHIVE_PATTERN: &str = "/tmp/archive/foo.{}.log"; + +use std::{ + thread::sleep, + time::{Duration, Instant}, +}; + +use log::{debug, error, info, trace, warn, LevelFilter, SetLoggerError}; +use log4rs::{ + append::{ + console::{ConsoleAppender, Target}, + rolling_file::policy::compound::{ + roll::fixed_window::FixedWindowRoller, + trigger::time::{TimeTrigger, TimeTriggerConfig, TimeTriggerInterval}, + CompoundPolicy, + }, + }, + config::{Appender, Config, Root}, + encode::pattern::PatternEncoder, + filter::threshold::ThresholdFilter, +}; + +fn main() -> Result<(), SetLoggerError> { + let level = log::LevelFilter::Info; + + // Build a stderr logger. + let stderr = ConsoleAppender::builder().target(Target::Stderr).build(); + + let trigger = TimeTrigger::new(TIME_TRIGGER_CONFIG); + let roller = FixedWindowRoller::builder() + .base(0) // Default Value (line not needed unless you want to change from 0 (only here for demo purposes) + .build(ARCHIVE_PATTERN, LOG_FILE_COUNT) // Roll based on pattern and max 3 archive files + .unwrap(); + let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller)); + + // Logging to log file. (with rolling) + let logfile = log4rs::append::rolling_file::RollingFileAppender::builder() + // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html + .encoder(Box::new(PatternEncoder::new("{l} - {m}\n"))) + .build(FILE_PATH, Box::new(policy)) + .unwrap(); + + // Log Trace level output to file where trace is the default level + // and the programmatically specified level to stderr. + let config = Config::builder() + .appender(Appender::builder().build("logfile", Box::new(logfile))) + .appender( + Appender::builder() + .filter(Box::new(ThresholdFilter::new(level))) + .build("stderr", Box::new(stderr)), + ) + .build( + Root::builder() + .appender("logfile") + .appender("stderr") + .build(LevelFilter::Trace), + ) + .unwrap(); + + // Use this to change log levels at runtime. + // This means you can change the default log level to trace + // if you are trying to debug an issue and need more logs on then turn it off + // once you are done. + let _handle = log4rs::init_config(config)?; + + error!("Goes to stderr and file"); + warn!("Goes to stderr and file"); + info!("Goes to stderr and file"); + debug!("Goes to file only"); + trace!("Goes to file only"); + + // Generate some log messages to trigger rolling + let instant = Instant::now(); + while instant.elapsed() < RUN_TIME { + info!("Running for {:?}", instant.elapsed()); + sleep(TIME_BETWEEN_LOG_MESSAGES); + } + info!( + "See '{}' for log and '{}' for archived logs", + FILE_PATH, ARCHIVE_PATTERN + ); + + Ok(()) +} diff --git a/src/append/rolling_file/policy/compound/trigger/time.rs b/src/append/rolling_file/policy/compound/trigger/time.rs index 4568a524..8b7ae7c3 100644 --- a/src/append/rolling_file/policy/compound/trigger/time.rs +++ b/src/append/rolling_file/policy/compound/trigger/time.rs @@ -23,9 +23,12 @@ use crate::config::{Deserialize, Deserializers}; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default, serde::Deserialize)] #[serde(deny_unknown_fields)] pub struct TimeTriggerConfig { + /// The date/time interval between log file rolls. interval: TimeTriggerInterval, + /// Whether to modulate the interval. #[serde(default)] modulate: bool, + /// The maximum random delay in seconds. #[serde(default)] max_random_delay: u64, } @@ -34,9 +37,12 @@ pub struct TimeTriggerConfig { /// Configuration for the time trigger. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct TimeTriggerConfig { - interval: TimeTriggerInterval, - modulate: bool, - max_random_delay: u64, + /// The date/time interval between log file rolls.Q + pub interval: TimeTriggerInterval, + /// Whether to modulate the interval. + pub modulate: bool, + /// The maximum random delay in seconds. + pub max_random_delay: u64, } /// A trigger which rolls the log once it has passed a certain time.