OpenTelemetry JavaScript SDK 不支持在运行时直接修改 TraceIdRatioBasedSampler 的采样比,但可通过自定义可变采样器(Mutable Sampler)实现动态调节,本文详解其实现原理与完整代码示例。
opentelemetry javascript sdk 不支持在运行时直接修改 `traceidratiobasedsampler` 的采样比,但可通过自定义可变采样器(mutable sampler)实现动态调节,本文详解其实现原理与完整代码示例。
在 OpenTelemetry JS 中,采样策略由 Sampler 接口定义,而官方提供的 TraceIdRatioBasedSampler 是不可变(immutable)的:其采样率(如 0.1 表示 10% 采样)在实例化时即固定,后续无法更改。TracerProvider(无论是 NodeTracerProvider 还是 BasicTracerProvider)也不提供 setSampler() 或类似方法——一旦初始化完成,其内部采样器即被锁定。
因此,若需在服务运行中动态调整采样率(例如根据 QPS、错误率或运维指令降级/提级采样),必须自行实现一个线程安全、可更新的采样器,并确保其符合 Sampler 接口规范:
import { Sampler, SamplingResult, SamplingDecision, TraceId, SpanKind,} from '@opentelemetry/sdk-trace-base';export class MutableTraceIdRatioBasedSampler implements Sampler { private _ratio: number = 1.0; constructor(initialRatio: number = 1.0) { this.updateRatio(initialRatio); } // ✅ 允许运行时更新采样率(注意:需保证并发安全) updateRatio(ratio: number): void { if (ratio < 0 || ratio > 1) { throw new Error('Sampling ratio must be between 0 and 1'); } this._ratio = ratio; } // ✅ 实现 Sampler 接口核心方法 shouldSample( context: unknown, traceId: TraceId, spanName: string, spanKind: SpanKind, attributes: Record<string, unknown>, links: unknown[] ): SamplingResult { // 使用 traceId 的低 64 位做 deterministic hash(与原生实现一致) const hash = this.hashTraceId(traceId); const decision = hash / Number.MAX_SAFE_INTEGER < this._ratio ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD; return { decision, attributes: {}, }; } // ⚠️ 注意:此 hash 实现需与 OpenTelemetry JS SDK 内部保持一致(简化版) private hashTraceId(traceId: TraceId): number { // 取 traceId 前 8 字节(16 hex chars),转为 BigInt 后取模 const hex = traceId.slice(0, 16); const num = BigInt('0x' + hex) % BigInt(Number.MAX_SAFE_INTEGER); return Number(num); } toString(): string { return `MutableTraceIdRatioBasedSampler{ratio=${this._ratio}}`; }}
使用方式如下——在初始化 TracerProvider 时传入该可变采样器,并在需要时调用 updateRatio():
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';import { SimpleSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';import { MeterProvider } from '@opentelemetry/sdk-metrics';// 1. 创建可变采样器(初始采样率 0.01 → 1%)const sampler = new MutableTraceIdRatioBasedSampler(0.01);// 2. 构建 TracerProvider 并注入采样器const provider = new NodeTracerProvider({ sampler });provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));// 3. 启用全局追踪器provider.register();// ✅ 运行时动态调整:例如收到配置中心推送后setTimeout(() => { console.log('Upgrading sampling to 10%...'); sampler.updateRatio(0.1); // 立即生效}, 5000);
⚠️ 关键注意事项:
总结:虽然 OpenTelemetry JS 当前不内置运行时采样率调节能力,但通过轻量级自定义 Sampler,即可安全、高效、兼容地实现动态采样控制,满足灰度发布、故障熔断、成本优化等典型生产需求。