如何使用追踪库?

Gun*_*t.r 28 rust rust-tracing

我这里有一个非常简单的代码示例,它只想获取我传入的列表的第一项。我一直在尝试通过跟踪来检测代码帮助调试应用程序,但坦率地说,文档太复杂了,我无法完全理解。

use std::fmt::Debug;
use tracing::{span, Level, event};

fn main() {
    pub fn calculate<T: Debug, const N: usize>(data_set: [T; N]) -> (i32, i32) {

        // Tracing BoilerPlate
        event!(Level::INFO, "something happened");
        let span = span!(Level::INFO, "my_span");
        let _guard = span.enter();
        
        // Key Code 
        let _var = data_set.get(0);
        println!("Output_1: {:?}", data_set.get(0)); 
        
        event!(Level::DEBUG, "something happened inside my_span");
        
        // Ignore
        return (0, 0)
    }

    let data = [1509, 1857, 1736, 1815, 1576];
    let _result = calculate(data);
}
Run Code Online (Sandbox Code Playgroud)

具体来说,我不明白在哪里可以查看event!日志。它们似乎没有打印到任何窗口或文件或任何东西。

有人可以指导我在哪里可以找到这些调试日志,或者为我提供如何使用跟踪箱的简化说明吗?

Gun*_*t.r 28

这是一个基本实现,tracing它使用名为的合作伙伴板条箱将信息输出到日志文件(存储库根目录中的 debug.log)和/或标准输出(带有更多代码)tracing-subscriber

要找到这些如何组合tracingtracing-subscriber组合的具体示例,您必须深入研究文档:转到tracing-subscribercrate,然后转到LayerTrait,然后转到Module level documentation. 这是一个替代链接。

坦率地说,该文档太复杂了,我无法完全理解。

我认为这两个箱子的文档还有大量工作要做。客观地讲,这并不能让初学者容易理解正在发生的事情。这些文档用高度复杂的语言描述了该板条箱,但未能正确地向新手传授基础知识。需要就此主题创建更完整的资源或快速入门指南。

可以使用更简单的调试工具,它们可以正确地教您如何使用它的 crateFlexi-logger提供了一个代码示例文档页面,它熟练地解释了如何使用 crate。Flexi-logger与 crate 协同工作Log以输出log files以及 tostdoutstderr

Here is the Tracing Implementation


use tracing_subscriber::{filter, prelude::*};
use std::{fs::File, sync::Arc};

// A layer that logs events to stdout using the human-readable "pretty"
// format.
fn main() {
    let stdout_log = tracing_subscriber::fmt::layer()
        .pretty();

    // A layer that logs events to a file.
    let file = File::create("debug.log");
    let file = match file  {Ok(file) => file,Err(error) => panic!("Error: {:?}",error),};
    let debug_log = tracing_subscriber::fmt::layer()
        .with_writer(Arc::new(file));

    // A layer that collects metrics using specific events.
    let metrics_layer = /* ... */ filter::LevelFilter::INFO;

    tracing_subscriber::registry()
        .with(
            stdout_log
                // Add an `INFO` filter to the stdout logging layer
                .with_filter(filter::LevelFilter::INFO)
                // Combine the filtered `stdout_log` layer with the
                // `debug_log` layer, producing a new `Layered` layer.
                .and_then(debug_log)
                // Add a filter to *both* layers that rejects spans and
                // events whose targets start with `metrics`.
                .with_filter(filter::filter_fn(|metadata| {
                    !metadata.target().starts_with("metrics")
                }))
        )
        .with(
            // Add a filter to the metrics label that *only* enables
            // events whose targets start with `metrics`.
            metrics_layer.with_filter(filter::filter_fn(|metadata| {
                metadata.target().starts_with("metrics")
            }))
        )
        .init();

    // This event will *only* be recorded by the metrics layer.
    tracing::info!(target: "metrics::cool_stuff_count", value = 42);

    // This event will only be seen by the debug log file layer:
    tracing::debug!("this is a message, and part of a system of messages");

    // This event will be seen by both the stdout log layer *and*
    // the debug log file layer, but not by the metrics layer.
    tracing::warn!("the message is a warning about danger!");

}
Run Code Online (Sandbox Code Playgroud)


kmd*_*eko 27

跟踪库本身不显示任何输出或写入任何文件。它只是一个外观,旨在允许开发人员以一种不可知的方式触发分组为跨度的事件,该方式与这些事件和跨度的处理方式分开。该库很复杂,因为有多种方法可以跟踪跨度和使用事件,并且需要在轻量级基础架构中支持它们。

然而,作为用户,您不需要真正担心这些。您需要做的就是使用trace!debug!info!warn!error!#[instrument]来描述您的代码正在做什么。然后,如果您正在编写一个应该对这些事件和跨度执行某些操作的程序,则应该设置一个Subscriber.

启动并运行将日志打印到控制台的最简单方法是使用跟踪订阅者箱中的基本格式订阅者,然后您将看到记录到控制台的事件:

use tracing::{info, debug};

#[tracing::instrument(ret)]
fn calculate(data_set: &[i32]) -> i32 {
    info!("starting calculations");

    let first = data_set.first();
    debug!("received {:?} as first element", first);
    
    let last = data_set.last();
    debug!("received {:?} as last element", last);

    first.unwrap_or(&0) + last.unwrap_or(&0)
}

fn main() {
    tracing_subscriber::fmt().init();

    // start running your code
    calculate(&[1509, 1857, 1736, 1815, 1576]);
}
Run Code Online (Sandbox Code Playgroud)
use tracing::{info, debug};

#[tracing::instrument(ret)]
fn calculate(data_set: &[i32]) -> i32 {
    info!("starting calculations");

    let first = data_set.first();
    debug!("received {:?} as first element", first);
    
    let last = data_set.last();
    debug!("received {:?} as last element", last);

    first.unwrap_or(&0) + last.unwrap_or(&0)
}

fn main() {
    tracing_subscriber::fmt().init();

    // start running your code
    calculate(&[1509, 1857, 1736, 1815, 1576]);
}
Run Code Online (Sandbox Code Playgroud)

这样fmt().init()可以让你快点出发;它的工作是创建一个Subscriber带有一堆合理默认值的文件,并将自己注册为全局订阅者。它也非常灵活,您可能会注意到上面的输出不包括事件debug!,并且您可能不关心在每条消息中显示板条箱名称。可以这样配置

tracing_subscriber::fmt()
    .with_max_level(tracing::Level::DEBUG)
    .with_target(false)
    .init();
Run Code Online (Sandbox Code Playgroud)
2022-09-15T16:11:47.830218Z  INFO calculate{data_set=[1509, 1857, 1736, 1815, 1576]}: mycrate: starting calculations
2022-09-15T16:11:47.830545Z  INFO calculate{data_set=[1509, 1857, 1736, 1815, 1576]}: mycrate: return=3085
Run Code Online (Sandbox Code Playgroud)

一切都设计得非常灵活:如果您想发送到文件而不是 stdout,可以使用.with_writer(). 如果您想将日志发送到多个位置,您可以使用Registry. 如果您只想根据事件的级别、来源或内容过滤某些事件,可以使用.with_filter. 如果您想以 JSON 格式而不是人类可读的文本进行登录,您可以使用.json().

常见的下一步是设置EnvFilter允许您根据环境变量配置要记录的事件,而不是尝试在代码中配置它。它可以像"info"/"trace"设置最大级别一样简单,也可以很复杂"warn,mycrate=debug"(从我的板条箱记录调试事件,仅记录其他任何内容的警告)。

除此之外,您可能正在寻找更专注的东西。就像您需要以特定格式登录一样。或者您需要将事件直接发送到外部提供商。或者您只是在寻找一种不同的方式来查看数据。在跟踪的相关板条箱部分中查找其他Subscriber有望满足您需求的东西。

  • 这是一篇很棒的文章。只想说。它很快就解决了复杂性及其原因,然后跳转到人们想要开始的简单界面。如果有人想取得进展,并提供后续行动。所有这些都非常易于解析和扫描。当我现在自己描述技术问题时,我会记住这一点@ (3认同)