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..f170fa1d --- /dev/null +++ b/examples/log_to_file_with_rolling_and_time_trigger.rs @@ -0,0 +1,117 @@ +//! Example showing how to use logging with a rolling trigger based on size +//! +//! NB: The size used in the example is intentionally small so multiple file +//! will be created in the 2 seconds that the example is set to run and is not +//! intended for practical for usage + +/// This is the size at which a new file should be created. For the demo it is +/// set to 2s which is very small 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(); + + // Create a policy to use with the file logging + // let time_trigger_config = TimeTriggerConfig { + // interval: Duration::from_secs(1), + // delay: Duration::from_secs(0), + // modulate: false, + // }; + 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.