Skill: ccrazyfish/sls-trace-analysis (version 1.0.0)

--- 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（直接分析）** ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" ``` 自定义时间范围（自然语言）： ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --duration "3天" ``` 精确时间范围： ```bash 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）： ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --skip-sls ``` 只查 SLS（跳过 ARMS）： ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --trace-id "TraceID" --skip-arms ``` **模式 B：未知 TraceID，通过 wusid / path 先检索** 按用户 ID 检索： ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --wusid "76149226" --no-interactive ``` 按请求路径检索： ```bash python "%USERPROFILE%\.openclaw\workspace\skills\sls-trace-analysis\scripts\query_trace.py" --path "/ny.apps_pb.promote_pb.PromotePB/UpdateRelation" --no-interactive ``` 两者组合（精确缩小范围）： ```bash 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` 字段，支持完整路径或路径片段


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)