#rotate #log #rotation #logging #logrotate #log-line

file-rotate-record-boundary

Please see 'file-rotate' instead. ( This is a fork with changes needed by Polyverse until the upstream PR has been marged. https://github.com/BourgondAries/file-rotate/pull/3

1 unstable release

0.3.0 Aug 4, 2020

#6 in #logrotate

LGPL-3.0-or-later

16KB
213 lines

DEPRECATION NOTICE

Please note that this repository has been deprecated and is no longer actively maintained by Polyverse Corporation. It may be removed in the future, but for now remains public for the benefit of any users.

Importantly, as the repository has not been maintained, it may contain unpatched security issues and other critical issues. Use at your own risk.

While it is not maintained, we would graciously consider any pull requests in accordance with our Individual Contributor License Agreement. https://github.com/polyverse/contributor-license-agreement

For any other issues, please feel free to contact info@polyverse.com


Build Status

file-rotate

Supports a Write or AsyncWrite trait over files whereby the underlying file can be rotated on various thresholds. USeful for logging.


lib.rs:

Write output to a file and rotate the files when limits have been exceeded.

Defines a simple std::io::Write object that you can plug into your writers as middleware.

Rotating by Lines

We can rotate log files by using the amount of lines as a limit.

use file_rotate::{FileRotate, RotationMode};
use std::{fs, io::Write};

// Create a directory to store our logs, this is not strictly needed but shows how we can
// arbitrary paths.
fs::create_dir("target/my-log-directory-lines");

// Create a new log writer. The first argument is anything resembling a path. The
// basename is used for naming the log files.
//
// Here we choose to limit logs by 10 lines, and have at most 2 rotated log files. This
// makes the total amount of log files 4, since the original file is present as well as
// file 0.
let mut log = FileRotate::new("target/my-log-directory-lines/my-log-file", RotationMode::Lines(3), 2);

// Write a bunch of lines
writeln!(log, "Line 1: Hello World!");
for idx in 2..11 {
    writeln!(log, "Line {}", idx);
}

assert_eq!("Line 10\n", fs::read_to_string("target/my-log-directory-lines/my-log-file").unwrap());

assert_eq!("Line 1: Hello World!\nLine 2\nLine 3\n", fs::read_to_string("target/my-log-directory-lines/my-log-file.0").unwrap());
assert_eq!("Line 4\nLine 5\nLine 6\n", fs::read_to_string("target/my-log-directory-lines/my-log-file.1").unwrap());
assert_eq!("Line 7\nLine 8\nLine 9\n", fs::read_to_string("target/my-log-directory-lines/my-log-file.2").unwrap());

fs::remove_dir_all("target/my-log-directory-lines");

Rotating by Bytes

Another method of rotation is by bytes instead of lines.

use file_rotate::{FileRotate, RotationMode};
use std::{fs, io::Write};

fs::create_dir("target/my-log-directory-bytes");

let mut log = FileRotate::new("target/my-log-directory-bytes/my-log-file", RotationMode::Bytes(5), 2);

writeln!(log, "Test file");

assert_eq!("Test ", fs::read_to_string("target/my-log-directory-bytes/my-log-file.0").unwrap());
assert_eq!("file\n", fs::read_to_string("target/my-log-directory-bytes/my-log-file").unwrap());

fs::remove_dir_all("target/my-log-directory-bytes");

Rotation Method

The rotation method used is to always write to the base path, and then move the file to a new location when the limit is exceeded. The moving occurs in the sequence 0, 1, 2, n, 0, 1, 2...

Here's an example with 1 byte limits:

use file_rotate::{FileRotate, RotationMode};
use std::{fs, io::Write};

fs::create_dir("target/my-log-directory-small");

let mut log = FileRotate::new("target/my-log-directory-small/my-log-file", RotationMode::Bytes(1), 3);

write!(log, "A");
assert_eq!("A", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());

write!(log, "B");
assert_eq!("A", fs::read_to_string("target/my-log-directory-small/my-log-file.0").unwrap());
assert_eq!("B", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());

write!(log, "C");
assert_eq!("A", fs::read_to_string("target/my-log-directory-small/my-log-file.0").unwrap());
assert_eq!("B", fs::read_to_string("target/my-log-directory-small/my-log-file.1").unwrap());
assert_eq!("C", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());

write!(log, "D");
assert_eq!("A", fs::read_to_string("target/my-log-directory-small/my-log-file.0").unwrap());
assert_eq!("B", fs::read_to_string("target/my-log-directory-small/my-log-file.1").unwrap());
assert_eq!("C", fs::read_to_string("target/my-log-directory-small/my-log-file.2").unwrap());
assert_eq!("D", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());

write!(log, "E");
assert_eq!("A", fs::read_to_string("target/my-log-directory-small/my-log-file.0").unwrap());
assert_eq!("B", fs::read_to_string("target/my-log-directory-small/my-log-file.1").unwrap());
assert_eq!("C", fs::read_to_string("target/my-log-directory-small/my-log-file.2").unwrap());
assert_eq!("D", fs::read_to_string("target/my-log-directory-small/my-log-file.3").unwrap());
assert_eq!("E", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());


// Here we overwrite the 0 file since we're out of log files, restarting the sequencing
write!(log, "F");
assert_eq!("E", fs::read_to_string("target/my-log-directory-small/my-log-file.0").unwrap());
assert_eq!("B", fs::read_to_string("target/my-log-directory-small/my-log-file.1").unwrap());
assert_eq!("C", fs::read_to_string("target/my-log-directory-small/my-log-file.2").unwrap());
assert_eq!("D", fs::read_to_string("target/my-log-directory-small/my-log-file.3").unwrap());
assert_eq!("F", fs::read_to_string("target/my-log-directory-small/my-log-file").unwrap());

fs::remove_dir_all("target/my-log-directory-small");

Filesystem Errors

If the directory containing the logs is deleted or somehow made inaccessible then the rotator will simply continue operating without fault. When a rotation occurs, it attempts to open a file in the directory. If it can, it will just continue logging. If it can't then the written date is sent to the void.

This logger never panics.

No runtime deps