Skip to main content

tdm_server_rust/dev/
routes.rs

1//! dev 路由:SkyWalking 302 + health + errors API
2
3use crate::{
4    app::AppState,
5    dev::{error_repo, health::run_health_checks, mcp},
6};
7use axum::{
8    extract::{Query, State},
9    http::StatusCode,
10    response::{IntoResponse, Redirect, Response},
11    routing::get,
12    Json, Router,
13};
14use serde::Deserialize;
15use serde_json::json;
16
17/// 错误列表查询
18#[derive(Debug, Deserialize)]
19pub struct ErrorListQuery {
20    /// 最大条数
21    #[serde(default = "default_limit")]
22    pub limit: i64,
23}
24
25fn default_limit() -> i64 {
26    100
27}
28
29/// 注册 dev 路由(仅 dev profile 挂载)
30pub fn routes(state: AppState) -> Router {
31    Router::new()
32        .route("/dev/console.html", get(console_redirect))
33        .route("/dev/api/health", get(health))
34        .route("/dev/api/errors", get(list_errors))
35        .route("/dev/api/mcp/trace-query", get(mcp_trace_query))
36        .with_state(state)
37}
38
39/// 302 跳转 SkyWalking UI
40#[tracing::instrument(skip_all, level = "info")]
41async fn console_redirect(State(state): State<AppState>) -> impl IntoResponse {
42    let url = state.config.telemetry.ui.skywalking.trim();
43    if url.is_empty() {
44        return Redirect::temporary("http://127.0.0.1:8080").into_response();
45    }
46    Redirect::temporary(url).into_response()
47}
48
49/// 健康检查
50#[tracing::instrument(skip_all, level = "info")]
51async fn health(State(state): State<AppState>) -> Json<serde_json::Value> {
52    let report = run_health_checks(&state).await;
53    Json(serde_json::to_value(report).unwrap_or(json!({"ok": false})))
54}
55
56/// 错误 JSON 列表(MySQL)
57#[tracing::instrument(skip_all, level = "info")]
58async fn list_errors(
59    State(state): State<AppState>,
60    Query(q): Query<ErrorListQuery>,
61) -> Response {
62    let limit = q.limit.clamp(1, 500);
63    match error_repo::list_recent(&state.db, limit).await {
64        Ok(rows) => Json(json!({"entries": rows})).into_response(),
65        Err(e) => (
66            StatusCode::INTERNAL_SERVER_ERROR,
67            Json(json!({"msg": e.to_string()})),
68        )
69            .into_response(),
70    }
71}
72
73/// MCP:按 trace_id 返回 SkyWalking GraphQL 查询模板
74#[tracing::instrument(skip_all, level = "info")]
75async fn mcp_trace_query(
76    State(state): State<AppState>,
77    Query(q): Query<McpTraceQuery>,
78) -> Json<serde_json::Value> {
79    Json(mcp::trace_lookup_template(
80        &state.config.telemetry.ui.skywalking,
81        &q.trace_id,
82    ))
83}
84
85/// MCP trace 查询参数
86#[derive(Debug, Deserialize)]
87pub struct McpTraceQuery {
88    /// OTel trace id(32 hex)
89    pub trace_id: String,
90}