pub struct LogRingFile {
pub file_path: Box<Path>,
pub level: Level,
pub format: LogFormat,
pub buf_size: i32,
}ringfile only.Expand description
The LogRingFile sink is a way to minimize the cost of logging, for debugging deadlock or race condition, when the problem cannot be reproduce with ordinary log (because disk I/O will slow down the execution and prevent the bug to occur).
§Usage
Enable feature ringfile in your Cargo.toml.
Replace the log setup with the following recipe::ring_file() in your test case:
(Set the level to Info or higher, to turn off other debugging logs.)
use captains_log::*;
// the recipe already register signal and dynamic=true, do not use test(),
// because test() will clear the signal.
recipe::ring_file("/tmp/ring.log", 1024*1024, Level::Info,
signal_consts::SIGHUP).build().expect("log setup");§Debugging deadlocks
Then add some high-level log to critical path in the code, try to reproduce the problem, and reduce the amount of log if the bug not occur.
On start-up, it will create a limited-size ring-buffer-like memory. The log content will be held within memory but not written to disk, old logs will be overwritten by new ones. Until specified signal arrives, the last part of log message will be dumped to the file, in time order.
Once your program hangs up completely, find your process PID and send a signal to it.
kill -SIGHUP <pid>There will be messages printed to stdout:
RingFile: start dumping
RingFile: dump completeThe program will exit. Then you can inspect your log content on disk (for this example /tmp/ring.log).
A real-life debugging story can be found on https://github.com/frostyplanet/crossfire-rs/issues/24.
§Debugging assertions
When you debugging the reason of some unexpected assertions, it will automatically trigger the dump in our panic hook. If you want an explicit dump, you can call:
log::logger().flush();§NOTE
The backend is provided by RingFile crate. To ensure low latency, the data is handle in background thread backed by a unbounded channel. After the program hangs, or panic, log content can be safely copied from the buffer area to disk.
Be aware that it did not use mlock to prevent memory from being swapping. (Swapping might make the
code slow to prevent bug reproduction). When your memory is not enough, use a smaller buf_size and turn off the swap with swapoff -a.
The collected logs are from all the threads, including those exited. That means there might be very old contents mixed with newer contents. We suggest you log before thread exits. And also note that thread_id is reused after thread exits.
Fields§
§file_path: Box<Path>§level: Level§format: LogFormat§buf_size: i320 < buf_size < i32::MAX, note this is the buffer size within each thread.