HomeBrowseUpload
← Back to registry
// Skill profile

SLS + ARMS + 代码 + 数据库 全链路问题排查

name: sls-trace-analysis

by ccrazyfish · published 2026-04-01

数据处理API集成
Total installs
0
Stars
★ 0
Last updated
2026-04
// Install command
$ claw add gh:ccrazyfish/ccrazyfish-sls-trace-analysis
View on GitHub
// Full documentation

---

name: sls-trace-analysis

description: >

查询阿里云SLS日志和ARMS调用链,结合源码和数据库进行全链路问题排查。

完整流程:查日志 → 画调用链 → 定位源码 → 排查数据库 → 给出修复方案。

Use when: 用户说「分析sls」「分析问题」或想排查业务服务/线上接口/用户请求的报错或异常。

触发示例:「分析sls」「帮我查一下这个trace_id」「分析一下这个trace_id」

「查一下这个用户的请求」「wusid 是 xxx」「uid xxx」

「查一下 /path/to/api 这个接口的报错」「帮我排查一下这个业务报错」「线上有个接口挂了」

「帮我分析一下这个报错的代码」「数据库报错了」「SQL超时」「查一下这个接口为什么慢」。

IMPORTANT: trace_id = 染色ID = 业务调用链ID = requestId,这些都是同一个东西,

统一用 trace_id 表述。用户提供的 trace_id 是业务系统的外部 trace,不是 OpenClaw 内部 session ID,

不要自行分析 trace_id 的来源或归属,必须调用此 skill 去 SLS/ARMS 查询。

NOT for: 查询OpenClaw自身状态、分析OpenClaw系统问题、搜索本地文件、openclaw内置命令。

license: MIT-0

compatibility: >

Python 3.8+, aliyun-log-python-sdk 0.9.42+, alibabacloud-arms20190808 10.0.4+.

需要阿里云 SLS 和 ARMS 的 AccessKey (AK/SK).

Windows / macOS / Linux 均可运行.

user-invocable: true

metadata:

openclaw:

emoji: "🔍"

version: "1.0.0"

author: "Crazyfish"

tags:

- sls

- arms

- trace

- debug

- log-analysis

- alibaba-cloud

requires:

bins:

- python

env:

- ALIBABA_CLOUD_ACCESS_KEY_ID

- ALIBABA_CLOUD_ACCESS_KEY_SECRET

---

# SLS + ARMS + 代码 + 数据库 全链路问题排查

查询阿里云SLS日志和ARMS调用链 → 定位源码问题 → 排查数据库异常 → 给出完整修复方案。

⚠️ 关键规则(必须严格遵守)

1. **必须且只能通过执行下方 python 命令查询,禁止使用本地搜索或内置日志命令。**

2. **用户给出的 trace_id 是外部业务系统的 ID,禁止自行推断其来源、归属或意义,直接执行查询脚本。**

3. **每个 logstore 的日志必须单独分组展示,严禁合并或去重。**

4. **即使多条日志来自同一服务、同一时间,也必须逐条完整输出。**

5. **输出报告中必须包含 `sls.logs_by_logstore` 里每个 logstore 的所有日志。**

6. **所有交互提示必须严格按照下方模板输出,禁止自由发挥、禁止用自己的话改写、禁止添加语气词或额外解释。用户看到的提示必须和模板一字不差。**

7. **Step 5 代码搜索和 Step 6 数据库排查必须自动执行,禁止只输出"建议搜索xxx"之类的文字。发现异常后必须立即用 Grep/Glob/Read 工具实际搜索代码仓库。**

8. **所有提供选项的提示必须带序号(`1` `2` `3` …),用户可以直接回复序号操作。禁止输出不带序号的选项列表。禁止自编"继续操作"/"接下来"等不在模板中的提示文字。每个需要用户选择的场景都有对应模板,必须使用模板。**

---

执行步骤

Step 1:收集查询参数(交互式)

> **进入此 skill 后,立即扫描用户消息提取参数。已有的直接用,缺的才问。**

---

#### 1.1 扫描用户消息

检查用户消息中是否已包含查询参数(TraceID / wusid / path / 时间):

  • **已有参数**(如用户说"帮我查 trace_id f1b37e05...")→ 直接提取,跳到 Step 1.3
  • **没有参数**(如用户只说"分析sls")→ 进入 Step 1.2 询问
  • ---

    #### 1.2 询问查询条件

    **你的回复必须且只能是下面这段文字,从「🔍」开始到「逐项输入。」结束,不能多一个字也不能少一个字,不能加语气词、不能加问候、不能用自己的话改写,输出后立即停止等待用户回复:**

    🔍 请输入查询条件,格式:`关键词 值`,多项用 `;` 分隔:

    trace_id xxx; wusid xxx; path xxx

    ① trace_id — 染色ID / 业务调用链ID(32位十六进制字符串)

    ② wusid — 用户空间ID(数字,也可以用 `uid`)

    ③ path — 请求路径(如 `/ny.apps_pb.xxx/Method`)

    至少输入一项,回复序号 `1` `2` `3` 可逐项输入。

    **解析用户回复规则:**

    > **概念统一**:trace_id = 染色ID = 业务调用链ID = requestId,都是同一个东西。

    **情况 A:用户输入了参数值(含 `;` 或关键词)**

    1. 按 `;` 或换行拆分每项

    2. 每项内按空格分隔:前面是参数名,后面是值

    - `trace_id` / `tid` / `trace` / `染色id` / `requestid` → trace_id

    - `wusid` / `uid` / `用户id` → wusid

    - `path` / `接口` / `api` → path

    3. 不带参数名时自动识别:32位十六进制→trace_id,纯数字→wusid,`/`开头→path

    4. 提取到任意参数 → 进入 Step 1.3

    **情况 B:用户回复了序号**

  • `1` → 回复「请输入 trace_id:」→ 等用户输入值 → 记录 → 进入 Step 1.3
  • `2` → 回复「请输入 wusid:」→ 等用户输入值 → 记录 → 进入 Step 1.3
  • `3` → 回复「请输入 path:」→ 等用户输入值 → 记录 → 进入 Step 1.3
  • **情况 C:无法识别**

  • 回复「未识别到参数,请按格式输入(如 `trace_id xxx`)或回复序号 `1` `2` `3`」
  • 用户说"没有"/"不知道" → 依次追问 wusid → path → 都没有则停止
  • ---

    #### 1.3 确认时间范围

    检查用户是否已提供时间信息:

  • **已提及时间**(如"今天下午"、"昨天"、"最近2小时")→ 自动转换,直接跳到 Step 1.4
  • **未提及时间** → 你的回复必须且只能是下面这段文字,不能改写:
  • ⏰ 时间范围?默认 **最近 1 周**,也可以指定:

    默认           →  最近 1 周(直接回车)
    1小时 / 3天 / 2周 / 1个月  →  相对时间
    今天 / 昨天    →  当天范围
    2024-03-15 14:00 ~ 16:00   →  精确时间段
  • 用户回车 / 说"默认"/"可以"/"行" → 使用默认 1 周
  • 用户给出时间 → 传给 `--duration` 或 `--start/--end`
  • 用户说"今天"/"昨天"等 → 自行计算 `--start/--end`
  • **时间转换参考:**

    | 用户说的 | 转换 |

    |---------|------|

    | 今天 | `--start "今天00:00:00" --end "当前时间"` |

    | 昨天 | `--start "昨天00:00:00" --end "昨天23:59:59"` |

    | 今天下午 | `--start "今天12:00:00" --end "当前时间"` |

    | 最近N小时/天/周/月 | `--duration "N小时/天/周/月"` |

    | 上周 | `--start "上周一00:00:00" --end "上周日23:59:59"` |

    | 3月15号 | `--start "3月15日00:00:00" --end "3月15日23:59:59"` |

    ---

    #### 1.4 输出查询摘要并执行

    > 📋 **查询参数:**

    > ```

    > 条件:trace_id = xxx / wusid = xxx / path = xxx

    > 时间:最近 1 周(2026-03-12 ~ 2026-03-19)

    > 来源:SLS + ARMS

    > ```

    > 🚀 正在查询,请稍候…

    高级选项(**不主动询问**,仅用户提到时才加):

  • "只查SLS" / "不查ARMS" → `--skip-arms`
  • "只查ARMS" / "不查SLS" → `--skip-sls`
  • "查 xxx logstore" → `--logstores "xxx"`
  • Step 2:执行查询脚本(必须执行)

    > **默认查最近 1 周,无需指定时间参数。**

    > 支持 `--duration` 自然语言时间:1小时、2天、1周、1星期、1个月、半天、30m、6h、3d、1w 等。

    > 也支持 `--minutes N` 直接传分钟数,或 `--start/--end` 精确时间段。

    **模式 A:已知 TraceID(直接分析)**

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID"

    自定义时间范围(自然语言):

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --duration "3天"

    精确时间范围:

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --start "2024-01-15 14:00:00" --end "2024-01-15 15:00:00"

    只查 ARMS(跳过 SLS):

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --skip-sls

    只查 SLS(跳过 ARMS):

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --skip-arms

    **模式 B:未知 TraceID,通过 wusid / path 先检索**

    按用户 ID 检索:

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --wusid "76149226" --no-interactive

    按请求路径检索:

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --path "/ny.apps_pb.promote_pb.PromotePB/UpdateRelation" --no-interactive

    两者组合(精确缩小范围):

    python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --wusid "76149226" --path "/ny.apps_pb.promote_pb.PromotePB/UpdateRelation" --no-interactive

    > **模式 B 说明**:`--no-interactive` 让脚本自动选择第一条 TraceID 进行分析。如果 JSON 输出的 `discovered_traces` 有多条,可展示列表让用户选择,然后用选中的 trace_id 以模式 A 重新查询。

    Step 3:解析脚本输出

    脚本返回 JSON,必须读取以下字段:

    **查询信息(`query`):**

    query.trace_id               → 本次使用的 TraceID(模式 A)
    query.wusid                  → 本次使用的 wusid(模式 B)
    query.path                   → 本次使用的路径(模式 B)

    **模式 B 专属(`discovered_traces`):**

    discovered_traces[].trace_id      → 找到的 TraceID
    discovered_traces[].first_time    → 首条日志时间
    discovered_traces[].service       → 服务名
    discovered_traces[].path          → 请求路径
    discovered_traces[].response_code → 响应码
    discovered_traces[].response_msg  → 响应消息
    discovered_traces[].has_error     → 是否有 ERROR 日志
    discovered_traces[].log_count     → 匹配日志条数

    **ARMS 调用链(`call_chain`):**

    call_chain.tree              → 带缩进的调用链路图(文本),含异常 ID 和完整堆栈
    call_chain.error_spans       → 异常 Span 列表(含 exception_id、full_stack 字段)
    call_chain.services          → 涉及的服务列表
    call_chain.total_duration_ms → 总耗时

    **方法级堆栈(`stack_details`):**

    stack_details.{key}.trace_id       → TraceID
    stack_details.{key}.rpc_id         → RpcID
    stack_details.{key}.service        → 服务名
    stack_details.{key}.operation      → 操作名
    stack_details.{key}.exception_id   → 异常 ID
    stack_details.{key}.stack_entries  → 方法级堆栈列表(api、duration、exception、line)
    stack_details.{key}.formatted      → 格式化后的堆栈文本

    **SLS 日志(`sls`):**

    sls.store_stats              → 每个 logstore 的查询统计(必须全部展示)
    sls.logs_by_logstore         → 按 logstore 分组的日志(必须按组展示,不能合并)
    sls.error_logs               → ERROR 级别日志

    **根因分析(`analysis`):**

    analysis.root_cause          → 根本原因结论
    analysis.findings            → 关键发现列表
    analysis.suggestions         → 排查建议列表

    Step 3.5:无数据时循环询问时间范围(必须严格遵守)

    > **核心规则:查不到数据就问用户,用户给了新时间就重查,如此循环直到查到数据或用户放弃。绝对不能自动重试,绝对不能输出空报告。**

    如果 JSON 输出中 `no_data` 为 `true`(SLS 和 ARMS 均无数据):

    **第一次无数据 → 输出以下提示,等待用户回复:**

    > ⚠️ 在最近 {当前查询范围,如"1周"} 内({time_range})未查到任何数据。

    >

    > 回复序号或直接输入时间范围:

    >

    > `1` 换时间重查 — 输入自然语言(如 `1个月`、`2周`、`3天`)

    > `2` 精确时间段 — 输入起止时间(如 `2024-03-10 00:00 ~ 2024-03-15 23:59`)

    > `3` 换条件重查 — 输入新的 trace_id / wusid / path

    > `4` 不用了 — 停止查询

    **收到用户回复后:**

  • `1` 或直接输入时间(如"1个月"、"2周"、"3天")→ 用 `--duration` 重新执行 Step 2,然后回到 Step 3
  • `2` 或输入精确时间段(如"3月10号到3月15号")→ 计算为 `--start/--end` 重新执行
  • `3` → 回到 Step 1.2 重新收集参数
  • `4` 或"不用了"、"算了"、"停" → 停止,输出简短结论:「在所有尝试的时间范围内均未查到该 TraceID 的数据,可能原因:1) TraceID 不正确 2) 日志已过期被清理 3) 该请求未经过当前 SLS 项目」
  • **再次无数据(第二次、第三次…) → 继续循环询问:**

    > ⚠️ 在 {本次时间范围} 内仍未查到数据。

    >

    > `1` 换时间继续 — 输入新的时间范围

    > `2` 换条件重查 — 输入新的 trace_id / wusid / path

    > `3` 不用了 — 停止查询

    **循环规则:**

    1. 每次查不到数据 → 必须停下来问用户 → 等用户回复 → 按用户指示执行

    2. **绝不跳过询问直接输出报告**

    3. **绝不自行决定用什么时间重试**

    4. 用户在此上下文中说的任何时间表述,一律视为新的查询时间范围

    5. 只有 `no_data` 为 `false`(查到数据了)才进入 Step 4 输出完整报告

    Step 4:输出分析报告(格式严格按下方执行)

    ---

    **📋 问题定位报告**

    | 项目 | 内容 |

    |------|------|

    | TraceID | `{query.trace_id 或 discovered_traces 中用户选择的 trace_id}` |

    | WSUID | `{query.wusid,无则省略此行}` |

    | 请求路径 | `{query.path,无则省略此行}` |

    | 时间范围 | `{time_range}` |

    | 涉及服务 | `{call_chain.services}` |

    | 总耗时 | `{call_chain.total_duration_ms}ms` |

    ---

    **🗺️ ARMS 调用链路图**(此段必须输出,不可跳过)

    > 判断条件:`call_chain.total_spans > 0` 表示有数据,`== 0` 表示无数据。

    > `call_chain.tree` 始终有值(无数据时也有提示文本),**必须原样输出**。

    {call_chain.tree 的完整内容,一字不改直接输出}

    > 示例(有数据时):

    > ```

    > ● [rpc-ny] gRPC → /PromotePB/UpdateRelation 156ms ❌

    > └─ [promote-service] MySQL → SELECT 12ms ✅

    > ⚡ 错误: record not found

    > 🔗 异常ID: 811073848360427400

    > ```

    >

    > 示例(无数据时,脚本输出的 tree 已包含提示):

    > ```

    > ⚠️ ARMS 未采样到此 TraceID 的调用链

    > ```

    ---

    **❌ 异常 Span**(此段必须输出,不可跳过)

    > 判断条件:`call_chain.error_spans` 列表是否非空。

    **有异常 Span(`call_chain.error_count > 0`)时,逐个输出:**

    | 服务 | 操作 | 异常 ID | 耗时 | 错误信息 |

    |------|------|---------|------|---------|

    | `{service}` | `{operation}` | `{exception_id}` | `{duration_ms}ms` | `{tags.error.message 或 tags.exception.message}` |

    每个异常 Span 下方,如果有 `full_stack`,必须输出完整堆栈:

    🔗 异常ID: {exception_id}
    ⚡ 堆栈:
    {full_stack 完整内容,不截断,逐行输出}

    **无异常 Span(`call_chain.error_count == 0`)时,输出:**

    > 无异常 Span(ARMS 未采样或调用链无错误)

    ---

    **🔬 方法级堆栈详情(GetStack)**

    > 判断条件:`stack_details` 不为 null 且非空对象。

    **有 `stack_details` 数据时,逐个输出:**

    ── [{service}] {operation} → 异常ID: {exception_id} ──
    {formatted 的完整内容,一字不改直接输出}

    > 示例:

    > ```

    > ── [rpc-ny] UpdateRelation → 异常ID: 811073848360427400 ──

    > [ 1] com.ny.service.PromoteService.updateRelation (服务: rpc-ny) 156ms L212

    > ⚡ 异常: record not found

    > [ 2] com.ny.dao.PromoterDAO.getByWusId (服务: rpc-ny) 12ms L89

    > ```

    **无 `stack_details` 数据时,输出:**

    > 无方法级堆栈(ARMS 未采样或无异常 Span)

    ---

    **📄 SLS 日志 — 按 LogStore 分组**

    > ⚠️ 以下每个 LogStore 单独展示,不合并,不去重

    **查询统计:**

    | LogStore | 状态 | 日志条数 |

    |----------|------|---------|

    | `{logstore1}` | `{status}` | `{count}` |

    | `{logstore2}` | `{status}` | `{count}` |

    ---

    **【LogStore: {logstore名称1}】**(共 {count} 条)

    逐条输出该 logstore 的每条日志:

    [1] 时间:{time}
        级别:{level}
        服务:{service}
        文件:{file}
        消息:{message}
        附加:{raw 中的 attach / request / response 等关键字段}

    ---

    **【LogStore: {logstore名称2}】**(共 {count} 条)

    逐条输出该 logstore 的每条日志(同上格式):

    [1] 时间:{time}
        级别:{level}
        服务:{service}
        文件:{file}
        消息:{message}
        附加:{raw 中的关键字段}

    ---

    **🔍 根因分析**

  • **直接原因**:{结合 ARMS error_spans 和 SLS error_logs 的错误信息}
  • **触发位置**:{service} → {operation}(来自哪个 logstore 第几条)
  • **关联日志**:{指明是哪个 logstore 的第几条}
  • **根本原因**:{综合分析}
  • **🛠️ 建议修复方向**

    {修复建议}

    ---

    Step 4.5:报告输出后的后续操作提示(必须严格按模板)

    > **⚠️ 核心规则:输出完 Step 4 报告后,必须且只能输出下面的统一模板,禁止自由发挥任何后续操作文字。**

    > **禁止行为:**

    > - 输出不带序号的选项,如"继续操作:新 trace_id / 用 wusid 查 / 不用了"

    > - 省略"查看代码"选项

    > - 自编任何不在模板中的提示文字

    **无论查询结果如何(成功/部分失败/有异常/无异常),Step 4 报告末尾统一输出以下模板:**

    > 回复序号选择下一步:

    >

    > `1` 排查代码 — 搜索 `{operation}` 方法源码,定位问题

    > `2` 换条件重查 — 输入新的 trace_id / wusid / path

    > `3` 换时间重查 — 输入新的时间范围(如 `1个月`、`3天`)

    > `4` 用 wusid 查用户请求 — 输入 wusid 查该用户的所有请求

    > `5` 不用了 — 结束排查

    其中 `{operation}` 替换为 ARMS error_spans 中的操作名(如 `UpdateRelation`),无 ARMS 数据时替换为请求路径中的方法名。

    **用户回复处理:**

  • `1` → 直接进入 Step 5 代码排查
  • `2` → 回到 Step 1.2 重新收集参数
  • `3` → 用新时间范围重新执行 Step 2
  • `4` → 用户提供 wusid 后,以模式 B 重新执行 Step 2
  • `5` → 输出简短结论,结束
  • ---

    Step 5:代码级排查(必须自动执行,不能只建议)

    > **⚠️ 核心规则:输出完 Step 4 报告后,如果存在 ERROR 日志或异常 Span,必须立即自动执行代码搜索,不能只输出"建议搜索 xxx 方法"之类的文字。**

    > 如果日志和调用链均无异常,跳过此步。

    >

    > **禁止行为**:输出类似"建议:在代码仓库搜索 UpdateRelation 方法"的文字而不实际执行搜索。必须直接使用 Grep/Glob/Read 工具去搜索代码。

    #### 5.1 提取代码线索

    从 Step 3/4 的结果中提取以下信息,作为代码搜索的关键词:

    | 来源 | 提取内容 | 用途 |

    |------|---------|------|

    | SLS 日志 `file` 字段 | 文件名和行号(如 `handler.go:156`) | 直接定位源码位置 |

    | SLS 日志 `message` 字段 | 错误消息关键词(如 `record not found`、`nil pointer`) | 搜索错误产生位置 |

    | ARMS `error_spans` | 服务名 + 操作名(如 `promote-service` → `UpdateRelation`) | 定位入口函数 |

    | ARMS `tags` | `exception.type`、`error.message`、`db.statement` | 定位异常类型和 SQL |

    | ARMS `stack_details` | 方法级堆栈中的类名、方法名、行号 | 精确定位异常代码位置 |

    | SLS 日志 `raw` | `data.request`、`data.response` 中的业务字段 | 理解请求上下文 |

    #### 5.2 搜索源码

    **按优先级依次搜索(找到即停):**

    1. **有明确文件名+行号**(如 `caller: service/handler.go:156`)

    - 直接用 Grep 搜索该文件名,用 Read 读取对应代码段(前后各 30 行)

    2. **有函数/方法名**(如 ARMS 的 `operation: UpdateRelation`)

    - 用 Grep 搜索函数定义:`func.*UpdateRelation` 或 `def UpdateRelation`

    - 读取函数完整实现

    3. **有错误消息**(如 `record not found`、`duplicate key`)

    - 用 Grep 在项目中搜索该错误消息字符串

    - 找到错误产生的代码位置

    4. **有请求路径**(如 `/ny.apps_pb.promote_pb.PromotePB/UpdateRelation`)

    - 路径中提取服务名和方法名(`PromotePB` / `UpdateRelation`)

    - 搜索 proto 定义和对应的 handler 实现

    5. **有 GetStack 方法级堆栈**(`stack_details` 不为空)

    - 从堆栈条目的 `api` 字段提取类名.方法名(如 `com.xxx.service.UpdateRelation`)

    - 用 Grep 搜索对应的类定义和方法实现

    - 堆栈中有 `exception` 字段的条目优先搜索

    > **搜索范围与代码仓库定位规则:**

    >

    > 1. 先在当前工作目录用 Grep 搜索关键方法/类名

    > 2. 如果当前目录搜不到(0 个结果),**输出以下提示(严格按模板)**:

    >

    > ```

    > 💻 需要搜索代码仓库来定位问题源码。

    >

    > 当前目录未找到相关代码,请提供业务代码仓库路径:

    > - 示例:`C:\projects\promote-service` 或 `/home/user/go/src/promote`

    > - 如果有多个服务,可提供多个路径,用 `;` 分隔

    > ```

    >

    > 3. 用户提供路径后 → 在该路径下用 Grep 搜索,然后继续 5.3 分析

    > 4. **必须实际执行搜索**:使用 Grep 工具搜索代码,不能只输出文字建议

    #### 5.3 分析代码问题

    找到相关代码后,分析以下内容:

  • **错误触发路径**:从入口函数到报错位置的调用链路
  • **错误原因**:参数校验缺失?空指针?异常未捕获?逻辑错误?
  • **上下文数据**:结合 SLS 日志中的 request/response 数据,还原触发条件
  • #### 5.4 输出代码分析

    **💻 代码排查**
    
    **定位文件:** `{file_path}:{line_number}`
    
    **关键代码段:**
    ​```{language}
    // 标注问题所在行
    {code snippet with comments}
    ​```
    
    **问题分析:**
    - 错误路径:{入口} → {中间调用} → {报错位置}
    - 直接原因:{具体代码问题,如"第 156 行未检查 err 返回值"}
    - 触发条件:{结合日志中的 request 数据说明什么情况下会触发}
    
    > ⚠️ 仅指出代码问题,不直接修改代码。由用户自行决定如何修复。

    ---

    Step 6:数据库排查(当错误涉及数据库时)

    > **触发条件**:仅当以下任一条件满足时才执行此步骤:

    > - ARMS tags 中有 `db.statement`、`db.type` 字段

    > - 错误消息包含 SQL/数据库相关关键词(`duplicate key`、`deadlock`、`record not found`、`foreign key`、`table doesn't exist`、`column not found`、`timeout` + `sql`/`db`/`mysql`/`redis`)

    > - SLS 日志中出现 SQL 语句或数据库错误

    > - 代码排查中发现 ORM 操作或 SQL 拼接

    >

    > 不满足以上条件则跳过此步骤。

    #### 6.1 提取数据库线索

    | 来源 | 提取内容 |

    |------|---------|

    | ARMS `tags.db.statement` | 完整 SQL 语句 |

    | ARMS `tags.db.type` | 数据库类型(MySQL/Redis/ES) |

    | SLS 日志 | SQL 相关错误消息 |

    | Step 5 代码 | ORM 模型定义、SQL 拼接逻辑、表名/字段名 |

    #### 6.2 分析数据库问题

    根据错误类型进行针对性分析:

    | 错误类型 | 排查方向 |

    |---------|---------|

    | `record not found` | 查询条件是否正确?数据是否存在?是否有软删除过滤? |

    | `duplicate key` | 唯一索引冲突,检查插入逻辑是否有并发问题或重试机制 |

    | `deadlock` | 事务中的锁顺序,是否有交叉更新 |

    | `timeout` | 慢 SQL,检查是否缺少索引、全表扫描、大事务 |

    | `foreign key` | 外键约束失败,检查关联数据是否存在 |

    | `connection refused` | 数据库连接池耗尽或实例宕机 |

    #### 6.3 搜索相关代码中的数据库操作

  • 在 Step 5 定位到的代码文件中,搜索 ORM 操作(如 `db.Where`、`db.Create`、`Model.objects`)
  • 查找表结构定义(model/schema)
  • 查找 SQL 拼接或 Raw SQL
  • #### 6.4 输出数据库分析

    **🗄️ 数据库排查**
    
    **涉及表/操作:** `{table_name}` — `{SELECT/INSERT/UPDATE/DELETE}`
    
    **问题 SQL:**
    ​```sql
    {SQL 语句,标注问题部分}
    ​```
    
    **分析:**
    - 错误类型:{如 duplicate key on index `idx_xxx`}
    - 原因:{如并发插入同一唯一键}
    - 对应代码:`{file}:{line}` — {代码描述}
    
    **🔎 建议检查的数据库配置项:**
    - 表:`{table_name}`
    - 字段/索引:`{需要检查的字段或索引名}`
    - 检查内容:{如"确认该用户的 xxx 字段值是否为 null"、"检查 idx_xxx 索引是否存在"、"核实 xxx 配置表中 key=yyy 的记录是否正确"}
    - 参考 SQL:`SELECT ... FROM {table} WHERE {condition}`

    > ⚠️ 仅指出应该检查哪些数据库配置项和数据,不直接执行 SQL。由用户或 DBA 自行查询确认。

    ---

    Step 7:综合结论与修复建议

    > 在完成所有排查后(Step 4 报告 + Step 5 代码 + Step 6 数据库),输出最终综合结论。

    **📝 综合结论**
    
    **问题链路:**
    {用户请求} → {入口服务} → {中间调用} → {出错位置}
    
    **根本原因:**
    {一句话总结,结合日志 + 代码 + 数据库的分析}
    
    **代码问题:**
    1. {文件:行号} — {问题描述}
    2. {文件:行号} — {问题描述}
    
    **需要检查的数据库配置:**
    1. 表 `{table}` — {检查什么,附参考 SQL}
    2. 配置项 `{key}` — {检查什么}
    
    **修复方向(按优先级):**
    1. 【紧急】{问题描述 + 修复思路}
    2. 【建议】{预防性改进}
    3. 【优化】{长期优化方向}
    
    **影响范围:**
    - 受影响接口:{path}
    - 受影响用户:{wusid 相关信息}
    - 影响程度:{根据 error_logs 数量和 error_spans 判断}

    > ⚠️ 本报告仅指出问题和排查方向,不直接修改代码或执行数据库操作。

    ---

    Step 8:询问用户是否需要进一步操作

    输出综合结论后,**严格按以下模板输出**:

    > 🔧 需要进一步操作吗?回复序号:

    >

    > `1` 查看更多代码 — 深入分析相关文件或上下游调用

    > `2` 查看更多日志 — 换条件 / 换时间范围重新查询

    > `3` 分析其他 TraceID — 输入新的查询条件

    > `4` 不用了 — 结束排查

    ---

    注意事项

  • **每个 logstore 的日志必须独立展示**,哪怕内容高度相似也不能合并
  • ARMS 未采样到时(call_chain 为 null),只展示 SLS 日志,注明"未采样到调用链"
  • TraceID 长度为 30 位时 ARMS 不需要时间范围;其他长度需要 `--start/--end`
  • SLS 和 ARMS 可以用不同的 AK/SK
  • 模式 B 使用 `--no-interactive`,脚本自动选第一条 TraceID;如需让用户选择,展示 `discovered_traces` 列表后用模式 A 重跑
  • `--wusid` 同时匹配 `wechat_user_space_id` 和 `promoter_wechat_user_space_id` 两个字段
  • `--path` 匹配 `data.request.path` 字段,支持完整路径或路径片段
  • // Comments
    Sign in with GitHub to leave a comment.
    // Related skills

    More tools from the same signal band