跳转至

03 — UI Logs 页 Session ID 搜索

LiteLLM Dashboard 的 /uiLogs 页提供两种基于 Session ID 的能力:

  1. 过滤搜索(本次新增):在高级 Filter 里输入 Session ID 前缀,全表过滤。
  2. 抽屉 session 模式(旧功能):点击表格里某行的 Session ID 单元格,右侧抽屉展开同 session 的全部 request。

本篇说清两者的区别、参数语义、以及"为什么顶部那个白色搜索框搜不到"的常见困惑。


一图看清三种搜索机制

flowchart LR
    UI[Logs 页] --> S1[顶部搜索框<br/>'Search by Request ID']
    UI --> S2[高级 Filter<br/>Session ID]
    UI --> S3[Session ID 单元格<br/>点击]

    S1 -. 纯前端 .-> P1["仅当前 50 条<br/>match: request_id, model, user"]
    S2 -->|GET /spend/logs/ui<br/>?session_id=前缀| P2[("LiteLLM_SpendLogs<br/>WHERE session_id LIKE 'xxx%'")]
    S3 -->|GET /spend/logs/session/ui<br/>?session_id=精确| P3[("LiteLLM_SpendLogs<br/>WHERE session_id = 'xxx'")]

    style S1 fill:#ffe8e8,stroke:#c00
    style S2 fill:#e8ffe8,stroke:#080
    style S3 fill:#e8f4ff,stroke:#06c
机制 范围 后端调用 匹配方式
顶部搜索框 仅当前页 50 条 子串匹配 request_id / model / user
高级 Filter → Session ID 全表 /spend/logs/ui?session_id=前缀 LIKE 'xxx%'
点击 Session ID 单元格 全表 /spend/logs/session/ui?session_id=精确 等值

1. 高级 Filter → Session ID(推荐)

操作步骤:

  1. 进入 /ui → 左侧导航 Logs
  2. 点顶栏右上角的 Filter 按钮,弹出过滤面板
  3. Session ID 字段
  4. 粘贴你拿到的 trace_id(完整值或前缀均可
  5. Apply

前端代码位置: ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsxFILTER_KEYS.SESSION_ID)。

后端代码位置: spend_management_endpoints.py:1641-1644ui_view_spend_logs query 参数 session_id

匹配语义: 前缀匹配LIKE 'xxx%'),不是等值。原因:上游 mirror 服务的 trace_id 常带 <trace>-<span> 结构,运维拿到 trace 部分时可以一次找到该 trace 下所有 span。

SQL 等价物:

SELECT * FROM "LiteLLM_SpendLogs"
WHERE session_id LIKE 'SPAN-2026-04-30-%'
  AND "startTime" BETWEEN ... AND ...
ORDER BY "startTime" DESC
LIMIT 50 OFFSET 0;

注意:

  • 时间窗仍以 Logs 页顶部的快捷范围(默认最近 24h)为准。如果你的请求是 3 天前的,记得把范围拉到 7 天。
  • Session ID 与其他 Filter(Team ID / Status / Model 等)可以叠加使用。

2. 抽屉 session 模式(点击单元格)

适用场景:你已经在表格里看到某条 request 行,想看"同一 session 的其他 request"。

操作: 直接点表格某行的 Session ID 单元格(可点链接样式)。

行为:

  • 触发 onSessionClick(sessionId) → 打开右侧抽屉
  • 抽屉内 query:GET /spend/logs/session/ui?session_id=<精确值>
  • 抽屉内拉取该 session 的全部 request,时间正序排列

与 Filter 的差异:

抽屉 session 模式 Filter Session ID
匹配 等值 前缀
范围 不受时间窗约束(接口内固定取整段) 受 Logs 页时间窗约束
上下文 抽屉内独立视图,主表格不变 主表格替换
入口 点单元格 顶部 Filter

3. 顶部搜索框 = 坑(待优化)

Logs 页表格上方有个白色 "Search by Request ID" 搜索框(view_logs/index.tsx:537-543)。

它的真实行为index.tsx:302-307):

const matchesSearch =
  !searchTerm ||
  log.request_id.includes(searchTerm) ||
  log.model.includes(searchTerm) ||
  (log.user && log.user.includes(searchTerm));

也就是说:

  • 纯前端,不发后端请求
  • ✗ 只在当前页 50 条已拉到的数据里子串匹配
  • ✗ 不匹配 session_id
  • ✗ 跨页搜索一律失败
  • ✓ 仅当目标确实在当前 50 条内时才管用

结论:搜 trace_id / session_id 一律用高级 Filter,不要用顶部那个搜索框。

待办:未来把顶部搜索框改造成统一走后端的智能搜索框(同时支持 request_id 与 session_id),目前未做。


4. 后端接口约束

/spend/logs/ui 是分页接口,单次返回上限 100 条。如果你按 Session ID 前缀搜出 1000 条记录,需要翻页(页号在 query 参数 pagepage_size)。

GET /spend/logs/ui?session_id=<前缀>&start_date=...&end_date=...&page=1&page_size=50

鉴权与可见范围:

  • Admin 视图:可见全表
  • 普通用户:受 _can_user_view_spend_log 限制,只能看到自己 user_id 名下的行
  • Team 视图:受 team 成员关系约束

详见 spend_management_endpoints.py:1832-1853 的鉴权分支。


5. 一个完整的全链路定位示例

业务方反馈:"2026-04-30 上午用户 X 的请求异常",给了 trace_id SPAN-2026-04-30-abc123-span04

  1. 打开 Logs 页,时间范围调到当天 8:00-12:00
  2. Filter → Session ID 输入 SPAN-2026-04-30-abc123只输 trace 部分,省略 span 后缀)
  3. 表格出现该 trace 下所有 span:8 行
  4. 点其中任一行的 Session ID 单元格,抽屉打开看到完整 8 个 span 的时序
  5. 找到失败那条,点 request_id 看 messages / response 详情
  6. 如需 S3 完整日志,复制 request_id 按 02-output-destinations.md ⑤ 拼路径下载