Rust+Axum高性能web系列(2)-集成日志功能Tracing
哈喽,大家好,我是呼噜噜。在上一篇文章Rust+Axum高性能web系列-从入门到速通教程 我们了解什么事axum和axum为web提供的服务,本文接着给web项目引入日志监控功能!
Tracing 是什么?
我们这里选用Tracing
这个库,它是一个用于检测Rust程序以收集结构化、基于事件的诊断信息的框架。它允许开发者跟踪异步操作的执行流,以更好地理解、监控和调试应用程序。而对于web项目来说,日志监控非常重要
在像 Tokio
这样的异步系统中,由于异步编程模型复杂,解释传统的日志消息通常非常具有挑战性(效率低下,难以掌握整个执行流程)。Tracing
扩展了日志记录样式的诊断,允许库和应用程序记录结构化事件,可以按区间span记录日志,并提供有关时间性和因果关系的附加信息,并收集关键的上下文信息,极大地提高了应用程序的可观测性
添加依赖
这里选用tracing
这个库的当前最新版本
tracing = { version = "0.1.41", features = ["async-await"] } #日志,追踪诊断信息;同时开启支持异步的特性
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "chrono"] } #日志订阅器,更好地处理日志
这里把axum
也升到最新版本,笔者发文此时现在最新版本:0.8.4
简单日志记录
- 编写logger.rs
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
pub fn init() {
// 注册一个全局的日志记录器
tracing_subscriber::registry()
.with(::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"))) // 设置日志级别
.with(
tracing_subscriber::fmt::layer()
.with_file(true) //打印文件名
.with_line_number(true) //打印行号
.with_thread_ids(true) //打印线程ID
.with_thread_names(true) //打印线程名称
.with_target(false) //不打印target
)
.init();
}
如果从环境变量RUST_LOG
未获取到日志等级,就设置默认等级为info
- main.rs
tracing
有 TRACE、DEBUG、INFO、WARN、ERROR
共5个日志级别,其中TRACE
是最详细的级别。
...
mod logger;
#[tokio::main]
async fn main() {
logger::init();// 初始化!
let app = Router::new()
.route("/test", get(handle_test))// 测试接口
//.layer(middleware::from_fn(logging_middleware));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
tracing::info!("rust_demo listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
...
#[debug_handler]
async fn handle_test() -> Json<Value> {
tracing::trace!("trace");
tracing::debug!("debug");
tracing::info!("info,test方法打印");
tracing::warn!("warn");
tracing::error!("error");
Json(json!({
"code": 0,
"msg": "请求成功",
"data": "手动构造 返回请求体"
}))
}
logger::init()
初始化日志后,就可以像tracing::debug
去使用,非常方便。我们在上面设置的日志等级为:INFO
,那么TRACE、DEBUG
级别的日志就不会显示
Spans与Events
Spans
区间,Span
表示具有开始、结束的时间段 及其他元数据,当 程序开始在上下文中执行或执行工作单元,则 输入该上下文的span
,当它停止在该上下文中执行时,它将退出span
。线程当前正在执行的span
称为该线程的当前span
use tracing::{span, Level};
let span = span!(Level::TRACE, "my_span");
// `enter` returns a RAII guard which, when dropped, exits the span. this
// indicates that we are in the span for the current lexical scope.
let _enter = span.enter();
// perform some work in the context of `my_span`...
<font style="color:rgb(0, 0, 0);">Events</font>
事件,表示某个时刻 。它表示在记录跟踪时发生的事情。Event
可与非结构化日志记录代码发出的日志记录相媲美,但与典型的 log 行不同,Event
可能在 span 的上下文中发生
use tracing::{event, span, Level};
// records an event outside of any span context:
event!(Level::INFO, "something happened");
let span = span!(Level::INFO, "my_span");
let _guard = span.enter();
// records an event within "my_span".
event!(Level::DEBUG, "something happened inside my_span");
小结
其实还有log这个库来实现日志功能,但涉及到异步程序就会比较复杂,不太好用。而tracing
则能很好地解决异步日志追踪这个问题,使用起来也非常方便。
参考:
https://docs.rs/tracing/latest/tracing
作者:小牛呼噜噜
本文到这里就结束啦,感谢阅读,关注同名公众号:小牛呼噜噜,防失联+获取更多技术干货