log4rs icon indicating copy to clipboard operation
log4rs copied to clipboard

Added roll on launch for rolling file appenders

Open MaFeLP opened this issue 3 years ago • 12 comments

Adds an option to roll the log files on startup.

It is a different approach to @OvermindDL1's #219.


Usage Examples

with yaml:

refresh_rate: 30 seconds

appenders:
  stderr:
    kind: console
    target: stderr
  logfile:
    kind: rolling_file
    path: logs/log-0.log
    encoder:
      pattern: "{l} - {m}\n"
    policy:
      kind: compound
      trigger:
        kind: size
        limit: 10 mb
      roller: &roll
        kind: fixed_window
        pattern: "logs/log-{}.log"
        base: 1
        count: 5
    roll_on_startup: true

root:
  level: info
  appenders:
    - stdout
    - logfile

programmatically

use log::{debug, error, info, trace, warn, LevelFilter, SetLoggerError};
use log4rs::append::rolling_file::{
    policy::compound::{
        roll::fixed_window::FixedWindowRoller, trigger::size::SizeTrigger, CompoundPolicy,
    },
    RollingFileAppender,
};
use log4rs::{
    append::console::{ConsoleAppender, Target},
    config::{Appender, Config, Root},
    encode::pattern::PatternEncoder,
    filter::threshold::ThresholdFilter,
};

fn main() -> Result<(), SetLoggerError> {
    let level = log::LevelFilter::Info;
    let file_path = "logs/latest.log";

    let stderr = ConsoleAppender::builder().target(Target::Stderr).build();

    let logfile = RollingFileAppender::builder()
        // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html
        .encoder(Box::new(PatternEncoder::new("{l} - {m}\n")))
        .roll_on_startup(true)
        .build(
            file_path,
            Box::new(CompoundPolicy::new(
                Box::new(SizeTrigger::new(10_000_000)),
                Box::new(
                    FixedWindowRoller::builder()
                        .build("logs/log-{}.log", 5)
                        .unwrap(),
                ),
            )),
        )
        .unwrap();

    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();

    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");

    Ok(())
}

MaFeLP avatar Apr 03 '22 20:04 MaFeLP

@MaFeLP I will try to review this asap, thanks for your contribution.

estk avatar Apr 20 '22 14:04 estk

So there is some CI to fix, and I think I would prefer a more expository name what do you think about roll_on_startup? Also I think its important that the roll_on_startup be the same as the normal roller and so should probably just be a bool.

estk avatar Apr 21 '22 06:04 estk

I should have fixed the CI, but I discovered a bug when running the implementation multiple times, as the rolling is kind of weird. I will investigate this further tomorrow.

MaFeLP avatar Apr 22 '22 20:04 MaFeLP

@MaFeLP acknowledged, would you add a test for that please?

estk avatar Apr 22 '22 20:04 estk

@MaFeLP bump, lets get this over the finish line!

estk avatar Apr 30 '22 03:04 estk

Working on it. I am currently investigating the issue... It seems to come from nowhere?

MaFeLP avatar Apr 30 '22 23:04 MaFeLP

@estk Should be fixed now 😉

Could you start the CI for test?

MaFeLP avatar May 01 '22 18:05 MaFeLP

Ok, so I looked into the test failing, and turns out, it fails because the background rotation thread is not finished rotating the log files. The test thread then tries to compare not-yet-rolled files' contents to the output that is requested. Because the log file is not rotated yet, the contents will differ.

This can be seen, if the following line is added in line 633 in src/append/rolling_file/mod.rs:

        std::thread::sleep(std::time::Duration::from_secs(5));

I currently only see three solutions, on how to fix this test:

  1. Disable this test, when the background_rotation feature is on (would 'defeat' the purpose of the test) or
  2. Sleep the test thread for a certain amount of time. This would a. increase the time needed to run the tests and b. might cause the test to fail on slower or single thread machines, that suspend the rolling thread not long enough, so that the test thread can compare them.
  3. Modify the FixedWindowRoller (feature: background_rotation) class to report when the rolling is finished.

PS: Sorry for the long break :/

MaFeLP avatar May 21 '22 21:05 MaFeLP

I think we should go with 3. but let's be sure to gate it on #[cfg(test)]

estk avatar May 22 '22 14:05 estk

Ok, I think I found a good workaround. Ran the tests in a VM and everything seems to be passing!

MaFeLP avatar May 22 '22 21:05 MaFeLP

@estk Is this still under review? If so, is there anything I can do for you?

MaFeLP avatar Jun 23 '22 19:06 MaFeLP

Hey @estk! Are you still reviewing this? If there is anything I can help with, just let me know!

MaFeLP avatar Jul 27 '22 15:07 MaFeLP