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
log = "0.4"
env_logger = "0.11"
#log4rs = "1.3.0"
$ RUST_LOG=info cargo run -p wrap_demo01 --bin wrap_demo01
$ RUST_LOG=debug cargo run -p wrap_demo01 --bin wrap_demo01
log4rs
log = "0.4"
#env_logger = "0.11"
log4rs = "1.3.0"
记录 HTTP 请求
- 输出到控制台
- 输出到文件
log4rs.yaml
配置
refresh_rate: 30 seconds
appenders:stdout:kind: consoleencoder:kind: jsonfile:kind: filepath: "stderr.log"encoder:kind : json#pattern: "{d} - {m}{n}"root:level: infoappenders:- stdout- file
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())});
日志跟踪
tracing = {version = "0.1.40", features = ["log"]}
tracing-subscriber = {version = "0.3.18", features = ["env-filter"]}
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条记录$ 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
#[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 条记录, 且提供更详细的信息$ 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