tdm_server_rust/dev/
error_log.rs1use crate::dev::error_repo::{self, DevErrorInsert};
4use crate::telemetry::skywalking;
5use sqlx::PgPool;
6use std::sync::OnceLock;
7
8static DEV_POOL: OnceLock<PgPool> = OnceLock::new();
9
10pub fn init_pool(pool: PgPool) {
12 let _ = DEV_POOL.set(pool);
13}
14
15pub fn current_trace_id() -> Option<String> {
17 skywalking::current_trace_id()
18}
19
20pub fn try_persist_http_error(
22 method: &str,
23 path: &str,
24 status: u16,
25 body: &str,
26 member_id: Option<i32>,
27) {
28 let Some(pool) = DEV_POOL.get().cloned() else {
29 return;
30 };
31 persist_http_error(pool, method, path, status, body, member_id);
32}
33
34pub fn try_persist_app_error(kind: &str, code: i32, msg: &str, detail: Option<&str>) {
36 let Some(pool) = DEV_POOL.get().cloned() else {
37 return;
38 };
39 persist_app_error(pool, kind, code, msg, detail);
40}
41
42fn persist_http_error(
44 pool: PgPool,
45 method: &str,
46 path: &str,
47 status: u16,
48 body: &str,
49 member_id: Option<i32>,
50) {
51 let row = DevErrorInsert {
52 kind: "http_error",
53 method: Some(method.to_string()),
54 path: Some(path.to_string()),
55 status: Some(status as i16),
56 code: None,
57 msg: truncate(body, 512),
58 member_id,
59 otel_trace_id: current_trace_id(),
60 };
61 spawn_insert(pool, row);
62}
63
64fn persist_app_error(pool: PgPool, kind: &str, code: i32, msg: &str, detail: Option<&str>) {
66 let text = match detail.filter(|d| !d.is_empty()) {
67 Some(d) => format!("{msg} | {d}"),
68 None => msg.to_string(),
69 };
70 let row = DevErrorInsert {
71 kind: static_kind(kind),
72 method: None,
73 path: None,
74 status: None,
75 code: Some(code),
76 msg: truncate(&text, 512),
77 member_id: None,
78 otel_trace_id: current_trace_id(),
79 };
80 spawn_insert(pool, row);
81}
82
83fn static_kind(kind: &str) -> &'static str {
84 match kind {
85 "business" => "business",
86 "login_expired" => "login_expired",
87 "oss" => "oss",
88 "internal" => "internal",
89 "download_unauth" => "download_unauth",
90 "download_failed" => "download_failed",
91 _ => "app_error",
92 }
93}
94
95fn truncate(s: &str, max: usize) -> String {
96 if s.len() <= max {
97 s.to_string()
98 } else {
99 format!("{}...", &s[..max])
100 }
101}
102
103fn spawn_insert(pool: PgPool, row: DevErrorInsert) {
104 tokio::spawn(async move {
105 let _ = error_repo::insert(&pool, row).await;
106 });
107}