tdm_server_rust/dev/
error_log.rs1use crate::dev::error_repo::{self, DevErrorInsert};
4use crate::telemetry::skywalking;
5use sqlx::MySqlPool;
6use std::sync::OnceLock;
7
8static DEV_POOL: OnceLock<MySqlPool> = OnceLock::new();
9
10pub fn init_pool(pool: MySqlPool) {
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: MySqlPool,
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(
66 pool: MySqlPool,
67 kind: &str,
68 code: i32,
69 msg: &str,
70 detail: Option<&str>,
71) {
72 let text = match detail.filter(|d| !d.is_empty()) {
73 Some(d) => format!("{msg} | {d}"),
74 None => msg.to_string(),
75 };
76 let row = DevErrorInsert {
77 kind: static_kind(kind),
78 method: None,
79 path: None,
80 status: None,
81 code: Some(code),
82 msg: truncate(&text, 512),
83 member_id: None,
84 otel_trace_id: current_trace_id(),
85 };
86 spawn_insert(pool, row);
87}
88
89fn static_kind(kind: &str) -> &'static str {
90 match kind {
91 "business" => "business",
92 "login_expired" => "login_expired",
93 "oss" => "oss",
94 "internal" => "internal",
95 "download_unauth" => "download_unauth",
96 "download_failed" => "download_failed",
97 _ => "app_error",
98 }
99}
100
101fn truncate(s: &str, max: usize) -> String {
102 if s.len() <= max {
103 s.to_string()
104 } else {
105 format!("{}...", &s[..max])
106 }
107}
108
109fn spawn_insert(pool: MySqlPool, row: DevErrorInsert) {
110 tokio::spawn(async move {
111 let _ = error_repo::insert(&pool, row).await;
112 });
113}