1个不稳定版本

0.0.0 2019年6月27日

#93#logging-tracing

Download history 16/week @ 2024-03-25 40/week @ 2024-04-01 10/week @ 2024-04-08 15/week @ 2024-04-15 21/week @ 2024-04-22 114/week @ 2024-04-29 23/week @ 2024-05-06 23/week @ 2024-05-13 70/week @ 2024-05-20 24/week @ 2024-05-27 13/week @ 2024-06-03 18/week @ 2024-06-10 14/week @ 2024-06-17 21/week @ 2024-06-24 13/week @ 2024-07-08

53 每月下载量
2 crates 中使用

MIT 协议

2KB

Tracing — Structured, application-level diagnostics

Crates.io Documentation Documentation (master) MIT licensed Build Status Discord chat

网站 | 聊天 | 文档(master分支)

master分支是tracing的预发布、开发版本。请参阅tracing发布到crates.io的版本v0.1.x分支。

概述

tracing是一个用于收集结构化、基于事件的诊断信息的框架。虽然tracing由Tokio项目维护,但需要使用tokio运行时。

用法

在应用程序中

为了记录跟踪事件,可执行文件必须使用与tracing兼容的收集器实现。收集器实现了一种收集跟踪数据的方式,例如通过将其记录到标准输出。 tracing-subscriberfmt模块提供了一个合理的默认值来记录跟踪数据的收集器。此外,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 构建的兼容性和工具库。其中一些库处于预发布状态,稳定性不如 tracingtracing-core 库。

Tracing 包含的库有

除了这个存储库之外,还有一些由 tokio 项目不维护的第三方库。这些包括

  • tracing-timingtracing 的基础上实现事件间时间度量。它提供了一个订阅者,用于记录一对 tracing 事件之间的时间差并生成直方图。
  • tracing-honeycomb 提供了一个层,用于将跨越多台机器的跟踪报告发送到 honeycomb.io。由 tracing-distributed 支持。
  • tracing-distributed 提供了一个通用的层实现,将跨越多台机器的跟踪报告发送到某个后端。
  • tracing-actix-webactix-web 网络框架提供 tracing 集成。
  • tracing-actixactix 演员(actor)框架提供 tracing 集成。
  • axum-insightsaxum 网络框架提供 tracing 集成和应用洞察导出。
  • tracing-gelf 实现了一个订阅者,用于以 Greylog GELF 格式导出跟踪信息。
  • tracing-coz 提供了与 Linux 上的 coz 因果分析器(causal profiler)的集成。
  • tracing-bunyan-formatter 提供了一个层实现,用于以 bunyan 格式报告事件和跨度,并添加了时间信息。
  • tide-tracingtide 中间件提供跟踪所有传入请求和响应的功能。
  • color-spantrace 提供了一个格式化程序,用于以 color-backtrace 风格渲染跨度跟踪。
  • color-eyreeyre::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 提供了便利方法,用于在 ResultOption 类型上报告失败的 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 仍处于未发布状态,并正在积极开发中。它们可能比 tracingtracing-core 稳定度低。

外部资源

这是一个关于跟踪的博客文章、会议演讲和教程的链接列表。

博客文章

演讲

帮助我们扩展这个列表!如果您已经撰写或讨论了追踪,或者知道未列出的资源,请提交一个pull请求添加它们。

许可证

本项目受MIT许可证的许可。

贡献

除非您明确说明,否则您提交给Tracing以供包含的贡献将被许可为MIT,不附加任何额外条款或条件。

无运行时依赖