关于 investigating-with-observability
该技能为使用 VictoriaMetrics、VictoriaLogs、VictoriaTraces 和 AlertManager 的排障提供分阶段流程,面向需要依据观测数据定位问题的 Agent。它强调先发现数据和告警,再提出假设,并通过至少两类信号交叉验证结论。
主要功能
- 01按四个阶段组织排障
- 02先发现指标、日志和追踪数据
- 03基于证据提出并测试假设
- 04跨信号类型交叉验证
- 05按环境变量选择可用后端
适用场景
- 01调查服务错误或崩溃
- 02分析请求延迟和资源异常
- 03核对告警并寻找故障根因
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ victoriametrics/ skills --skill investigating-with-observability安装后在 Claude Code 中输入/investigating-with-observability确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/alertmanager-check.mdlogs-discovery.mdmetrics-discovery.mdtraces-discovery.md详细介绍
使用可观测性技能进行故障排查
核心原则
随机查询会浪费时间,并产生误导性结果。错误的指标名称导致的空结果,看起来和“没有问题”完全一样。没有假设就跳转查看不同信号,会让排查陷入混乱。
先发现,再查询。先提出假设,再关联。先确认,再下结论。
如果尚未完成阶段 1,就不能提出根因。如果尚未关联至少两种信号类型,那么结论就只是猜测。
调查流程
完成每个阶段后,再进入下一阶段。
Phase 1: Gather Signals → What's already known? What's alerting?
Phase 2: Discover and Scope → What data exists? What are the real names?
Phase 3: Hypothesize and Test → Form one theory, query to confirm or refute
Phase 4: Correlate and Confirm → Cross-reference across signal types, find root cause
阶段 1:收集信号
编写任何查询之前,先了解已有信息。
1. 检查环境变量是否可用 —— 运行“子 Agent 调度”部分中的门控检查。
2. 并行调度负责收集信号的子 Agent:
| 子 Agent | 条件 | 执行内容 |
|---|---|---|
| AlertManager 检查 | VM_ALERTMANAGER_URL 可用 | 检查 VM 告警、AlertManager 告警及静默规则 |
| 指标发现(仅告警) | VM_METRICS_URL 可用且 VM_ALERTMANAGER_URL 不可用 | 当无法调度 AlertManager Agent 时,检查 VM 告警作为备用 |
如果 VM_ALERTMANAGER_URL 可用,AlertManager 检查 Agent 会同时处理 VM 告警和 AlertManager 查询,无需再单独调度负责告警的指标 Agent。
读取 Agent 提示词文件,并在一次 Agent 工具调用中完成调度。向每个子 Agent 的提示词中加入:
- Agent 文件内容
- 调查目标(如果已知,包括命名空间、服务或组件名称)
3. 综合结果 —— 子 Agent 返回后:
- 汇总所有来源的告警发现
- 建立时间线:症状何时开始?发生了什么变化?
- 如果时间线不清楚,请询问用户
4. 确定首先查看哪种信号类型:
| 症状 | 首先查看 | 然后关联 |
|---|---|---|
| 资源/速率问题 | 指标 | 日志 |
| 错误/崩溃 | 日志 | 指标 |
| 延迟/请求缓慢 | 追踪 | 日志 |
| 告警触发 | 指标(告警详情) | 日志 + 追踪 |
阶段 2:发现并确定范围
切勿猜测指标名称、日志字段名称或服务名称。 发现是必需步骤,它能避免最常见的调查失败:根据空结果得出结论,而空结果可能是由错误名称导致的。
并行调度所有可用后端的发现子 Agent。读取每个 Agent 提示词文件,并在一次 Agent 工具调用中完成调度。向每个子 Agent 的提示词中加入:
- Agent 文件内容
- 目标命名空间和/或服务名称(来自阶段 1 的发现)
- 调查时间范围(RFC3339 格式)
- 要搜索的具体关键词或组件
| 子 Agent | 条件 |
|---|---|
| 指标发现 | VM_METRICS_URL 可用 |
| 日志发现 | VM_LOGS_URL 可用 |
| 追踪发现 | VM_TRACES_URL 可用 |
综合发现结果:
- 合并所有后端发现的名称
- 记录哪些后端有目标数据,哪些没有
- 找出在阶段 3 假设验证中信号最丰富的来源
复杂查询请参考技能文档。 你无法从训练数据中掌握 LogsQL 语法——它与 Loki LogQL 不同。对于超出子 Agent 已执行查询范围的复杂查询,请调用相应的 *-query 技能,或使用下方的 LogsQL 快速参考。
阶段 3:提出假设并进行测试
发现后,先提出一个具体假设,再进行后续查询。
明确陈述假设:“我认为 [组件 X] 正在 [故障/运行缓慢/内存溢出],因为 [阶段 1 中的证据 Y]。”
尽量少做测试:
- 查询一项内容,以证实或证伪假设
- 不要一次查询所有内容,否则会被数据淹没
- 先使用即时查询(成本更低、速度更快),再使用范围查询
如果假设不成立:
- 不要在现有查询基础上继续添加查询,而要提出一个新假设
- 重新检查阶段 1 和阶段 2 揭示的内容
- 思考:发现过程中是否出现了意外情况?
连续 3 个假设失败后:停止。 连续 3 次猜错,说明你遗漏了某个根本因素。可能是:
- 还没有发现某个关键数据源
- 范围有误(命名空间、服务或时间范围不同)
- 需要向用户询问更多背景信息
阶段 4:关联并确认
单一信号类型不能作为证据。下结论前,至少关联两种信号。
并行派发关联分析子 Agent,处理所需的信号类型。重复使用 agents/ 中相同的 Agent 提示词文件,但提供具体查询,而不是发现任务。每个子 Agent 的提示词中都应包含:
- Agent 文件内容
- 要执行的具体查询(指标表达式、日志筛选条件、链路搜索参数)
- 要查询的准确时间范围(根据阶段 3 的发现缩小范围)
- 要查找的内容(阶段 3 中已确认的假设)
并行派发关联分析的示例:
- 指标 Agent:“从 T1 到 T2 查询
rate(http_requests_total{code=~'5..', namespace='myapp'}[5m])” - 日志 Agent:“从 T1 到 T2 搜索
{namespace='myapp'} error,并返回示例消息” - 链路 Agent:“从 T1 到 T2 搜索服务
myapp的链路,并设置minDuration=1s”
**只有完成关联分析后:**才能提出根因和修复措施。
危险信号 — 停止并返回阶段 1
如果你发现自己正在:
- 只查询了一种信号类型,就提出根因
- 不检查语法,凭记忆编写 LogsQL 查询
- 查询尚未通过发现确认存在的指标名称
- 遇到空结果就断定“没有问题”
- 因为“可能不是这个原因”而跳过告警检查
- 运行五个不同的查询,指望其中一个能发现问题
- 说“我再试试……”而不是先提出假设
以上情况都意味着:停止。你是在猜测,而不是调查。
常见借口
| 借口 | 实际情况 |
|---|---|
| “我知道指标名称” | 也许吧。发现只需 2 秒,就能避免花 20 分钟追查空结果。 |
| “告警在这里没用” | 检查告警无需成本,而且其中经常包含确切答案。跳过检查可能会付出代价。 |
| “只需要快速检查一下日志” | 不先发现就快速检查日志,会导致字段名称错误和误导性结果。 |
| “空结果 = 没有问题” | 空结果更常意味着查询有误,而不是问题不存在。先确认名称。 |
| “我稍后再做关联分析” | 单一信号得出的结论只是猜测。声称找到根因前先进行关联分析。 |
| “LogsQL 和 LogQL/Elasticsearch 差不多” | 并非如此。语法差异会导致查询静默失败。请查阅参考资料。 |
环境
环境由环境变量控制。检查当前状态:
echo "VM_METRICS_URL: $VM_METRICS_URL"
echo "VM_LOGS_URL: $VM_LOGS_URL"
echo "VM_TRACES_URL: $VM_TRACES_URL"
echo "VM_ALERTMANAGER_URL: $VM_ALERTMANAGER_URL"
echo "VM_CURL_CONFIG: ${VM_CURL_CONFIG:-(unset - no auth)}"
如果不确定应用在哪个环境中运行,请询问用户。
子 Agent 派发
此技能会在各阶段的交界处并行派发子 Agent,以加快调查速度。每个子 Agent 都包含内嵌的 API 参考资料,并返回结构化的发现结果。
环境变量门控
每轮派发前,检查哪些后端可用:
echo "METRICS:${VM_METRICS_URL:+available}"
echo "LOGS:${VM_LOGS_URL:+available}"
echo "TRACES:${VM_TRACES_URL:+available}"
echo "ALERTMANAGER:${VM_ALERTMANAGER_URL:+available}"
仅为报告状态为 available 的后端派发子 Agent。 如果环境变量为空或未设置,不要派发子 Agent。
如何派发
- 从
agents/目录(相对于此技能所在目录)读取 Agent 提示词文件 - 使用 Agent 工具进行派发,并包含:
- Agent 提示词文件内容作为基础指令
- 调查上下文:目标命名空间、服务名称、时间范围(RFC3339)
- 要查找的具体查询或指标
- 在同一条工具调用消息中派发相互独立的子 Agent,以便并行执行
- 为每个子 Agent 设置
allowed-tools: Bash(curl:*), Bash(jq:*), Bash(date:*)
Agent 文件
| Agent | 文件 | 需要 | 用于 |
|---|---|---|---|
| AlertManager 检查 | agents/alertmanager-check.md | VM_ALERTMANAGER_URL + VM_METRICS_URL | 阶段 1 |
| 指标发现 | agents/metrics-discovery.md | VM_METRICS_URL | 阶段 2、4 |
| 日志发现 | agents/logs-discovery.md | VM_LOGS_URL | 阶段 2、4 |
| 链路追踪发现 | agents/traces-discovery.md | VM_TRACES_URL | 阶段 2、4 |
技能与 API 的映射
victoriametrics-query = Metrics only (MetricsQL/PromQL) → $VM_METRICS_URL
victorialogs-query = Logs only (LogsQL) → $VM_LOGS_URL
victoriatraces-query = Traces only (Jaeger API) → $VM_TRACES_URL
alertmanager-query = AlertManager (silences, routing) → $VM_ALERTMANAGER_URL
切勿跨后端调用 API。每种数据类型都要使用正确的环境变量和端点。
AlertManager 提供 VM 告警所不具备的能力:静默和抑制状态。但它运行在集群内,可能会宕机——如果不可用,请回退到 $VM_METRICS_URL/api/v1/alerts。
时间戳格式
| 后端 | 参数 | 格式 | 示例 |
|---|---|---|---|
| VictoriaMetrics | start/end | RFC3339 字符串 | 2026-02-06T09:00:00Z |
| VictoriaLogs | start(必需)、end | RFC3339 字符串 | 2026-02-06T09:00:00Z |
| VictoriaTraces | start/end | Unix 微秒数值 | 1738836000000000(16 位) |
| VictoriaTraces(依赖关系) | endTs/lookback | Unix 毫秒数值 | 1738836000000(13 位)/ 3600000 |
VictoriaLogs 的 start 始终为必需项——省略它会扫描所有已存储的数据(开销极大)。
发现流程
针对每种信号类型,按以下顺序操作。要查看完整的 API 详情和其他端点,请调用对应的查询技能。
指标发现 → victoriametrics-query 技能
- 按关键词搜索元数据:
$VM_METRICS_URL/api/v1/metadata?metric=<keyword>&limit=10 - 获取标签值以限定范围:
$VM_METRICS_URL/api/v1/label/<label_name>/values(使用match[]过滤) - 获取命名空间的时间序列:
$VM_METRICS_URL/api/v1/series?limit=20,并使用match[]={namespace="X"} - 然后查询——即时查询使用
api/v1/query,范围查询使用api/v1/query_range(范围查询需要start,格式为 RFC3339)
日志发现 → victorialogs-query 技能
VictoriaLogs 的所有端点都需要 start(RFC3339)。查询参数请使用 --data-urlencode。
- 流字段名称:
$VM_LOGS_URL/select/logsql/stream_field_names?start=<RFC3339> - 流字段值:
$VM_LOGS_URL/select/logsql/stream_field_values?start=<RFC3339>&field=namespace - 分面(最佳发现工具——一次调用即可获取所有字段的分布):
$VM_LOGS_URL/select/logsql/facets?start=<RFC3339> - 非流字段名称:
$VM_LOGS_URL/select/logsql/field_names?start=<RFC3339> - 然后查询(响应为 JSON Lines):
$VM_LOGS_URL/select/logsql/query?start=<RFC3339>&limit=100
链路追踪发现 → victoriatraces-query 技能
链路追踪发现端点不接受任何时间范围参数:
- 列出服务:
$VM_TRACES_URL/api/services - 获取服务的操作:
$VM_TRACES_URL/api/services/<service>/operations - 依赖关系(Unix 毫秒数值,13 位):
$VM_TRACES_URL/api/dependencies?endTs=<ms>&lookback=3600000 - 然后搜索链路追踪(必须指定
service,时间使用 Unix 微秒,16 位):$VM_TRACES_URL/api/traces?service=<svc>&start=<µs>&end=<µs>&limit=20
LogsQL 快速参考
如需完整的 LogsQL 语法,请调用 victorialogs-query 技能。要点如下:
- LogsQL 使用空格分隔(默认执行 AND)。管道使用
|。 - 流筛选器:
{namespace="myapp"} - 单词筛选器:
{namespace="myapp"} error - OR:
(error OR warning),正则表达式:~"err|warn",特定字段:level:error - 时间筛选器:
_time:1h(可替代 API 的start/end参数——二者择一使用,不能同时使用) - 否定:
-"expected error" - 统计:
| stats by (level) count() as total
常见错误:| grep 不存在(请使用单词筛选器或 ~"regex")。| filter 仅在 | stats 之后有效。流字段名称取决于采集配置——请先发现字段。
调查手册
“应用运行缓慢”
- 阶段 1:检查告警。确定时间线——延迟何时开始升高?
- 阶段 2:发现与该应用匹配的链路追踪服务和指标
- 阶段 3:提出假设——“根据[告警/用户报告],延迟出现在[服务 X]”
- 查询该服务的延迟/错误率指标
- 使用
minDuration筛选器搜索链路追踪,找出缓慢的跨度
- 阶段 4:将链路追踪时间戳与这些时段前后的日志关联起来
“Pod 反复崩溃重启”
- 阶段 1:检查告警(可能已显示 KubePodCrashLooping)。获取 Pod 名称。
- 阶段 2:发现重启次数、内存使用量指标。发现该 Pod 的日志流。
- 阶段 3:提出假设——OOM?存活探针失败?启动时崩溃?
- 按固定间隔崩溃 → 存活探针。崩溃前内存激增 → OOM。
- 阶段 4:将错误日志与指标时间戳关联,以确认原因。
“资源持续增长”
- 阶段 1:检查告警。增长速度有多快?
- 阶段 2:发现该命名空间/Pod 的资源使用量指标
- 阶段 3:提出假设——泄漏?负载增加?缺少限制?
- 使用
deriv()或increase()量化增长速率 - 检查各 Pod 的细分数据,找出问题所在
- 使用
- 阶段 4:将其与日志中的部署事件关联起来。增长是否始于某次部署之后?
常见错误
| 错误 | 修正方法 |
|---|---|
| 猜测指标名称 | 使用元数据端点:$VM_METRICS_URL/api/v1/metadata?metric=keyword |
| 凭记忆编写 LogsQL | 参考上面的 LogsQL 快速参考或 victorialogs-query 技能 |
| 时间戳格式错误 | 请参见上面的时间戳格式表 |
| 跳过告警检查 | 先查询 $VM_METRICS_URL/api/v1/alerts——这是免费的 |
| 结果为空就认为“没有问题” | 先通过发现确认指标/字段名称是否存在 |
探索日志时未使用 facets | facets 一次调用即可返回字段分布 |
| 未对查询进行 URL 编码 | POST 请求请使用 --data-urlencode 'query=...' |
VictoriaLogs 查询缺少 start | 省略 start 会扫描所有数据(开销极大) |
忘记 match[] 需要 [] | 单独使用 match 无效——必须使用 match[] |
| 链路追踪的时间戳类型错误 | 搜索使用微秒(16 位数字),依赖关系使用毫秒(13 位数字) |
混淆 stats_query 和 stats_query_range | 即时查询使用 time,范围查询使用 start/end/step |
将 _time: 筛选器与 API start 混用 | 二者择一使用,不能同时使用 |
| 搜索“error”时捕获到 vmselect 噪声 | 添加 -"vm_slow_query_stats" 以排除 PromQL 文本 |
按 cluster 字段对日志分组 | Vector 日志缺少 cluster 流字段——请使用 kubernetes.pod_namespace |
| 因 AlertManager 故障而阻塞 | 以 VM 告警为主,尽力使用 AlertManager |
| 仅依据单一信号下结论 | 宣称根本原因前,至少关联两种信号类型 |