Rust请求追踪库tower-request-id的使用,为HTTP请求添加唯一标识符实现分布式追踪
Rust请求追踪库tower-request-id的使用,为HTTP请求添加唯一标识符实现分布式追踪
tower-request-id是一个用于tower生态(hyper, axum, warp等)的小型服务,为每个传入请求生成随机ID。
使用示例
将RequestIdLayer
添加到axum中间件后,请求ID可以通过http::Request::extensions()
获取。对于tracing集成,请参考日志记录示例。
完整示例代码
use axum::{
routing::get,
Router,
extract::Request,
middleware::{self, Next},
response::IntoResponse,
};
use tower_request_id::{RequestId, RequestIdLayer};
use uuid::Uuid;
async fn handler(request: Request) -> impl IntoResponse {
// 从请求扩展中获取请求ID
let request_id = request.extensions().get::<RequestId>().unwrap();
format!("Request ID: {}", request_id)
}
async fn log_request_id(request: Request, next: Next) -> impl IntoResponse {
// 在中间件中获取请求ID
let request_id = request.extensions().get::<RequestId>().unwrap();
println!("Request ID in middleware: {}", request_id);
next.run(request).await
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(handler))
// 添加请求ID层
.layer(RequestIdLayer::with_generator(|| Uuid::new_v4().to_string()))
// 添加记录请求ID的中间件
.layer(middleware::from_fn(log_request_id));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
代码说明
- 首先我们导入必要的模块和类型
- 创建一个简单的handler函数,从中获取并返回请求ID
- 创建一个中间件函数
log_request_id
,演示如何在中间件中访问请求ID - 在main函数中:
- 创建路由
- 添加
RequestIdLayer
中间件层,使用UUID作为ID生成器 - 添加我们的日志记录中间件
- 启动服务器
这个示例展示了如何:
- 为每个请求自动生成唯一ID
- 在handler和中间件中访问这些ID
- 使用自定义ID生成器(这里使用UUID)
许可证
本项目使用MIT许可证。
1 回复
Rust请求追踪库tower-request-id的使用:为HTTP请求添加唯一标识符实现分布式追踪
介绍
tower-request-id
是一个Rust中间件库,用于为HTTP请求添加唯一标识符(Request ID),帮助实现分布式系统追踪。它基于tower
生态构建,可以轻松集成到使用tower
或axum
等框架的应用中。
主要功能:
- 为每个HTTP请求生成唯一ID
- 支持自定义ID生成策略
- 可以从请求头中提取已有ID
- 将ID注入到请求和响应中
完整示例代码
下面是一个完整的示例,展示了如何使用tower-request-id
为HTTP请求添加唯一标识符:
use axum::{
routing::get,
Router,
extract::Request,
middleware,
response::Response,
body::Body
};
use tower::ServiceBuilder;
use tower_request_id::{RequestId, RequestIdLayer};
use uuid::Uuid;
use tracing::info;
use tower_http::trace::TraceLayer;
// 处理函数,显示请求ID
async fn handler(request_id: RequestId) -> String {
info!(request_id = %request_id, "处理请求");
format!("请求ID: {}", request_id)
}
// 自定义中间件,记录请求ID
async fn request_id_middleware(request: Request, next: middleware::Next) -> Response {
let request_id = request.extensions().get::<RequestId>().unwrap().clone();
info!(%request_id, "开始处理请求");
let response = next.run(request).await;
info!(%request_id, "请求处理完成");
response
}
#[tokio::main]
async fn main() {
// 初始化tracing日志
tracing_subscriber::fmt().init();
let app = Router::new()
.route("/", get(handler))
.layer(
ServiceBuilder::new()
// 添加请求ID层,使用UUID v4生成ID
.layer(RequestIdLayer::new(
|| Uuid::new_v4().to_string(),
"x-request-id".to_string(),
))
// 添加HTTP追踪层
.layer(TraceLayer::new_for_http())
// 添加自定义中间件层
.layer(middleware::from_fn(request_id_middleware))
);
let addr = "0.0.0.0:3000".parse().unwrap();
info!("服务器启动,监听 {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
代码说明
- 依赖配置 (Cargo.toml):
[dependencies]
axum = "0.7"
tower = "0.4"
tower-request-id = "0.3"
tower-http = "0.4"
uuid = { version = "1.3", features = ["v4"] }
tracing = "0.1"
tracing-subscriber = "0.3"
tokio = { version = "1.0", features = ["full"] }
- 核心组件:
RequestIdLayer
: 生成请求ID的中间件层RequestId
: 请求ID类型,可以从请求扩展中获取TraceLayer
: HTTP请求追踪中间件tracing
: 日志记录框架
- 工作流程:
- 每个请求到达时,
RequestIdLayer
会生成唯一ID - 中间件和处理器可以通过请求扩展获取这个ID
- ID会被自动添加到响应头中
- 所有日志都会包含请求ID,便于追踪
最佳实践
- 一致性: 建议使用标准的请求头名称如
x-request-id
- 传播: 调用下游服务时,确保传递请求ID
- 日志: 在关键日志点记录请求ID
- 格式: 使用UUID或ULID等标准格式,确保全局唯一性
这个完整示例展示了如何在实际项目中使用tower-request-id
实现请求追踪,包括ID生成、日志记录和中间件集成。