You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring 3中如何用Micrometer+OpenTelemetry在发送至Collector前过滤/丢弃Span?

在Spring 3结合Micrometer Tracing与OpenTelemetry时过滤Span的最优实现

问题描述

在Spring 3中使用Micrometer Tracing结合OpenTelemetry时,需要在Span发送至Collector前丢弃不需要的Span。尝试通过自定义OpenTelemetry Sampler实现过滤,但遇到以下问题:

  • 当management.tracing.sampling.probability=1.0时符合预期
  • 当设置为0.0时,父Span被丢弃,但子Span依然被发送,期望概率为0时不发送任何Span

原实现代码如下:

@Override
public SamplingResult shouldSample(Context context, String traceId, String name, SpanKind spanKind, Attributes attributes, List<LinkData> list) {
    if (name.equalsIgnoreCase("xyz")) {
        return SamplingResult.drop();
    } else {
        // 根据采样概率设置record或recordAndSample
        return SamplingResult.recordAndSample();
    }
}

@Override
public String getDescription() {
    return CustomSampler.class.getSimpleName();
}
@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class })
@EnableConfigurationProperties(TracingProperties.class)
public class SamplerConfig {
    @Bean
    @Primary
    public Sampler customSampler() {
        Float samplerProbability = this.tracingProperties.getSampling().getProbability();
        return Sampler.parentBasedBuilder(Sampler.traceIdRatioBased(samplerProbability))
                .setRemoteParentNotSampled(new CustomSampler())
                .setLocalParentNotSampled(new CustomSampler())
                .setLocalParentSampled(new CustomSampler())
                .setRemoteParentSampled(new CustomSampler())
                .build();
    }
}

问题分析

原实现的核心问题在于:

  • 自定义CustomSampler在非目标Span名称的场景下直接返回SamplingResult.recordAndSample(),完全忽略了父Span的采样状态
  • ParentBasedBuilder的所有父Span分支都被替换为CustomSampler,导致当概率为0.0时,根Span被traceIdRatioBased(0.0)拒绝,但子Span的父Span未采样状态被CustomSampler覆盖,强制发送子Span

最优实现方案

方案1:正确的自定义Sampler(推荐,开销更低)

通过包装概率采样器实现先过滤Span名称,再继承父Span采样决策的逻辑,确保子Span会遵循父Span的采样状态:

自定义Sampler实现

public class CustomSampler implements Sampler {
    private final Sampler delegate;

    public CustomSampler(Sampler delegate) {
        this.delegate = delegate;
    }

    @Override
    public SamplingResult shouldSample(Context context, String traceId, String name, SpanKind spanKind, Attributes attributes, List<LinkData> links) {
        // 优先过滤指定名称的Span,直接丢弃
        if (name.equalsIgnoreCase("xyz")) {
            return SamplingResult.drop();
        }
        // 其余情况交给委托的概率采样器处理,自动继承父Span的采样决策
        return delegate.shouldSample(context, traceId, name, spanKind, attributes, links);
    }

    @Override
    public String getDescription() {
        return "CustomSampler{" + delegate.getDescription() + "}";
    }
}

配置类优化

@AutoConfigureBefore(OpenTelemetryAutoConfiguration.class)
@ConditionalOnClass({OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class})
@EnableConfigurationProperties(TracingProperties.class)
public class SamplerConfig {

    private final TracingProperties tracingProperties;

    public SamplerConfig(TracingProperties tracingProperties) {
        this.tracingProperties = tracingProperties;
    }

    @Bean
    @Primary
    public Sampler customSampler() {
        Float samplerProbability = tracingProperties.getSampling().getProbability();
        // 创建概率采样器
        Sampler probabilitySampler = Sampler.traceIdRatioBased(samplerProbability);
        // 用自定义Sampler包装,实现名称过滤+概率采样的组合逻辑
        Sampler filteredSampler = new CustomSampler(probabilitySampler);
        // 使用ParentBasedBuilder的默认配置,自动处理父Span的采样继承
        return Sampler.parentBasedBuilder(filteredSampler).build();
    }
}

方案2:使用SpanProcessor(更灵活)

如果需要基于Span的更多属性(如持续时间、标签)过滤,可以使用SpanProcessor在Span结束时决定是否丢弃,适合复杂过滤场景:

@Bean
public SpanProcessor filteringSpanProcessor() {
    return SpanProcessor.filtering(span -> {
        // 过滤条件:不是指定名称的Span,且Span已被采样
        return !span.getName().equalsIgnoreCase("xyz") && span.getSpanContext().isSampled();
    });
}

两种方案对比

  • Sampler方案:在Span创建阶段就决定是否采样,能减少不必要的Span创建开销,同时影响上下文传播的采样标记,适合入口级过滤
  • SpanProcessor方案:在Span结束阶段过滤,可基于更多运行时属性判断,灵活性更高,但已创建Span会产生少量额外开销

内容的提问来源于stack exchange,提问作者Anuj Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:23:16