Effect 里怎么关掉局部追踪或调整日志级别?

我用一个计数的 tracer 验证过:在局部把 TracerEnabled 设为 false 之后,tracer 的 span 方法一次都没有被调用,业务代码一行没改。

用 Effect.provideService 覆盖 effect 的 References 模块里对应的内置 Reference 即可:References.TracerEnabled 管 span 是否注册,References.MinimumLogLevel 管日志级别阈值。

这些内置项在 v3 里是各个 FiberRef,v4 里它们都是 Context.Reference,也就是带默认值的服务键,覆盖方式和你自定义的完全一致,如果这个概念还不熟,可以先看 Effect v4 里 FiberRef 去哪了?。下面先列清单,再看日志和追踪各一个例子。

有哪些内置的 References?

常用的几个:

  • MinimumLogLevel:日志级别阈值,低于它的日志被丢弃,默认 "Info"。
  • CurrentLogAnnotations:附加到每条日志上的注解,默认空对象。
  • CurrentLogLevel:Effect.log 不指定级别时用的级别。
  • TracerEnabled:是否注册 span,默认 true。
  • TracerSpanAnnotations、TracerSpanLinks:附加到之后创建的每个 span 上。
  • Tracer:当前使用的 tracer 服务。
  • MaxOpsBeforeYield、PreventSchedulerYield:调度器让出 CPU 的预算,属于底层调优,一般不碰。

怎么局部调整日志级别?

覆盖 MinimumLogLevel:

import { Effect, References } from "effect"

const work = Effect.gen(function*() {
  yield* Effect.logDebug("debug")
  yield* Effect.logInfo("info")
  yield* Effect.logWarning("warn")
})

const program = Effect.gen(function*() {
  console.log("默认值", yield* References.MinimumLogLevel, yield* References.TracerEnabled)

  console.log("-- MinimumLogLevel = Debug")
  yield* Effect.provideService(work, References.MinimumLogLevel, "Debug")

  console.log("-- MinimumLogLevel = Warn")
  yield* Effect.provideService(work, References.MinimumLogLevel, "Warn")
})

Effect.runPromise(program)

输出(时间戳略):

默认值 Info true
-- MinimumLogLevel = Debug
DEBUG debug
INFO info
WARN warn
-- MinimumLogLevel = Warn
WARN warn

默认阈值是 Info,所以不覆盖时 debug 那条不会出现;设成 Debug 三条都有,设成 Warn 只剩警告。覆盖只对被包住的那个 effect 生效。

怎么在局部关闭 span?

覆盖 TracerEnabled。我用一个计数的 tracer 验证:

import { Effect, References, Tracer } from "effect"

const program = Effect.gen(function*() {
  const base = yield* References.Tracer
  let created = 0
  const counting = Tracer.make({
    span(options) {
      created++
      return base.span.call(base, options)
    }
  })

  const traced = Effect.withSpan(Effect.void, "work")
  const run = (effect: Effect.Effect<void>) => Effect.provideService(effect, References.Tracer, counting)

  yield* run(traced)
  console.log("TracerEnabled=true 创建的 span 数", created)
  yield* run(Effect.provideService(traced, References.TracerEnabled, false))
  console.log("关闭后累计 span 数", created)
})

Effect.runPromise(program)

输出两行都是 1:开启时创建了一个 span,在局部把 TracerEnabled 设为 false 之后,tracer 的 span 方法根本没有被调用。典型用途是高频的内部循环或健康检查端点,不想给它们产生 span 又不想改业务代码,在入口局部关掉就行。

日志注解和 span 命名还有什么要注意的?

直接覆盖 CurrentLogAnnotations 是整体替换而不是合并,细节见 覆盖 CurrentLogAnnotations 为什么会丢注解?。给函数加 span 的写法见 Effect 里怎么给函数加 span?,可观测性整体怎么搭,见 Effect 可观测性:Effect.fn 命名、Metric 基数与错误上报的边界。

版本是 effect@4.0.5。上面两个例子,以及各内置项的默认值(MinimumLogLevel 为 Info、TracerEnabled 为 true),都在本地跑过。清单里 CurrentLogLevel、TracerSpanAnnotations、TracerSpanLinks、Tracer、MaxOpsBeforeYield、PreventSchedulerYield 的作用来自对模块导出的描述,没有逐个单独运行验证。