Skip to main content

rolling_file_appender/
rolling_file_appender.rs

1//! Demonstrates size-based log rotation with gzip compression: with a small
2//! `max_size`, the current file is rolled over to a timestamped sibling once
3//! the next line would exceed the limit, and rotated files are gzipped.
4
5use std::io::Read;
6
7use flate2::read::GzDecoder;
8use log4rc::{FileAppender, LogLevel, Logger, SimpleLayout};
9
10fn main() {
11    let dir = std::env::temp_dir();
12    let prefix = format!("log4rc-rolling-{}", std::process::id());
13    let log_path = dir.join(format!("{prefix}.log"));
14
15    Logger::builder(LogLevel::Info)
16        .appender(Box::new(
17            FileAppender::builder(&log_path, Box::new(SimpleLayout))
18                .max_size(100) // tiny limit so a few messages trigger a roll
19                .max_files(3) // keep only the 3 newest rotated files
20                .compressed() // gzip rotated files
21                .build()
22                .expect("failed to open log file"),
23        ))
24        .init();
25
26    for i in 0..10 {
27        log4rc::info!("This is message number {i:02} with some padding to grow the file");
28    }
29
30    // List the active file plus any rotated siblings.
31    let mut files: Vec<_> = std::fs::read_dir(&dir)
32        .unwrap()
33        .flatten()
34        .map(|e| e.path())
35        .filter(|p| {
36            p.file_name()
37                .and_then(|n| n.to_str())
38                .is_some_and(|n| n.starts_with(&prefix))
39        })
40        .collect();
41    files.sort();
42
43    println!("--- Log files ---");
44    let mut total_lines = 0;
45    for path in &files {
46        let contents = if path.to_string_lossy().ends_with(".gz") {
47            let mut contents = String::new();
48            let file = std::fs::File::open(path).expect("failed to open rotated file");
49            GzDecoder::new(file)
50                .read_to_string(&mut contents)
51                .expect("failed to decompress rotated file");
52            contents
53        } else {
54            std::fs::read_to_string(path).expect("failed to read log file")
55        };
56        let lines = contents.lines().count();
57        total_lines += lines;
58        println!("{} ({} lines):", path.display(), lines);
59    }
60    println!("total lines across files: {total_lines}");
61
62    for path in files {
63        let _ = std::fs::remove_file(path);
64    }
65}