feat(trace): add trace_id
This commit is contained in:
3
init.sql
3
init.sql
@@ -24,3 +24,6 @@ CREATE INDEX idx_logs_service_time ON app_logs(service_name, created_at);
|
|||||||
-- 这里的日期逻辑需要通过外部脚本(Python/Shell)动态生成 SQL 语句
|
-- 这里的日期逻辑需要通过外部脚本(Python/Shell)动态生成 SQL 语句
|
||||||
CREATE TABLE IF NOT EXISTS app_logs_2026_01 PARTITION OF app_logs
|
CREATE TABLE IF NOT EXISTS app_logs_2026_01 PARTITION OF app_logs
|
||||||
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
|
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
|
||||||
|
|
||||||
|
ALTER TABLE app_logs ADD COLUMN trace_id VARCHAR(64);
|
||||||
|
CREATE INDEX idx_logs_trace_id ON app_logs(trace_id); -- 加上索引,查问题全靠它
|
||||||
16
src/context.rs
Normal file
16
src/context.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// src/context.rs
|
||||||
|
use tokio::task_local;
|
||||||
|
|
||||||
|
// 定义一个 Tokio 任务局部变量
|
||||||
|
task_local! {
|
||||||
|
pub static TRACE_ID: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:设置 TraceID 作用域
|
||||||
|
// 在这个 scope 闭包内运行的所有代码,都能访问到这个 ID
|
||||||
|
pub async fn with_trace_id<F, R>(id: String, f: F) -> R
|
||||||
|
where
|
||||||
|
F: std::future::Future<Output = R>,
|
||||||
|
{
|
||||||
|
TRACE_ID.scope(id, f).await
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/core.rs
|
// src/core.rs
|
||||||
|
use crate::context::TRACE_ID;
|
||||||
use crate::model::{LogLevel, LogRecord};
|
use crate::model::{LogLevel, LogRecord};
|
||||||
use crate::outputs::LogOutput;
|
use crate::outputs::LogOutput;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
@@ -56,6 +57,8 @@ impl Logger {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let trace_id = TRACE_ID.try_with(|id| id.clone()).ok();
|
||||||
|
|
||||||
// 2. 构造记录
|
// 2. 构造记录
|
||||||
let record = LogRecord {
|
let record = LogRecord {
|
||||||
service_name: self.service_name.clone(),
|
service_name: self.service_name.clone(),
|
||||||
@@ -63,6 +66,7 @@ impl Logger {
|
|||||||
level,
|
level,
|
||||||
message,
|
message,
|
||||||
module,
|
module,
|
||||||
|
trace_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3. 发送 (非阻塞,如果队列满则丢弃,防止拖死业务)
|
// 3. 发送 (非阻塞,如果队列满则丢弃,防止拖死业务)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pub mod core;
|
|||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod outputs;
|
pub mod outputs;
|
||||||
pub use cleaner::LogCleaner;
|
pub use cleaner::LogCleaner;
|
||||||
|
pub mod context;
|
||||||
|
|
||||||
use crate::core::Logger;
|
use crate::core::Logger;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|||||||
@@ -34,4 +34,5 @@ pub struct LogRecord {
|
|||||||
pub level: LogLevel,
|
pub level: LogLevel,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub module: String,
|
pub module: String,
|
||||||
|
pub trace_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,10 +110,16 @@ impl LogOutput for FileOutput {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let trace_part = match &record.trace_id {
|
||||||
|
Some(id) => format!("[{}] ", id),
|
||||||
|
None => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
let log_line = format!(
|
let log_line = format!(
|
||||||
"{} [{}] - {}\n",
|
"{} [{}] {}- {}\n",
|
||||||
record.timestamp.format("%Y-%m-%d %H:%M:%S%.3f"),
|
record.timestamp.format("%Y-%m-%d %H:%M:%S%.3f"),
|
||||||
record.level,
|
record.level,
|
||||||
|
trace_part,
|
||||||
record.message
|
record.message
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ impl LogOutput for PostgresOutput {
|
|||||||
self.ensure_partition_exists(&record.timestamp).await;
|
self.ensure_partition_exists(&record.timestamp).await;
|
||||||
|
|
||||||
let query = r#"
|
let query = r#"
|
||||||
INSERT INTO app_logs (service_name, log_level, message, module, created_at)
|
INSERT INTO app_logs (service_name, log_level, message, module, created_at, trace_id)
|
||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
// 注意:这里的 write 是在后台任务中执行的,就算慢也不会阻塞主业务
|
// 注意:这里的 write 是在后台任务中执行的,就算慢也不会阻塞主业务
|
||||||
@@ -98,6 +98,7 @@ impl LogOutput for PostgresOutput {
|
|||||||
.bind(&record.message)
|
.bind(&record.message)
|
||||||
.bind(&record.module)
|
.bind(&record.module)
|
||||||
.bind(record.timestamp)
|
.bind(record.timestamp)
|
||||||
|
.bind(&record.trace_id)
|
||||||
.execute(&self.pool)
|
.execute(&self.pool)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user