3

I am trying to build a logger based on a rolling policy. Below is the closest I was able to implement:

let logfile = FileAppender::builder()
    .encoder(Box::new(PatternEncoder::new("{d} {l}::{m}{n}")))
    .build("log/output.log")?;

let config = Config::builder()
    .appender(Appender::builder().build("logfile", Box::new(logfile)))
    .build(Root::builder()
                .appender("logfile")
                .build(LevelFilter::Debug))?;

log4rs::init_config(config)?;

This helped me log messages at all levels. However, logging to a file for a long time can be a dangerous proposition. Consequently, I am looking for something which can limit the amount of log data that's preserved. I came across RollingFileAppender, but I am not able to find the proper usage of Policy.

Please guide me through this. I am mostly looking for programmatic configuration.

ravi
  • 10,994
  • 1
  • 18
  • 36

1 Answers1

10

You can implement it via using RollingFileAppender CompoundPolicy , FixedWindowRoller and SizeTrigger from log4rs crate.

You need to implement the followings in order to create your rolling file logic:

  1. FixedWindowRoller

Specify FixedWindowRoller to roll your log file in a fixed window_size like following:

let window_size = 3; // log0, log1, log2
let fixed_window_roller = 
FixedWindowRoller::builder().build("log{}",window_size).unwrap();
  1. SizeTrigger

Specify SizeTrigger to declare the size limit of the file to trigger the Roller like following:

let size_limit = 5 * 1024; // 5KB as max log file size to roll
let size_trigger = SizeTrigger::new(size_limit);
  1. CompoundPolicy

Declare CompoundPolicy to use it in RollingFileAppender like following:

let compound_policy = CompoundPolicy::new(Box::new(size_trigger),Box::new(fixed_window_roller));

Then in your Config, you need to use RollingFileAppender in order to get desired behavior.

let config = Config::builder()
    .appender(
        Appender::builder()
            .filter(Box::new(ThresholdFilter::new(LevelFilter::Debug)))
            .build(
                "logfile",
                Box::new(
                    RollingFileAppender::builder()
                        .encoder(Box::new(PatternEncoder::new("{d} {l}::{m}{n}")))
                        .build("logfile", Box::new(compound_policy))?,
                ),
            ),
    )
    .build(
        Root::builder()
            .appender("logfile")
            .build(LevelFilter::Debug),
    )?;

With this implementation, you get a rolling file for the window size 3 and the roll size 5KB


If you want to compress the rolled files you can define this in your roller file extension. Instead of log{}you can specify extension as log{}.gz

However, if you want to enable compression with the log files you need to enable this feature in your cargo.toml as following:

log4rs = { version ="1.0.0", features = ["gzip"] }

Note: If you want to have a custom roller and custom trigger for your own purpose, you can implement your own Trigger and Roller from the respective traits

Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68
  • This does not work for me--the output all gets written to a file called "logfile" as the path is one of the parameters for RollingFileAppender::builder().build( – jle Nov 16 '20 at 20:18
  • Unless the roller is used in addition to the primary log file? – jle Nov 16 '20 at 20:40
  • Ok it appears that there are two paths. Primary log file path "logfile" and then the rolling file path, which is the 'archive' path. It will fill up primary and then send to archive when that is full. – jle Nov 16 '20 at 20:51
  • @jle yes this is the main idea behind file rolling. You are handling these via 2 parameters as `window size` and `roll size` as I mention on the answer – Akiner Alkan Nov 17 '20 at 11:58