9个版本
新 0.11.0-alpha.9 | 2024年8月21日 |
---|---|
0.11.0-alpha.8 | 2024年8月15日 |
0.11.0-alpha.7 | 2024年7月31日 |
0.11.0-alpha.6 | 2024年6月28日 |
#496 in 调试
366 每月下载量
250KB
5K SLoC
emit_file
向滚动文件中发出诊断事件。
lib.rs
:
向滚动文件中发出诊断事件。
所有文件I/O都在一个专用的后台线程中按批执行。
此库默认以换行符分隔的JSON写入,例如
{"ts_start":"2024-05-29T03:35:13.922768000Z","ts":"2024-05-29T03:35:13.943506000Z","module":"my_app","msg":"in_ctxt failed with `a` is odd","tpl":"in_ctxt failed with `err`","a":1,"err":"`a` is odd","lvl":"warn","span_id":"0a3686d1b788b277","span_parent":"1a50b58f2ef93f3b","trace_id":"8dd5d1f11af6ba1db4124072024933cb"}
入门
将 emit
和 emit_file
添加到您的 Cargo.toml
[dependencies.emit]
version = "0.11.0-alpha.9"
[dependencies.emit_file]
version = "0.11.0-alpha.9"
使用滚动文件集初始化 emit
fn main() {
let rt = emit::setup()
.emit_to(emit_file::set("./target/logs/my_app.txt").spawn().unwrap())
.init();
// Your app code goes here
rt.blocking_flush(std::time::Duration::from_secs(30));
}
[\code]set 的输入是日志文件命名的模板。前面示例中使用了 ./target/logs/my_app.txt
。从该模板,日志文件将写入 ./target/logs
,每个日志文件名将以 my_app
开头,并使用 .txt
作为其扩展名。
文件命名
日志文件使用以下命名方案创建
{prefix}.{date}.{counter}.{id}.{ext}
其中
prefix
: 一个用户定义的名称,用于将所有与同一应用程序相关的日志文件分组在一起。date
: 文件创建时所在的滚动间隔。这不一定与文件中事件的戳记有关。counter
: 文件创建时从当前滚动间隔开始以来的毫秒数。id
: 文件在该间隔中的唯一标识符。ext
: 一个用户定义的文件扩展名。
在以下日志文件中
log.2024-05-27-03-00.00012557.37c57fa1.txt
部分是
prefix
:log
.日期
:2024-05-27-03-00
。计数器
:00012557
。ID
:37c57fa1
。扩展名
:txt
。
当文件滚动时
诊断事件一次只写入一个文件。该文件在以下情况下会发生变化:
- 应用程序重启,并且
FileSetBuilder::reuse_files
为 false。 - 滚动周期改变。这由
FileSetBuilder::roll_by_day
、FileSetBuilder::roll_by_hour
和FileSetBuilder::roll_by_minute
设置。 - 文件大小超过
FileSetBuilder::max_file_size_bytes
。 - 写入文件失败。
持久性
诊断事件以异步批量的形式写入文件。在正常操作中,在调用 emit::Emitter::blocking_flush
之后,所有在调用之前发出的事件都将被确保写入并通过 Rust 的 std::fs::File::sync_all
方法进行同步。这通常足以保证持久性。
处理IO故障
如果在尝试写入文件时写入批处理失败,则正在写入的文件被视为已中毒,并且不会尝试再次写入。批处理将而是在新文件上重试。尝试同步失败的批处理不会重试。由于批处理没有显式的事务,在失败的情况下,可能实际上在原始文件中存在失败批处理的部分或全部。这意味着在写入诊断事件时可能发生IO错误,导致诊断事件重复。
故障排除
如果您没有看到诊断文件如预期的那样出现,可以通过配置 emit
的内部日志记录器来排除 emit_file
中的配置问题,并收集其指标
use emit::metric::Source;
fn main() {
// 1. Initialize the internal logger
// Diagnostics produced by `emit_file` itself will go here
let internal = emit::setup()
.emit_to(emit_term::stdout())
.init_internal();
let mut reporter = emit::metric::Reporter::new();
let rt = emit::setup()
.emit_to({
let files = emit_file::set("./target/logs/my_app.txt").spawn().unwrap();
// 2. Add `emit_file`'s metrics to a reporter so we can see what it's up to
// You can do this independently of the internal emitter
reporter.add_source(files.metric_source());
files
})
.init();
// Your app code goes here
rt.blocking_flush(std::time::Duration::from_secs(30));
// 3. Report metrics after attempting to flush
// You could also do this periodically as your application runs
reporter.emit_metrics(&internal.emitter());
}
诊断包括批处理写入的时间和观察到的任何失败。
依赖项
~1.4–2.1MB
~48K SLoC