跳轉到

Server Metrics Access-log Drill-down 前端整合

本文件描述 cortex-management「系統監控 / 伺服器狀態」頁從 GET /api/admin/server-metrics 統計值下鑽至 GET /api/admin/access-logs 實際請求的最終契約。所有請求都需要 admin Bearer token。

Endpoint 與 response

GET /api/admin/access-logs

Response wrapper 不變:

type AccessLogListResponse = {
  total: number;
  items: AccessLogItem[];
};

total 是套用全部 filter 後的總筆數,不是當頁筆數;即使 offset 超出最後一頁,仍回正確 total。

新增 query parameters

參數 TypeScript 預設 行為
status_gte number 無 100..599,篩選 status_code >= value(含)
status_lte number 無 100..599,篩選 status_code <= value(含)
min_duration_ms number 無 有限值且 >= 0,篩選 duration_ms >= value(含);NULL 不符合
order_by 'timestamp_desc' \| 'duration_desc' 'timestamp_desc' 指定排序

四個參數可與既有 from_ts、to_ts、status、method、path、member_id、request_id、limit、offset 任意組合,條件間採 AND。若同時傳 status 與 status 級距,也必須同時符合。

order_by 的穩定排序:

  • timestamp_desc:記錄時間新到舊,再以 id 新到舊。
  • duration_desc:耗時大到小,NULL 排最後;相同耗時再以記錄時間、id 新到舊。

Server-metrics 下鑽呼叫

5xx 錯誤率:

GET /api/admin/access-logs?from_ts=<區間起>&to_ts=<區間迄>&status_gte=500&status_lte=599&order_by=timestamp_desc&limit=50&offset=0

4xx 錯誤率:

GET /api/admin/access-logs?from_ts=<區間起>&to_ts=<區間迄>&status_gte=400&status_lte=499&order_by=timestamp_desc&limit=50&offset=0

P95 延遲(平均、P50、P99 可套用相同模式):

GET /api/admin/access-logs?from_ts=<區間起>&to_ts=<區間迄>&min_duration_ms=<p95值>&order_by=duration_desc&limit=50&offset=0

from_ts 是 inclusive,to_ts 是 exclusive。請沿用 server-metrics 所選日期換算出的相同 UTC 時間邊界,並以標準 ISO 8601 URL encoding 傳送。

時間欄位

AccessLogItem 新增:

type AccessLogItem = {
  // existing fields...
  timestamp: string;
  request_started_at: string | null;
  response_completed_at: string | null;
  db_duration_ms: number | null;
  db_query_count: number | null;
  timing_breakdown: {
    schema_version: 1;
    phases_ms: Record<string, number>;
    cache_outcomes: Record<string, 'hit' | 'miss' | 'bypass'>;
    // #2056 additive runtime keys; absent on older rows. UI may ignore them.
    db_pool?: Record<string, unknown>;
    db_pool_spawned_tasks?: Record<string, unknown>;
    sync_cpu?: Record<string, unknown>;
    post_response?: Record<string, unknown>;
  } | null;
};

欄位語意:

  • request_started_at:middleware 真實記錄的請求開始時間。
  • response_completed_at:final response body 成功送出後的真實完成時間。
  • timestamp:背景 writer 建立/持久化 access-log row 的時間,可能比 response completion 晚;不是 request start 或 response completion。

前端「請求時間/回應時間」兩欄應直接使用新欄位。Migration 117 上線前的歷史 row 兩欄都是 null;例外或未完整送出 response 的 row,其 response_completed_at 也可能為 null。遇到 null 建議顯示 —,不要用 timestamp ± duration_ms 冒充真實時間。若畫面仍顯示 timestamp,欄名應為「記錄時間」。

db_duration_ms 是 API SQLAlchemy engine 的 cursor execution 累計, db_query_count 是相同範圍內的 query 次數。DB 耗時是資源累計,可能和 phases_ms 重疊,並行 query 時也可能大於 wall-clock duration;UI 不可把 DB 耗時與 phases 相加。timing_breakdown 未知 schema、非物件、負值/非有限 phase 或未知 cache outcome 應視為不可顯示;歷史 null 與無效值都顯示 —。 phase 也可能巢狀(single_flight_wait 包含 polling 的 cache_lookup),彼此 不可相加當總耗時。合法但前端尚未認識的 phase key 可直接顯示原始 key。

Validation errors

下列情況回 FastAPI 422 validation response:

  • status_gte 或 status_lte 不在 100..599。
  • status_gte > status_lte。
  • min_duration_ms 不是有限數值或 < 0。
  • order_by 不是 timestamp_desc 或 duration_desc。

部署相依

先套用 117_access_log_request_response_timestamps.sql 與 147_api_access_log_timing_breakdown.sql,再部署對應 API。兩次 schema 變更 都是 additive nullable,歷史資料不回填;application rollback 時保留欄位即可。