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

Quarkus+RabbitMQ环境下OpenTelemetry Span添加异常失败问题

问题解答

你的假设是否正确?

你的核心判断方向是对的,但细节上需要修正:addEvent和recordException本身是同步操作,问题出在你的错误处理逻辑执行时机晚于Span的结束时间。

Quarkus结合OpenTelemetry时,会自动为消息消费、请求处理等场景创建并管理Span生命周期(比如@Incoming方法执行完毕后自动结束Span)。如果你的错误处理逻辑是在方法执行完成后才触发(比如异步回调、延迟处理),此时原Span已经被自动结束,后续的Span操作自然不会生效。

正确将异常事件添加到现有Span的方法

1. 同步在Span活跃期内处理异常

确保异常捕获和Span操作在当前活跃Span的生命周期内完成,比如直接在消息消费方法内同步处理:

@Incoming("rabbitmq-input")
public void processMessage(String payload) {
    Span currentSpan = Span.current();
    try {
        // 执行消息处理业务逻辑
        doBusinessLogic(payload);
    } catch (Exception e) {
        // 同步修改当前活跃的Span
        currentSpan.setStatus(StatusCode.ERROR, "消息处理失败");
        currentSpan.addEvent("异常触发", Attributes.of(
            AttributeKey.stringKey("exception.type"), e.getClass().getName(),
            AttributeKey.stringKey("exception.message"), e.getMessage()
        ));
        currentSpan.recordException(e);
        // 按需抛出异常或处理错误
        throw new RuntimeException("消息处理失败", e);
    }
}

2. 异步处理时手动传递Span上下文

如果错误处理必须异步执行(比如异步重试、异步通知),需要先提取当前Span的上下文,在异步任务中激活关联的Span(可以创建子Span关联原Span):

@Incoming("rabbitmq-input")
public CompletionStage<Void> processMessage(String payload) {
    // 提取当前Span的上下文
    SpanContext parentSpanContext = Span.current().getSpanContext();
    Tracer tracer = GlobalOpenTelemetry.getTracer("your-app-tracer");

    return CompletableFuture.runAsync(() -> {
        // 创建子Span并关联原Span上下文,确保错误事件被关联到原链路
        try (Scope scope = tracer.spanBuilder("async-error-handling")
                .setParent(Context.current().with(Span.wrap(parentSpanContext)))
                .startSpan()
                .makeCurrent()) {
            Span errorSpan = Span.current();
            try {
                // 执行异步错误处理逻辑
                asyncErrorHandler(payload);
            } catch (Exception e) {
                errorSpan.setStatus(StatusCode.ERROR);
                errorSpan.recordException(e);
            }
        }
    });
}

注意:如果原Span已经结束,无法直接修改它,此时通过创建子Span的方式,能保证错误事件被关联到原链路追踪中。

3. 检查Quarkus的Span自动管理规则

Quarkus默认会自动为Reactive Messaging、REST端点等创建Span,并在方法执行完成后自动结束Span。如果你的业务逻辑涉及异步流转,需要确保Span的生命周期被正确延长:

  • 对于返回CompletionStage的方法,Quarkus会等待异步任务完成后再结束Span,所以尽量使用异步返回类型来让框架自动管理Span生命周期。
  • 避免在方法内手动提前结束Span(除非你明确知道自己在做什么)。

4. 验证Span的生命周期

可以通过日志打印Span的状态,确认操作时Span是否处于活跃状态:

Span currentSpan = Span.current();
System.out.println("Span是否活跃:" + currentSpan.isRecording());

如果输出false,说明Span已经结束,此时任何修改操作都会无效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:32:16