53 个版本
4.0.0-beta.1 |
|
---|---|
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 编程
165,495 每月下载量
用于 54 个 Crates (38 个直接使用)
71KB
583 行
tracing-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
的文档提供了一个速成课程,介绍如何使用 tracing
对 actix-web
应用程序进行仪表化。
如果您想了解更多,请查看 "Are we observable yet?" - 它提供了对 crate 的深入介绍以及它在 可观察性 大背景下的解决的问题。
根跨度
tracing::Span
是 tracing
的关键抽象:它表示您系统中的一个工作单元。
一个 tracing::Span
有一个开始和一个结束。它可以包含一个或多个 子跨度 来表示较大任务中的子工作单元。
当您的应用程序接收到一个请求时,TracingLogger
创建一个新的跨度 - 我们称之为 根跨度。
在处理请求时创建的所有跨度都将成为根跨度的子跨度。
tracing
使我们能够将结构化属性附加到跨度上,作为键值对的集合。
这些属性可以在各种工具(例如 ElasticSearch、Honeycomb、DataDog)中进行查询,以了解您的系统正在发生什么。
通过 RootSpanBuilder
进行自定义
当根跨度具有 丰富上下文 时,故障排除变得更加容易 - 例如,您只需查看相应根跨度附加的属性,就可以了解请求处理过程中发生了什么。
您可能已经听说过这种技术被称为 规范日志行模式,由 Stripe 流行。最近,由 Honeycomb 和其他可观察性领域的供应商讨论为 高基数事件。
TracingLogger
给您机会使用相同的模式:您可以自定义附加到根跨度的属性,以捕获与您的特定领域相关的上下文。
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 实现来自定义根跨度。
让我们想象一下,例如,我们的系统关心一个嵌入在授权头中的客户端标识符。我们可以使用自定义构建器 DomainRootSpanBuilder
将 client_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!
揭示了您可以在 tracing
的 span!
宏上找到的类似旋钮。例如,您可以自定义跨度级别
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-middleware
和 reqwest-tracing
- 该上下文将传播到您的下游依赖项。
然后您可以通过查找 trace_id
(由 tracing-actix-web
自动记录)来找到所有服务的相同请求的日志。
如果您在您的 tracing::Subscriber
中添加 tracing-opentelemetry::OpenTelemetryLayer
,您将能够将根跟踪(及其所有子跟踪)导出为 OpenTelemetry 跟踪。
请参阅 GitHub 仓库中的相关示例以供参考 [链接]。
许可证
在您的选择下,根据 Apache License, Version 2.0 或 MIT 许可证。
除非您明确声明,否则根据 Apache-2.0 许可证定义,您提交给 tracing-actix-web
的任何有意贡献都应作为上述双许可,不附加任何额外条款或条件。
依赖关系
~15–27MB
~469K SLoC