#log-messages #log #logging-tracing #spans #logging #async #trace

async-log

为日志crate提供的异步跟踪功能

8个版本 (稳定)

2.0.0 2019年8月10日
1.1.0 2019年7月9日
1.0.4 2019年6月29日
1.0.1 2019年6月28日
0.0.0 2019年6月4日

#803异步

Download history 732/week @ 2024-03-14 786/week @ 2024-03-21 971/week @ 2024-03-28 769/week @ 2024-04-04 641/week @ 2024-04-11 739/week @ 2024-04-18 641/week @ 2024-04-25 679/week @ 2024-05-02 761/week @ 2024-05-09 938/week @ 2024-05-16 624/week @ 2024-05-23 815/week @ 2024-05-30 646/week @ 2024-06-06 508/week @ 2024-06-13 754/week @ 2024-06-20 523/week @ 2024-06-27

每月2,583次下载
12 个crate中使用 (直接使用2个)

MIT/Apache

24KB
273

async-log

crates.io version build status downloads docs.rs docs

为标准 log crate 提供异步跟踪功能。

这个crate提供扩展类型和钩子到 log 以启用异步日志。

什么是异步日志?

当构建一个 同步 应用程序时,日志消息可以依赖其总是按顺序发生。但不幸的是,同步应用程序很少能够充分利用系统资源。

相比之下,并发应用程序能更好地利用系统资源。但这也意味着我们不能再依赖日志消息严格按顺序发生。为了理解异步应用程序中的日志,我们需要能够将事件序列相互关联

a1 -> b1 -> b2 -> a2 -> b3     # raw log stream

a1 -------------> a2           # parsed log stream a
      b1 -> b2 -------> b3     # parsed log stream b

原始日志流包含"a"和"b"的项目。使用异步日志,您希望能够区分"a"的项目和"b"的项目。

我们如何关联消息?

异步日志的目标是确定在您的代码中哪些事件按顺序发生。实际上这意味着能够在 yield points (例如 .await) 和 thread bounds 之后将事件相互关联。

我们是这样做的:通过添加日志发生的当前任务ID和线程ID。每当一个新的任务被生成时,我们记录以下值

  • 生成新任务的父任务ID (task_parent_id)
  • 生成的新任务ID (task_id)
  • 当前的线程ID (thread_id)
  • 任务生成的行 (spawn_line,当 RUST_BACKTRACE=1 启用时)

拥有所有这些信息,我们就可以将任务相互关联。我们知道父任务是什么,新任务是什么,并将这些信息记录在一起。在接收端,我们可以重新构建这些信息以创建关联。

什么是跨度(span)?

跨度是一对消息。一个在操作开始时发出,另一个在操作结束时发出。如果我们给每个消息发送的时间戳,我们就能确定操作花费了多长时间。或者确定哪些操作从未完成。

async-log 中,每个跨度都用 span_mark 消息进行标注

  • span_mark=start 标记跨度的开始
  • span_mark=end 标记跨度的结束

示例

runtime::fs::read_to_string, span_mark=start, path=/tmp/foob, task_id=7, thread_id=8
runtime::fs::read_to_string, span_mark=end, path=/tmp/foob, task_id=7, thread_id=8

为什么要基于日志crate构建?

log 是Rust的标准日志crate。它非常灵活,并且考虑到了可扩展性。因为它被广泛使用,所以能够扩展它允许我们在不修改任何 log! 调用的同时为crate添加跟踪数据。

格式化

结构化日志(键值日志)目前正在添加到 log

在撰写本文时,没有可用的发布版本,甚至实验性功能也没有。因此,在此之前,我们必须使用字符串添加键值对。一旦将键值日志添加到 log,我们将发布一个破坏性变更,并迁移过去。

我们选择使用的语法是 foo=bar 对。多个对应使用逗号(,)分隔。每个对应该跟在第一条消息之后。一个示例日志如下

a new cat has logged on, name=nori, snacks=always

示例

use async_log::span;
use log::info;

fn setup_logger() {
    let logger = femme::pretty::Logger::new();
    async_log::Logger::wrap(logger, || 12)
        .start(log::LevelFilter::Trace)
        .unwrap();
}

fn main() {
    setup_logger();

    span!("level I", {
        let x = "beep";
        info!("look at this value, x={}", x);

        span!("level II", {
            let y = "boop";
            info!("another nice value, y={}", y);
        })
    })
}

安装

$ cargo add async-log

安全性

这个crate使用 #![deny(unsafe_code)] 来确保所有内容都在100%安全的Rust中实现。

贡献

想加入我们吗?查看我们的 "贡献" 指南 并查看一些这些问题

参考

许可证

MIT OR Apache-2.0

依赖

~6MB
~126K SLoC