1个不稳定版本
0.0.0 | 2019年6月27日 |
---|
#93 在 #logging-tracing
53 每月下载量
在 2 crates 中使用
2KB
网站 | 聊天 | 文档(master分支)
master分支是tracing
的预发布、开发版本。请参阅tracing
发布到crates.io的版本v0.1.x分支。
概述
tracing
是一个用于收集结构化、基于事件的诊断信息的框架。虽然tracing
由Tokio项目维护,但不需要使用tokio
运行时。
用法
在应用程序中
为了记录跟踪事件,可执行文件必须使用与tracing
兼容的收集器实现。收集器实现了一种收集跟踪数据的方式,例如通过将其记录到标准输出。 tracing-subscriber
的fmt
模块提供了一个合理的默认值来记录跟踪数据的收集器。此外,tracing-subscriber
能够消费由log
工具库和模块发出的消息。
要使用tracing-subscriber
,请将以下内容添加到您的Cargo.toml
[dependencies]
tracing = "0.1"
tracing-subscriber = "0.3"
然后创建并安装一个收集器,例如使用init()
use tracing::info;
use tracing_subscriber;
fn main() {
// install global collector configured based on RUST_LOG env var.
tracing_subscriber::fmt::init();
let number_of_yaks = 3;
// this creates a new event, outside of any spans.
info!(number_of_yaks, "preparing to shave yaks");
let number_shaved = yak_shave::shave_all(number_of_yaks);
info!(
all_yaks_shaved = number_shaved == number_of_yaks,
"yak shaving completed."
);
}
使用init()
调用set_global_default()
,因此这个收集器将在程序剩余时间内作为所有线程的默认值使用,类似于在log
包中的日志记录器。
为了获得更多控制,可以逐步构建收集器而不是全局设置,而是用于局部覆盖默认收集器。例如
use tracing::{info, Level};
use tracing_subscriber;
fn main() {
let collector = tracing_subscriber::fmt()
// filter spans/events with level TRACE or higher.
.with_max_level(Level::TRACE)
// build but do not install the subscriber.
.finish();
tracing::collect::with_default(collector, || {
info!("This will be logged to stdout");
});
info!("This will _not_ be logged to stdout");
}
在收集器上下文之外生成的任何跟踪事件都不会被收集。
这种方法允许在程序的不同上下文中由多个收集器收集跟踪数据。请注意,覆盖仅适用于当前正在执行的线程;其他线程不会看到with_default
中的更改。
一旦设置了收集器,就可以使用tracing
包的宏将仪器点添加到可执行文件中。
在库中
库应仅依赖于 tracing
包,并使用提供的宏和类型来收集对下游消费者可能有用的任何信息。
use std::{error::Error, io};
use tracing::{debug, error, info, span, warn, Level};
// the `#[tracing::instrument]` attribute creates and enters a span
// every time the instrumented function is called. The span is named after
// the function or method. Parameters passed to the function are recorded as fields.
#[tracing::instrument]
pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
// this creates an event at the DEBUG level with two fields:
// - `excitement`, with the key "excitement" and the value "yay!"
// - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
//
// unlike other fields, `message`'s shorthand initialization is just the string itself.
debug!(excitement = "yay!", "hello! I'm gonna shave a yak.");
if yak == 3 {
warn!("could not locate yak!");
// note that this is intended to demonstrate `tracing`'s features, not idiomatic
// error handling! in a library or application, you should consider returning
// a dedicated `YakError`. libraries like snafu or thiserror make this easy.
return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into());
} else {
debug!("yak shaved successfully");
}
Ok(())
}
pub fn shave_all(yaks: usize) -> usize {
// Constructs a new span named "shaving_yaks" at the TRACE level,
// and a field whose key is "yaks". This is equivalent to writing:
//
// let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks);
//
// local variables (`yaks`) can be used as field values
// without an assignment, similar to struct initializers.
let span = span!(Level::TRACE, "shaving_yaks", yaks);
let _enter = span.enter();
info!("shaving yaks");
let mut yaks_shaved = 0;
for yak in 1..=yaks {
let res = shave(yak);
debug!(yak, shaved = res.is_ok());
if let Err(ref error) = res {
// Like spans, events can also use the field initialization shorthand.
// In this instance, `yak` is the field being initialized.
error!(yak, error = error.as_ref(), "failed to shave yak!");
} else {
yaks_shaved += 1;
}
debug!(yaks_shaved);
}
yaks_shaved
}
[dependencies]
tracing = "0.1"
注意:库不应通过调用 set_global_default()
方法安装收集器,因为这将在可执行文件尝试稍后设置默认值时引起冲突。
异步代码
要跟踪 async fn
,首选方法是使用 #[instrument]
属性
use tracing::{info, instrument};
use tokio::{io::AsyncWriteExt, net::TcpStream};
use std::io;
#[instrument]
async fn write(stream: &mut TcpStream) -> io::Result<usize> {
let result = stream.write(b"hello world\n").await;
info!("wrote to stream; success={:?}", result.is_ok());
result
}
对于使用 std::future::Future
或带有 async
/await
块的代码的一般情况,需要特殊处理,因为以下示例 不会 工作
async {
let _s = span.enter();
// ...
}
范围保护器 _s
将在由 async
块生成的未来完成之前不会退出。由于未来和范围可以在它们完成之前多次进入和退出,因此范围将保持进入状态,直到未来存在,而不是只在它被轮询时进入,导致非常混乱和错误的结果。有关更多详细信息,请参阅 关闭范围文档。
可以使用 Future::instrument
组合器来解决这个问题
use tracing::Instrument;
let my_future = async {
// ...
};
my_future
.instrument(tracing::info_span!("my_future"))
.await
Future::instrument
将范围附加到未来,确保范围的生命周期与未来的生命周期相同。
在内部,#[instrument]
宏执行与 Future::instrument
相同的显式范围附加操作。
支持的 Rust 版本
Tracing 是针对最新的稳定版本构建的。最低支持版本是 1.63。当前 Tracing 版本不一定能在低于最低支持版本的 Rust 版本上构建。
Tracing 遵循 Tokio 项目中其余部分的编译器支持策略。当前的稳定 Rust 编译器和它之前的三个最近的小版本将始终得到支持。例如,如果当前稳定编译器版本是 1.69,则最低支持版本不会增加到 1.66 之前的三个小版本。只要这样做符合此政策,增加最低支持编译器版本不被视为 semver 破坏性更改。
获取帮助
首先,查看您的答案是否可以在 API 文档中找到。如果答案不在那里,Tracing Discord 频道 中有一个活跃的社区。我们很乐意尝试回答您的问题。最后,如果那也不行,尝试打开一个 问题。
贡献
🎈 感谢您帮助我们改进项目!我们非常高兴有您的参与!我们有一个贡献指南,帮助您参与追踪项目。
项目布局
tracing
库包含主要的 instrumentation API,用于对库和应用程序进行仪器化,以发出追踪数据。 tracing-core
库包含 核心 API 原语,其余的 tracing
都是基于这些原语进行仪器化的。追踪订阅者的作者可能依赖于 tracing-core
,这保证了更高的稳定性。
此外,此存储库还包含了一些基于 tracing
构建的兼容性和工具库。其中一些库处于预发布状态,稳定性不如 tracing
和 tracing-core
库。
Tracing 包含的库有
-
tracing-futures
:用于仪器化futures
的实用程序。(crates.io|文档) -
tracing-macros
:用于发出追踪事件的实验性宏(不稳定)。 -
tracing-attributes
:用于自动仪器化函数的进程宏属性。(crates.io|文档) -
tracing-log
:与log
库的兼容性(不稳定)。 -
tracing-serde
:与serde
的兼容层,用于序列化追踪数据(不稳定)。 -
tracing-subscriber
:收集器实现,以及实现和组合Collector
的实用程序。(crates.io|文档) -
tracing-tower
:与tower
生态系统的兼容性(不稳定)。 -
tracing-appender
:输出追踪数据的实用程序,包括文件追加器和非阻塞写入器。(crates.io|文档) -
tracing-error
:提供SpanTrace
类型,用于使用追踪跨度仪器化错误 -
tracing-flame
;提供基于追踪跨度进入/退出事件的火焰图生成层。 -
tracing-journald
:提供将事件记录到 Linuxjournald
服务并保留结构化数据的层。
相关库
除了这个存储库之外,还有一些由 tokio
项目不维护的第三方库。这些包括
tracing-timing
在tracing
的基础上实现事件间时间度量。它提供了一个订阅者,用于记录一对tracing
事件之间的时间差并生成直方图。tracing-honeycomb
提供了一个层,用于将跨越多台机器的跟踪报告发送到 honeycomb.io。由tracing-distributed
支持。tracing-distributed
提供了一个通用的层实现,将跨越多台机器的跟踪报告发送到某个后端。tracing-actix-web
为actix-web
网络框架提供tracing
集成。tracing-actix
为actix
演员(actor)框架提供tracing
集成。axum-insights
为axum
网络框架提供tracing
集成和应用洞察导出。tracing-gelf
实现了一个订阅者,用于以 Greylog GELF 格式导出跟踪信息。tracing-coz
提供了与 Linux 上的 coz 因果分析器(causal profiler)的集成。tracing-bunyan-formatter
提供了一个层实现,用于以 bunyan 格式报告事件和跨度,并添加了时间信息。tide-tracing
为tide
中间件提供跟踪所有传入请求和响应的功能。color-spantrace
提供了一个格式化程序,用于以color-backtrace
风格渲染跨度跟踪。color-eyre
为eyre::Report
提供了自定义的恐慌和 eyre 报告处理器,用于捕获带有新错误和格式化打印的跨度跟踪和回溯。spandoc
提供了一个进程宏,用于从函数内部的文档注释中构建跨度。tracing-wasm
提供了一个Collector
/Subscriber
实现,通过浏览器console.log
和 用户时间 API (window.performance
) 报告事件和跨度。tracing-web
提供了一个层实现,将事件以不同级别记录到网页浏览器的console.*
以及跨度事件记录到 用户时间 API (window.performance
)。test-log
根据环境变量和与env_logger
兼容的语法初始化测试中的tracing
。tracing-unwrap
提供了便利方法,用于在Result
或Option
类型上报告失败的 unwraps 到Collector
。diesel-tracing
提供了与diesel
数据库连接的集成。tracing-tracy
提供了一种在受监测的应用程序中收集 Tracy 配置文件的方法。tracing-elastic-apm
提供了一个向 Elastic APM 报告跟踪的层。tracing-etw
提供了一个发射 Windows ETW 事件的层。sentry-tracing
提供了一个向 Sentry 报告事件和跟踪的层。tracing-forest
提供了一个订阅者,通过在写入时将来自相同 span 的日志分组在一起,以保持上下文一致性。tracing-loki
提供了一个将日志发送到 Grafana Loki 的层。tracing-logfmt
提供了一个将事件和 span 格式化为 logfmt 格式的层。tracing-chrome
提供了一个可以用于在chrome://tracing
中查看的层。reqwest-tracing
提供了一个中间件,用于跟踪reqwest
HTTP 请求。tracing-cloudwatch
提供了一个将事件发送到 AWS CloudWatch 日志的层。clippy-tracing
提供了一个用于添加、删除和检查tracing::instrument
的工具。
(如果你是这个列表中未列出的 tracing
生态系统 crate 的维护者,请告诉我们!)
注意: 目前,一些生态系统 crate 仍处于未发布状态,并正在积极开发中。它们可能比 tracing
和 tracing-core
稳定度低。
外部资源
这是一个关于跟踪的博客文章、会议演讲和教程的链接列表。
博客文章
- 在 Tokio 博客上使用跟踪进行诊断,2019 年 8 月
- 在 Rust 应用程序中进行生产级日志记录,2020 年 11 月
- 使用
tracing
和tracing-subscriber
在 Rust 中进行自定义日志记录,第一部分 和 第二部分,2021 年 10 月 - 对 Axum 项目进行仪器化,2023 年 8 月
演讲
- 湾区 Rust Meetup 演讲和问答,2019 年 3 月
- RustConf 2019 演讲 和 幻灯片,2019 年 8 月
- 我们是否已经被观察到?@ RustyDays 讲座 和 幻灯片,2020年8月
- 带着仪器的蟹!,2021年9月
帮助我们扩展这个列表!如果您已经撰写或讨论了追踪,或者知道未列出的资源,请提交一个pull请求添加它们。
许可证
本项目受MIT许可证的许可。
贡献
除非您明确说明,否则您提交给Tracing以供包含的贡献将被许可为MIT,不附加任何额外条款或条件。