defectsOnly 会把预期内的失败过滤掉吗?

你写了 defectsOnly: true,以为从此只有 bug 会上报,结果监控里出现了一条本该被忽略的 404。

不会逐条过滤:defectsOnly 判断的是「这条 cause 里有没有 defect」,只要有,整条 cause 的所有原因都会上报,包括预期内的失败。 想精确地让某类错误永远不报,要用 ErrorReporter.ignore 标注。

Effect.withErrorReporting 会在 effect 失败时,把 cause 交给当前的上报器(整体介绍见 Effect 里怎么统一上报错误?,它在 4.0.5 里是 unstable)。defect 指 Effect.die 这类非预期错误,与预期失败的区别见 Effect 里的 failure 和 defect 怎么区分?。下面用三种 cause 验证。

三种 cause 下 defectsOnly 各上报什么?

import { Cause, Data, Effect, ErrorReporter } from "effect"

class Typed extends Data.TaggedError("Typed")<{ readonly code: number }> {
  get message() {
    return `code ${this.code}`
  }
}

const collect = async (options: { readonly defectsOnly: boolean }, effect: Effect.Effect<never, unknown>) => {
  const seen: Array<string> = []
  const reporter = ErrorReporter.make(({ error }) => { seen.push(error.message) })
  await Effect.runPromiseExit(
    effect.pipe(Effect.withErrorReporting(options), Effect.provide(ErrorReporter.layer([reporter])))
  )
  return seen
}

const failOnly = Effect.fail(new Typed({ code: 1 }))
const dieOnly = Effect.die(new Error("bug"))
const mixed = Effect.failCause(Cause.combine(Cause.fail(new Typed({ code: 1 })), Cause.die(new Error("bug"))))

console.log("fail", await collect({ defectsOnly: true }, failOnly))
console.log("die", await collect({ defectsOnly: true }, dieOnly))
console.log("mixed", await collect({ defectsOnly: true }, mixed))

输出:纯失败上报 [],纯 defect 上报 ['bug'],混合 cause 上报 ['code 1', 'bug']。

混合 cause 为什么是要点?

最后一行说明:只要 cause 里含有任何一个 defect,整条 cause 的所有原因都会上报,包括里面那个本来「预期内」的 Typed 失败。判断条件是「这条 cause 有没有 defect」,不是「逐个原因是不是 defect」。

并发场景里一条 cause 常常混着多个原因,所以别把它理解成精确过滤。

想让某类错误永远不报,该用什么?

用 ErrorReporter.ignore 标注,它是逐个错误对象生效的:

import { Data, ErrorReporter } from "effect"

export class NotFound extends Data.TaggedError("NotFound")<{ readonly id: string }> {
  readonly [ErrorReporter.ignore] = true
}

标了 ignore 的错误,在上报器里完全不会出现。其余两个标注 severity 与 attributes 的写法,见主文的最小示例。结论是:defectsOnly 适合「整条 cause 里没有 bug 就别打扰我」,不适合代替 ignore。

版本是 effect 4.0.5。三种 cause 下 defectsOnly 的输出在这个版本上跑过。ignore 标注让错误不出现,是在主文的最小示例里跑过的;这里单独列出的 NotFound 片段是该示例的子集,没有再单独运行。