mcpField
G
grouping-noisy-errors

grouping-noisy-errors

github.com/posthog开发76325 次安装今天更新
代码仓库

关于 grouping-noisy-errors

这是一个 PostHog 技能,用于安全合并重复的错误追踪问题,并防止噪声指纹持续产生新问题。它指导开发者核对调用位置、合并历史问题,并创建范围严格的分组规则。

主要功能

  1. 01比对异常类型、SDK、堆栈、消息和处理状态
  2. 02合并已确认的重复问题
  3. 03创建规则以分组后续事件
  4. 04检查现有规则并验证结果

适用场景

  1. 01合并因堆栈或消息动态数据而重复的问题
  2. 02清理不会再出现的历史重复问题
  3. 03防止重复错误持续产生新指纹

MCP 相关

使用 PostHog MCP 工具查询问题和事件、合并或拆分问题,以及管理分组规则。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/posthog/skills --skill grouping-noisy-errors

安装后在 Claude Code 中输入/grouping-noisy-errors确认已加载。

详细介绍

对噪声错误进行归组

当堆栈帧或消息中包含易变数据(随机 ID、动态文件路径、构建哈希、匿名函数名称)时,同一个错误可能会被报告为数十个独立问题。解决方法分两步:先将现有问题合并到一个目标问题中,再创建归组规则,让来自同一调用位置的后续事件共享一个规范指纹,而不是不断产生新指纹。

首先要明确:“同一个错误”的定义范围很窄。如果两个问题只是名称相同,或消息文本中有相同的句子,但来自不同代码路径、不同 SDK 或不同运行时,它们就是不同的错误,应保持分开,即使用户认为它们是“同一类 Bug”。因为消息中都包含“undefined”,就把前端的 TypeError 和后端的 TypeError 归为一组,会破坏团队定位各自问题所需的信号。步骤 1 中的标准就是为了避免这种情况。

可用工具

工具用途
posthog:query-error-tracking-issues-list查找可能重复的问题
posthog:query-error-tracking-issue获取单个问题的简要详情
posthog:query-error-tracking-issue-events获取带有堆栈和消息的采样 $exception 事件
posthog:error-tracking-issues-merge-create将现有问题合并到目标问题
posthog:error-tracking-issues-split-create如果合并出错,将指纹精准拆分回原状
posthog:error-tracking-grouping-rules-create自动将后续事件归入同一个问题
posthog:error-tracking-grouping-rules-list添加新规则前检查现有归组规则
posthog:error-tracking-issues-partial-update合并后重命名目标问题或重新描述它

合并与归组规则

这两种工具分别解决问题的不同部分:

  • 合并是一次性操作。它会将现有问题合并到一个目标问题中,并重新关联其事件。后续事件仍会按原始指纹归组——如果相同的噪声模式不断产生新指纹,合并就会变成无休止的重复操作。
  • 归组规则具有持久性。它会在事件入库时,将任何匹配事件的指纹改写为 custom-rule:<rule_id>,让所有后续匹配事件共享一个规范指纹,而不是产生新指纹。首次匹配时,系统会创建一个以该指纹为键的新问题,或将事件路由到已关联该指纹的问题。

如果问题会反复出现,请同时使用两者:将历史重复问题合并到目标问题中,然后创建规则。规则 API 不接受目标问题 ID——规则开始生效后,可以将生成的 custom-rule:... 问题合并到同一个目标问题中,从而保持归并结果。对于预计不会再次出现的历史问题扩散,只使用合并。对于刚出现、希望提前处理且无需与现有问题合并的新模式,只使用归组规则。

工作流

步骤 1 — 确认重复项

按异常类型或消息搜索候选项:

posthog:query-error-tracking-issues-list
{
  "searchQuery": "TypeError: Cannot read property",
  "status": "active",
  "limit": 50,
  "orderBy": "occurrences",
  "dateRange": { "date_from": "-30d" }
}

对每个候选项,获取一个采样异常事件,以比较堆栈、类型和消息:

posthog:query-error-tracking-issue-events
{
  "issueId": "<candidate_issue_id>",
  "limit": 1,
  "include": ["exception", "stacktrace", "environment"]
}

对每个候选项执行一次。工具默认使用 onlyAppFrames: true,让最上方的应用内帧一目了然。如果两个候选项的最上方帧和异常类型相同,它们很可能是同一个错误——但合并前,请根据下面的完整检查清单进行核实。

它们是同一个错误吗?

只有在以下各项全部匹配时,才将两个问题视为重复问题:

  • $lib 是同一个 SDK。浏览器/JS SDK 会将 $lib 记录为 web(而不是 posthog-js);服务端 SDK 使用 posthog-python、posthog-node 等。请使用 read-data-schema(查询 $exception 的 $lib 对应的 event_property_values)确认 确切值,不要凭猜测——值不正确会导致匹配结果为空,且不会提示错误。 即使异常类型相同,不同 SDK 的错误也几乎总是来自不同的代码路径。
  • 异常类型完全相同($exception_types)。
  • 应用内堆栈的顶部调用帧指向同一个文件和同一个函数。行号和该函数内的细微偏移可以不同;顶部调用帧位于不同文件或函数,就意味着是不同的 Bug。
  • 消息遵循相同的模板,差异仅限于易变数据——ID、哈希、时间戳、动态路径。如果差异是动词、对象或操作不同,那就是不同的 Bug。
  • $exception_handled 一致(都已处理或都未处理)。被捕获的变体和未被捕获的变体属于不同的代码路径,最好分开处理。

如果以上任何一项不匹配,它们就不是重复问题——请分别调查 (investigating-error-issue)。

不要将以下情况归为一组

以下故障模式会破坏调试信号。即使用户称它们为“同一类 Bug”,也不要跨以下任何情况归组:

  • 同一异常类型的前端和后端变体。 浏览器 Bundle 中的 TypeError 和 Node 服务中的 TypeError 名称相同,消息中也经常有相同的词,但堆栈、运行时和修复方法都不同。
  • 不同的 SDK / 平台。 web(浏览器/JS)与 posthog-python、posthog-node 属于不同的调用点。
  • 类型相同,但堆栈顶部的文件或函数不同。 从 OrderService.cancel 抛出的 NullPointerException 与从 PaymentService.refund 抛出的异常不是同一个 Bug,即使两者的消息都写着 “user was null”。
  • 已捕获与未捕获。 两个问题仅 $exception_handled 不同,通常表示某个代码路径会在一处吞掉错误,而在另一处让错误继续传播——将它们分开可以清楚地显示这一点。
  • 概念相似、恰好有共同短语的 Bug。 “Cannot read property of undefined” 会出现在许多相互独立的 Bug 中。没有匹配的堆栈帧,仅凭消息相似并不足以判定为同一问题。
第 2 步 — 选择目标问题

选择应吸收其他问题的问题:

  • 出现次数最多——保留占主导地位的问题,使仪表板数据保持连续
  • 名称和描述最佳——如果用户已添加注释,优先选择该问题
  • 最早的 first_seen——保留原始时间线

记下目标问题的 ID。其他候选项将成为要合并的 ids。

第 3 步 — 合并现有重复问题
posthog:error-tracking-issues-merge-create
{
  "id": "<target_issue_id>",
  "ids": ["<duplicate_id_1>", "<duplicate_id_2>", "..."]
}

合并具有破坏性(注释 destructive: true)——问题合并到目标后,源问题会从活动列表中移除。调用前请与用户确认目标。每次合并调用最多处理约 50 个源 ID,以便将故障影响范围限制在局部;如果涉及大量问题,请分批处理。

合并后的变更可能不会立即显示在问题列表中——调用后立即重新列出问题,短时间内仍可能看到源问题。如果后续的 error-tracking-issues-list 调用结果看起来没有变化,请等待几秒后重新查询,而不要再次发起合并。

如果合并后目标的元数据有误(例如某个重复问题的名称更好),请使用 error-tracking-issues-partial-update 修正目标的名称或描述,而不是重新合并。

步骤 4 — 判断是否需要创建分组规则

满足以下两个条件时,值得创建分组规则:

  • 此模式持续产生新的指纹(自上次合并后,仍出现了新的重复项)
  • 你可以用属性过滤器描述此模式,且不会意外涵盖无关错误

标准异常属性($exception_types、表示消息的 $exception_values、表示文件路径的 $exception_sources、表示函数名称的 $exception_functions)在捕获时都是数组。PostHog 的属性过滤器会对它们做特殊处理:每个过滤器都会匹配数组中的各个元素,因此所有标准运算符(exact、is_not、icontains、not_icontains、regex、not_regex)都可以直接使用值: exact "TypeError",而不是 exact '["TypeError"]' 或 regex '"TypeError"'。

单数形式($exception_type、$exception_message)和 $exception_stack_trace_raw 只会出现在不到百分之一的事件中;以它们为条件创建的规则会悄无声息地永远无法匹配。

如果消息存在变化(例如,TypeError at /static/main.<hash>.js),可以在 $exception_values 上使用 regex 过滤器。如果已知文件中的行号存在变化,可以在 $exception_sources 上使用 icontains。$exception_handled 也是一个实用的细分维度——应区分已处理和未处理的异常,而不是混在一起。

以下情况应跳过分组规则:

  • 重复项是历史遗留的(一次性回填,没有新的发生记录)——合并即可
  • 无法编写足够精准且安全的过滤器——改为提高合并频率,之后再重新评估
步骤 5 — 创建分组规则

将步骤 1 中“相同错误”的检查清单转换为规则过滤条件。如果规则的匹配范围比检查清单更宽松,就会悄无声息地永久合并无关的 Bug——这种规则比合并更危险,因为它会针对之后的每个事件运行。至少应按 SDK 和异常类型进行限定,并添加第三个维度(通过 $exception_sources 指定文件路径,或通过 $exception_values 指定具体的消息短语)来锁定调用位置。

先确认 $lib 的值——浏览器/JS SDK 捕获的值是 $lib="web",而不是 posthog-js,因此按 posthog-js 过滤的规则会悄无声息地永远无法匹配。在将某个值写入规则之前,使用 read-data-schema(针对 $exception 查询 $lib 的 event_property_values)进行验证:

posthog:error-tracking-grouping-rules-create
{
  "filters": {
    "type": "AND",
    "values": [
      {
        "type": "event",
        "key": "$lib",
        "operator": "exact",
        "value": "web"
      },
      {
        "type": "event",
        "key": "$exception_types",
        "operator": "exact",
        "value": "TypeError"
      },
      {
        "type": "event",
        "key": "$exception_sources",
        "operator": "icontains",
        "value": "/static/checkout/"
      },
      {
        "type": "event",
        "key": "$exception_values",
        "operator": "icontains",
        "value": "Cannot read property"
      }
    ]
  },
  "description": "Cleanup: collapse noisy checkout TypeError fingerprints (web)"
}

规则按顺序评估。先列出已有规则(posthog:error-tracking-grouping-rules-list)——如果某条规则已经部分覆盖了此模式,优先调整其过滤条件,而不是再叠加一条近似重复的规则。

可选字段 assignee 会自动将规则创建的问题分配给指定对象。除非用户明确希望在规则中固定负责人,否则应跳过此字段。

步骤 6 — 验证并整合

抽样检查已合并问题的近期事件,确认合并成功。留意规则的 custom-rule:<rule_id> 指纹是否开始匹配事件——首次匹配会创建一个新问题(或将事件路由到此前已关联该指纹的问题)。若要让事件归入历史目标问题,而不是分散到新的自定义规则问题中,请再执行一次合并,将自定义规则问题合并到目标问题中。

如果规则生效后仍持续出现新的(非规则)指纹,说明过滤条件过于严格——应放宽条件。

提示

  • 用户经常会混淆分组规则和分配规则。分组规则决定事件归入 哪个 问题。分配规则决定由 谁 负责处理产生的问题。
  • 不要仅凭“看起来相似”就合并问题,应先检查事件。发生在不同文件中的两个 TypeError 是不同的错误。
  • 堆栈帧是规范的分组信号——摄取阶段已经根据堆栈生成指纹,因此稳定的堆栈会自行完成分组。分组规则适用于自然指纹产生过多分组的情况(文件名易变、函数名称经过哈希处理、行号动态变化),此时需要覆盖默认规则。
  • 禁用或收紧分组规则不会追溯性地取消现有事件的分组;未来的事件会正确路由,过去的事件仍留在原处。如果需要精确拆分已合并问题中的指纹,请使用 error-tracking-issues-split-create。
  • 分组规则可在 UI 中通过 Project settings → Error tracking → Grouping rules 查看;用户询问规则在哪里时,请告知这一位置。

相关技能

  • suppressing-noisy-errors — 完全丢弃无价值的事件,而不是重新分组
  • triaging-error-issues — 清理分组后,重新排列问题队列的优先级
  • investigating-error-issue — 端到端检查已合并的问题

评论

支持 Markdown