尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

如何为 axum::serve 配置自定义 Executor 以注入连接任务 tracing

如何为 axum::serve 配置自定义 Executor 以注入连接任务 tracing 如何为 axum::serve 配置自定义 Executor 以注入连接任务 tracing【免费下载链接】axumHTTP routing and request-handling library for Rust that focuses on ergonomics and modularity项目地址: https://gitcode.com/GitHub_Trending/ax/axumaxum::serve接受连接后会为每条连接 spawn 一个后台任务来驱动整个连接的生命周期。默认情况下这个 spawn 就是一个裸的tokio::spawn连接任务内部的 tracing 事件不属于任何应用层 span难以和请求日志、telemetry 关联。当前仓库提供的解法是axum::serve::Executortrait 和Serve::with_executor方法自定义一个包装tokio::spawn的 executor在 spawn 时把任务挂进一个tracingspan即可为每条连接任务注入 tracing。该能力在 CHANGELOG 的 Unreleased 区列为新增项当前仓库中 axum 版本为 0.8.9说明这一分支上可用。准备条件已启用 axum 的tokio特性以及http1或http2特性中至少一个。serve相关代码的编译条件是#[cfg(all(feature tokio, any(feature http1, feature http2)))]见 axum/src/serve/mod.rs。这两个特性都在 axum 的 default features 中正常依赖 axum 即可满足。依赖tokio需要spawn能力、tracing和一个 tracing subscriber如tracing-subscriberREADME 示例中使用tracing_subscriber::fmt::init()初始化。Executor 的作用范围与实现要求先看 Executor trait 的定义文档其中明确了三点executor 用于 spawn 三类任务连接任务、优雅关闭任务、hyper 的内部任务如 HTTP/2 连接管理默认 executor 是TokioExecutor其execute实现就是tokio::spawn(fut)spawn 出来的 future 内部依赖 Tokio 原语因此自定义 executor 必须在 Tokio runtime 上下文中运行它们例如通过tokio::spawn。你不能把 future 塞进别的线程池而不经过 Tokio runtime否则会出问题。trait 签名本身很简单定义位置pub trait Executor: Clone Send Sync static { fn executeFut(self, fut: Fut) - JoinHandleFut::Output where Fut: Future Send static, Fut::Output: Send static; }返回类型固定为 tokio 的JoinHandle注意这一约束。实现一个注入 tracing span 的 executor文档给出的官方示例是一个把每个任务包进tracing::info_span!(axum.serve.task)的 executor示例来源。完整可运行的最小示例如下路由、listener 部分来自 hello-world 示例use axum::{routing::get, serve::Executor, Router}; use std::future::Future; use tokio::task::JoinHandle; use tracing::Instrument; #[derive(Clone)] struct InstrumentedExecutor; impl Executor for InstrumentedExecutor { fn executeFut(self, fut: Fut) - JoinHandleFut::Output where Fut: Future Send static, Fut::Output: Send static, { let span tracing::info_span!(axum.serve.task); tokio::spawn(fut.instrument(span)) } } #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); let app Router::new().route(/, get(|| async { Hello, World! })); let listener tokio::net::TcpListener::bind(127.0.0.1:3000).await.unwrap(); axum::serve(listener, app) .with_executor(InstrumentedExecutor) .await; }说明#[derive(Clone)]是因为 trait 要求Clone。如果 executor 字段较多、clone 昂贵文档指出对ArcT where T: Executor提供了 blanket impl实现位置直接传Arc::new(...)即可不必自己派生Clone。span 的名字axum.serve.task和 levelinfo_span!来自文档示例你可以按自己的 telemetry 规范改成别的名字或debug_span!示例中 span 没有携带任何字段如果需要 remote addr 等信息需要在你的execute实现里自行构造 span 字段——注意execute的入参只有 future 本身不携带连接元数据。serve内部会通过一个HyperExecutor适配器把 axum 的 executor 转成hyper::rt::Executor交给 hyper见 axum/src/serve/mod.rs所以 HTTP/2 的 hyper 内部任务同样会经过你的execute不需要额外接线。接线with_executor 与优雅关闭的组合with_executor定义在Serve上方法位置文档明确说明它可以在with_graceful_shutdown之前或之后调用。如果服务启用了优雅关闭WithGracefulShutdown也提供了同名方法位置。因此带 shutdown 的写法是axum::serve(listener, app) .with_executor(InstrumentedExecutor) .with_graceful_shutdown(shutdown_signal()) .await;顺序可以互换with_graceful_shutdown返回WithGracefulShutdown它同样实现with_executor。注意优雅关闭的信号处理任务本身也是通过 executor spawn 的见 run 实现所以它也会被包进你的 span。验证构建并运行上面的示例。向127.0.0.1:3000发起一个请求。由于 subscriber 已在main中初始化连接任务内产生的 tracing 事件会关联到axum.serve.taskspan 下——span 名与层级关系由示例代码本身保证具体日志行格式取决于你使用的 subscriber 层文档没有给出固定日志输出按你环境的 subscriber 输出判断即可。文档中的示例代码本身是可运行的 doc-testaxum crate 的cargo test会执行axum::serve相关模块的文档测试可用来核对示例代码在当前分支能编译通过。限制executor 的execute必须在 Tokio runtime 上下文中运行 future文档要求通常即tokio::spawn不能改用非 Tokio 的线程池。返回类型必须是 tokio 的JoinHandleFut::Output不是任意 future这限制了底层调度器的选择。该 API 目前记录在 axum/CHANGELOG.md 的 Unreleased 区块使用发布版 axum 时需要确认所用版本已包含serve::Executor。【免费下载链接】axumHTTP routing and request-handling library for Rust that focuses on ergonomics and modularity项目地址: https://gitcode.com/GitHub_Trending/ax/axum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表