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

基于OpenTelemetry Collector实现类New Relic分段拆解及父Span名称传递

解决方案:将根Span名称作为属性传递给所有子Span

方法一:应用端(Java自动插桩)实现(推荐)

在应用层面处理更高效,避免Collector端的性能开销。可以通过自定义SpanProcessor实现根Span名称的传递:

  1. 实现自定义SpanProcessor,在根Span启动时将其名称存入Baggage,子Span继承并转为属性:
public class RootSpanNameBaggageProcessor implements SpanProcessor {
    @Override
    public void onStart(Context parentContext, ReadWriteSpan span) {
        // 判断是否为根Span(parent_span_id为空或全0)
        if (span.getParentSpanId().isEmpty() || span.getParentSpanId().equals("0000000000000000")) {
            // 将根Span名称存入Baggage
            Context updatedContext = parentContext.with(Baggage.currentBuilder()
                    .put("trace.root.name", span.getName())
                    .build());
            span.setParentContext(updatedContext);
        } else {
            // 子Span继承父Span的Baggage,并转为自身属性
            Baggage baggage = Baggage.fromContext(parentContext);
            baggage.getEntry("trace.root.name").ifPresent(entry -> {
                span.setAttribute("trace.root.name", entry.getValue());
            });
        }
    }

    @Override
    public boolean isStartRequired() {
        return true;
    }

    @Override
    public void onEnd(ReadableSpan span) {}

    @Override
    public boolean isEndRequired() {
        return false;
    }
}
  1. 将该处理器注册到OpenTelemetry SDK:
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
        .setTracerProvider(SdkTracerProvider.builder()
                .addSpanProcessor(new RootSpanNameBaggageProcessor())
                .build())
        .buildAndRegisterGlobal();

如果用自动插桩Agent,可通过otel.java.span-processor.implementation配置加载自定义处理器,或打包成jar放入Agent扩展目录。

方法二:Collector端通过groupbytrace + transform处理器实现

若必须在Collector端处理,正确配置groupbytrace后,transform可访问整个追踪的Span上下文:

  1. 添加处理器配置:
processors:
  groupbytrace:
    wait_duration: 1s # 根据实际追踪延迟调整,确保所有Span被收集
    num_traces: 10000 # 调整并发追踪数,避免内存溢出
  transform:
    traces:
      queries:
        # 定位根Span
        - context: trace
          statements:
            - set(trace["root_span"], filter(spans, span -> span.parent_span_id == "0000000000000000")[0])
        # 给所有子Span添加trace.root.name属性
        - context: span
          statements:
            - set(attributes["trace.root.name"], trace["root_span"].name) where parent_span_id != "0000000000000000"
  1. 在追踪管道中启用处理器:
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [groupbytrace, transform, spanmetrics]
      exporters: [otlp/tempo]

注意:groupbytrace会增加Collector内存占用,需根据流量调整参数避免OOM。

方法三:Grafana查询层关联(无需修改链路)

若不想修改数据处理链,可在Grafana中直接关联Tempo与Prometheus数据:

在面板中使用Prometheus查询Span指标,同时通过Tempo获取对应追踪的根Span名称作为聚合维度,示例表达式:

sum(otel_span_duration_sum) by (trace_id)
| with trace_data = tempo_trace_data(trace_id)
| with root_span = filter(trace_data.spans, s -> s.parent_span_id == "0000000000000000")[0]
| sum by (root_span.name) (value)

这种方法无需修改链路,但依赖Grafana的Tempo-Prometheus关联能力,查询性能可能受影响。


内容的提问来源于stack exchange,提问作者Amit Bhushan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:15:11