53 个版本

4.0.0-beta.1 2021 年 4 月 25 日
0.7.11 2024 年 6 月 5 日
0.7.10 2024 年 3 月 10 日
0.7.9 2023 年 11 月 10 日
0.2.1 2020 年 9 月 28 日

#131 in Web 编程

Download history 47194/week @ 2024-04-30 44467/week @ 2024-05-07 49167/week @ 2024-05-14 46715/week @ 2024-05-21 52063/week @ 2024-05-28 48314/week @ 2024-06-04 47007/week @ 2024-06-11 47252/week @ 2024-06-18 51037/week @ 2024-06-25 39186/week @ 2024-07-02 40778/week @ 2024-07-09 39772/week @ 2024-07-16 43145/week @ 2024-07-23 39559/week @ 2024-07-30 40681/week @ 2024-08-06 34567/week @ 2024-08-13

165,495 每月下载量
用于 54 个 Crates (38 个直接使用)

MIT/Apache 许可

71KB
583

tracing-actix-web

actix-web 应用程序的结构化诊断


tracing-actix-web 提供了 TracingLogger,这是一个中间件,用于从基于 actix-web 框架构建的应用程序收集遥测数据。

tracing-actix-web 最初是为 Rust 编程语言使用的后端开发的实战介绍《Zero to Production In Rust》中的遥测章节开发的。

入门

如何安装

tracing-actix-web 添加到依赖项

[dependencies]
# ...
tracing-actix-web = "0.7"
tracing = "0.1"
actix-web = "4"

tracing-actix-web 暴露以下功能标志

  • opentelemetry_0_13:使用 opentelemetry 0.13 将 OpenTelemetry 的上下文附加到根跨度;
  • opentelemetry_0_14:与上述相同,但使用 opentelemetry 0.14;
  • opentelemetry_0_15:与上述相同,但使用 opentelemetry 0.15;
  • opentelemetry_0_16:与上述相同,但使用 opentelemetry 0.16;
  • opentelemetry_0_17:与上述相同,但使用 opentelemetry 0.17;
  • opentelemetry_0_18:与上述相同,但使用 opentelemetry 0.18;
  • opentelemetry_0_19:与上述相同,但使用 opentelemetry 0.19;
  • opentelemetry_0_20:与上述相同,但使用 opentelemetry 0.20;
  • opentelemetry_0_21:与上述相同,但使用 opentelemetry 0.21;
  • opentelemetry_0_22:与上述相同,但使用 opentelemetry 0.22;
  • opentelemetry_0_23:与上述相同,但使用 opentelemetry 0.23。
  • emit_event_on_error:当请求处理失败时发出一个 tracing 事件(默认启用)。
  • uuid_v7:在 RequestId 中使用 UUID v7 实现,而不是 UUID v4(默认禁用)。

快速入门

use actix_web::{App, web, HttpServer};
use tracing_actix_web::TracingLogger;

fn main() {
    // Init your `tracing` subscriber here!

    let server = HttpServer::new(|| {
        App::new()
            // Mount `TracingLogger` as a middleware
            .wrap(TracingLogger::default())
            .service( /*  */ )
    });
}

请查看 GitHub 上的示例,以了解如何使用 TracingLogger 来观察和监控您的应用程序。

从零到英雄:可观察性速成课程

tracing:你是谁?

TracingLogger 基于 tracing 构建,这是一个现代的仪表化框架,拥有一个充满活力的生态系统 (链接)

tracing-actix-web 的文档提供了一个速成课程,介绍如何使用 tracingactix-web 应用程序进行仪表化。
如果您想了解更多,请查看 "Are we observable yet?" - 它提供了对 crate 的深入介绍以及它在 可观察性 大背景下的解决的问题。

根跨度

tracing::Spantracing 的关键抽象:它表示您系统中的一个工作单元。
一个 tracing::Span 有一个开始和一个结束。它可以包含一个或多个 子跨度 来表示较大任务中的子工作单元。

当您的应用程序接收到一个请求时,TracingLogger 创建一个新的跨度 - 我们称之为 根跨度
在处理请求时创建的所有跨度都将成为根跨度的子跨度。

tracing 使我们能够将结构化属性附加到跨度上,作为键值对的集合。
这些属性可以在各种工具(例如 ElasticSearch、Honeycomb、DataDog)中进行查询,以了解您的系统正在发生什么。

通过 RootSpanBuilder 进行自定义

当根跨度具有 丰富上下文 时,故障排除变得更加容易 - 例如,您只需查看相应根跨度附加的属性,就可以了解请求处理过程中发生了什么。

您可能已经听说过这种技术被称为 规范日志行模式,由 Stripe 流行。最近,由 Honeycomb 和其他可观察性领域的供应商讨论为 高基数事件

TracingLogger 给您机会使用相同的模式:您可以自定义附加到根跨度的属性,以捕获与您的特定领域相关的上下文。

TracingLogger::default 等价于

use tracing_actix_web::{TracingLogger, DefaultRootSpanBuilder};

// Two ways to initialise TracingLogger with the default root span builder
let default = TracingLogger::default();
let another_way = TracingLogger::<DefaultRootSpanBuilder>::new();

我们将根跨度构造委托给 DefaultRootSpanBuilder
DefaultRootSpanBuilder 默认捕获了在查看 HTTP API 时通常相关的几个维度:方法、版本、路由等。 - 查看其文档以获取完整列表。

您可以通过提供自己的 RootSpanBuilder trait 实现来自定义根跨度。
让我们想象一下,例如,我们的系统关心一个嵌入在授权头中的客户端标识符。我们可以使用自定义构建器 DomainRootSpanBuilderclient_id 属性添加到根跨度中。

use actix_web::body::MessageBody;
use actix_web::dev::{ServiceResponse, ServiceRequest};
use actix_web::Error;
use tracing_actix_web::{TracingLogger, DefaultRootSpanBuilder, RootSpanBuilder};
use tracing::Span;

pub struct DomainRootSpanBuilder;

impl RootSpanBuilder for DomainRootSpanBuilder {
    fn on_request_start(request: &ServiceRequest) -> Span {
        let client_id: &str = todo!("Somehow extract it from the authorization header");
        tracing::info_span!("Request", client_id)
    }

    fn on_request_end<B: MessageBody>(_span: Span, _outcome: &Result<ServiceResponse<B>, Error>) {}
}

let custom_middleware = TracingLogger::<DomainRootSpanBuilder>::new();

但是有一个问题:client_id 是我们捕获的 唯一 属性。
使用当前的 DomainRootSpanBuilder,我们无法获得 DefaultRootSpanBuilder 提供的有用 HTTP 相关信息。

我们可以做得更好!

use actix_web::body::MessageBody;
use actix_web::dev::{ServiceResponse, ServiceRequest};
use actix_web::Error;
use tracing_actix_web::{TracingLogger, DefaultRootSpanBuilder, RootSpanBuilder};
use tracing::Span;

pub struct DomainRootSpanBuilder;

impl RootSpanBuilder for DomainRootSpanBuilder {
    fn on_request_start(request: &ServiceRequest) -> Span {
        let client_id: &str = todo!("Somehow extract it from the authorization header");
        tracing_actix_web::root_span!(request, client_id)
    }

    fn on_request_end<B: MessageBody>(span: Span, outcome: &Result<ServiceResponse<B>, Error>) {
        DefaultRootSpanBuilder::on_request_end(span, outcome);
    }
}

let custom_middleware = TracingLogger::<DomainRootSpanBuilder>::new();

root_span! 是由 tracing-actix-web 提供的一个宏:它通过组合 DefaultRootSpanBuilder 跟踪的所有 HTTP 属性以及调用它时指定的自定义属性(例如,我们的示例中的 client_id)来创建一个新的跨度。

我们需要使用宏,因为 tracing 要求在创建跨度时提前声明附加到跨度的所有属性。
之后无法添加新的属性。这使得它非常快,但当我们需要某种程度的组合时,它促使我们使用宏。

root_span! 揭示了您可以在 tracingspan! 宏上找到的类似旋钮。例如,您可以自定义跨度级别

use actix_web::body::MessageBody;
use actix_web::dev::{ServiceResponse, ServiceRequest};
use actix_web::Error;
use tracing_actix_web::{TracingLogger, DefaultRootSpanBuilder, RootSpanBuilder, Level};
use tracing::Span;

pub struct CustomLevelRootSpanBuilder;

impl RootSpanBuilder for CustomLevelRootSpanBuilder {
    fn on_request_start(request: &ServiceRequest) -> Span {
        let level = if request.path() == "/health_check" {
            Level::DEBUG
        } else {
            Level::INFO
        };
        tracing_actix_web::root_span!(level = level, request)
    }

    fn on_request_end<B: MessageBody>(span: Span, outcome: &Result<ServiceResponse<B>, Error>) {
        DefaultRootSpanBuilder::on_request_end(span, outcome);
    }
}

let custom_middleware = TracingLogger::<CustomLevelRootSpanBuilder>::new();

RootSpan 提取器

通常,关于任务的信息并非预先知道,编码在传入请求中。
您可以使用 RootSpan 提取器在您的处理程序中捕获根跨度,并在相关信息变得可用时将其附加到根跨度上

use actix_web::body::MessageBody;
use actix_web::dev::{ServiceResponse, ServiceRequest};
use actix_web::{Error, HttpResponse};
use tracing_actix_web::{RootSpan, DefaultRootSpanBuilder, RootSpanBuilder};
use tracing::Span;
use actix_web::get;
use tracing_actix_web::RequestId;
use uuid::Uuid;

#[get("/")]
async fn handler(root_span: RootSpan) -> HttpResponse {
    let application_id: &str = todo!("Some domain logic");
    // Record the property value against the root span
    root_span.record("application_id", &application_id);

    // [...]
    # todo!()
}

pub struct DomainRootSpanBuilder;

impl RootSpanBuilder for DomainRootSpanBuilder {
    fn on_request_start(request: &ServiceRequest) -> Span {
        let client_id: &str = todo!("Somehow extract it from the authorization header");
        // All fields you want to capture must be declared upfront.
        // If you don't know the value (yet), use tracing's `Empty`
        tracing_actix_web::root_span!(
            request,
            client_id, application_id = tracing::field::Empty
        )
    }

    fn on_request_end<B: MessageBody>(span: Span, response: &Result<ServiceResponse<B>, Error>) {
        DefaultRootSpanBuilder::on_request_end(span, response);
    }
}

唯一标识符

请求 ID

tracing-actix-web 为每个传入请求生成一个唯一标识符,即 请求 ID

您可以使用 RequestId 提取器提取请求 ID

use actix_web::get;
use tracing_actix_web::RequestId;
use uuid::Uuid;

#[get("/")]
async fn index(request_id: RequestId) -> String {
  format!("{}", request_id)
}

请求 ID 的目的是在您的 API 的边界内识别与特定请求相关的所有操作。
如果您需要跨多个服务 跟踪 请求(例如,在微服务架构中),请查看下一节中的 OpenTelemetry 以获取更多详细信息。

可选地,使用 uuid_v7 功能标志可以让 RequestId 使用 UUID v7 而不是当前使用的 UUID v4。

跟踪 Id

为了满足一个请求,你通常需要执行额外的 I/O 操作 - 例如调用其他 REST 或 gRPC API、数据库查询等。
分布式跟踪 是在整个堆栈中跟踪单个请求的标准方法。

tracing-actix-web 通过支持 OpenTelemetry 标准 来提供分布式跟踪的支持。
tracing-actix-web 遵循 OpenTelemetry 的语义约定 对于字段名称。
此外,它提供了一个 opentelemetry_0_17 功能标志来自动执行跟踪传播:它尝试从传入请求的头部中提取 OpenTelemetry 上下文,当找到时,将其设置为当前根跟踪的远程上下文。然后,如果您的 HTTP 或 gRPC 客户端支持 OpenTelemetry - 例如,如果您使用 reqwest 作为 HTTP 客户端,则使用 reqwest-middlewarereqwest-tracing - 该上下文将传播到您的下游依赖项。
然后您可以通过查找 trace_id(由 tracing-actix-web 自动记录)来找到所有服务的相同请求的日志。

如果您在您的 tracing::Subscriber 中添加 tracing-opentelemetry::OpenTelemetryLayer,您将能够将根跟踪(及其所有子跟踪)导出为 OpenTelemetry 跟踪。

请参阅 GitHub 仓库中的相关示例以供参考 [链接]

许可证

在您的选择下,根据 Apache License, Version 2.0MIT 许可证

除非您明确声明,否则根据 Apache-2.0 许可证定义,您提交给 tracing-actix-web 的任何有意贡献都应作为上述双许可,不附加任何额外条款或条件。

依赖关系

~15–27MB
~469K SLoC