rust 日志记录与跟踪

日志

Cargo.toml

复制代码
[dependencies]
warp = "0.3.7"
tokio = {version = "1.39.3", features = ["full"]}
serde = { version = "1.0.208", features = ["derive"] }
serde_json = "1.0.125"
#log = "0.4"
#env_logger = "0.11"
#log4rs = "1.3.0"
tracing = {version = "0.1.40", features = ["log"]}
tracing-subscriber = {version = "0.3.18", features = ["env-filter"]}
uuid = {version = "0.8", features = ["v4"]}

日志记录

env_logger

python 复制代码
log = "0.4"
env_logger = "0.11"
#log4rs = "1.3.0"
rust 复制代码
$ RUST_LOG=info cargo run -p wrap_demo01 --bin wrap_demo01
$ RUST_LOG=debug cargo run -p wrap_demo01 --bin wrap_demo01

log4rs

python 复制代码
log = "0.4"
#env_logger = "0.11"
log4rs = "1.3.0"

记录 HTTP 请求

  • 输出到控制台
  • 输出到文件

log4rs.yaml 配置

log4rs.yaml 复制代码
refresh_rate: 30 seconds
appenders:
   stdout:
     kind: console
     encoder:
       kind: json
   file:
     kind: file
     path: "stderr.log"
     encoder:
       kind : json
       #pattern: "{d} - {m}{n}"

root:
  level: info
  appenders:
    - stdout
    - file
rust 复制代码
log4rs::init_file("log4rs.yaml", Default::default()).unwrap();
let log = warp::log::custom(|info| {
        eprintln!(
            "{} {} {} {:?} from {} with {:?}",
            info.method(),
            info.path(),
            info.status(),
            info.elapsed(),
            info.remote_addr().unwrap(),
            info.request_headers()
        )
    });
let routes = get_questions
        .or(add_question)
        .or(update_question)
        .or(delete_question)
        .or(add_answer)
        .with(cors)
        .with(log)
        .recover(error::return_error);
warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;

创建结构化的日志

复制代码
let log = warp::log::custom(|info| {
        eprintln!(
            "{} {} {} {:?} from {} with {:?}",
            info.method(),
            info.path(),
            info.status(),
            info.elapsed(),
            info.remote_addr().unwrap(),
            info.request_headers()
        )
    });

日志跟踪

rust 复制代码
tracing = {version = "0.1.40", features = ["log"]}
tracing-subscriber = {version = "0.3.18", features = ["env-filter"]}
rust 复制代码
let log_filter =
        std::env::var("RUST_LOG").unwrap_or_else(|_| "wrap_demo01=info,warp=error".to_owned());

    tracing_subscriber::fmt()
        .with_env_filter(log_filter)
        .with_span_events(FmtSpan::CLOSE)
        .init();

// 针对某个请求设置跟踪
let get_questions = warp::get()
        .and(warp::path("questions"))
        .and(warp::path::end())
        .and(warp::query())
        .and(store_filter.clone())
        .and_then(get_questions)
        .with(warp::trace(|info| {
            tracing::info_span!("get_questions request", method = %info.method(),
            path = %info.path(),
            id = %uuid::Uuid::new_v4()) // 可根据 UUID 跟踪某个请求
        }));

// 记录每个传入的请求
let routes = get_questions
        .or(add_question)
        .or(update_question)
        .or(delete_question)
        .or(add_answer)
        .with(cors)
        //.with(log)
        .with(warp::trace::request())
        .recover(error::return_error);

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}
  • 未设置 instrument​ , 单个请求有3条记录

    rust 复制代码
    $ cargo run -p wrap_demo01 --bin wrap_demo01
    2024-08-23T14:18:45.013769Z  INFO get_questions request{method=GET path=/questions id=5828015e-0289-47f1-9a26-16028f54dd3f}: wrap_demo01::routes::question: Querying questions
    2024-08-23T14:18:45.013967Z  INFO get_questions request{method=GET path=/questions id=5828015e-0289-47f1-9a26-16028f54dd3f}: wrap_demo01::routes::question: pagination=false
    2024-08-23T14:18:45.014083Z  INFO get_questions request{method=GET path=/questions id=5828015e-0289-47f1-9a26-16028f54dd3f}: wrap_demo01: close time.busy=355µs time.idle=45.9µs
rust 复制代码
#[instrument]
pub async fn get_questions(
    params: HashMap<String, String>,
    store: Store,
) -> Result<impl Reply, Rejection> {
    info!("Querying questions");

    match extract_pagination(params) {
        Ok(pagination) => {
            info!(pagination = true);
            let questions = store.get(Some(pagination)).await;
            Ok(warp::reply::json(&questions))
        }
        Err(_) => {
            info!(pagination = false);
            let questions = store.get(None).await;
            Ok(warp::reply::json(&questions))
        }
    }
}
  • 设置 instrument​ 后, 单个请求有 4 条记录, 且提供更详细的信息

    rust 复制代码
    $ cargo run -p wrap_demo01 --bin wrap_demo01
    2024-08-23T14:22:46.631654Z  INFO get_questions request{method=GET path=/questions id=da967f3f-ff95-4dc0-bf17-935a38a863e8}:get_questions{params={} store=Store { questions: RwLock { data: {QuestionId("1"): Question { id: QuestionId("1"), title: "How?", content: "Please help!", tags: Some(["general"]) }} }, answers: RwLock { data: {} } }}: wrap_demo01::routes::question: Querying questions
    2024-08-23T14:22:46.631765Z  INFO get_questions request{method=GET path=/questions id=da967f3f-ff95-4dc0-bf17-935a38a863e8}:get_questions{params={} store=Store { questions: RwLock { data: {QuestionId("1"): Question { id: QuestionId("1"), title: "How?", content: "Please help!", tags: Some(["general"]) }} }, answers: RwLock { data: {} } }}: wrap_demo01::routes::question: pagination=false
    2024-08-23T14:22:46.631851Z  INFO get_questions request{method=GET path=/questions id=da967f3f-ff95-4dc0-bf17-935a38a863e8}:get_questions{params={} store=Store { questions: RwLock { data: {QuestionId("1"): Question { id: QuestionId("1"), title: "How?", content: "Please help!", tags: Some(["general"]) }} }, answers: RwLock { data: {} } }}: wrap_demo01::routes::question: close time.busy=212µs time.idle=9.73µs
    2024-08-23T14:22:46.632025Z  INFO get_questions request{method=GET path=/questions id=da967f3f-ff95-4dc0-bf17-935a38a863e8}: wrap_demo01: close time.busy=520µs time.idle=87.6µs

日志调试

相关推荐
凤山老林3 小时前
Spring Boot 启动冲刺:耗时剖析、懒加载策略与事件驱动初始化优化
spring boot·后端·python
朱涛的自习室4 小时前
我给 Gemini 4 和 DeepSeek 搞了套「末位淘汰」,AI 干活会更猛吗?(Day 3)
android·前端·后端
woniu_maggie6 小时前
SAP MDG主数据治理实战:从架构原理到项目实施全解析
后端
xiaoqiMikko6 小时前
Redis 实战(一):内存满了 —— 拒写、淘汰、被系统杀掉,以及删了 key 内存为什么不降(6.2.4 实测)
redis·后端
工程师小爱7 小时前
电芯尺寸合格,不等于电池包尺寸合格
后端
geovindu7 小时前
rust:Memento Pattern(续)
开发语言·后端·设计模式·rust·行为模式·备忘录模
闲云lazycloud7 小时前
第 1 课:Harness 与 Agent 运行时
人工智能·后端
熊哈哈O_o7 小时前
260+异构同步链路:DDL语法自动翻译在大规模数据同步中的实现原理
后端
用户9888321871748 小时前
别把 IOptionsSnapshot 注入单例:从生命周期看 .NET 配置读取
后端