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

Spring Boot 3集成SQS Queue时OpenTelemetry追踪失效问题

解决SQS消费时日志无traceId的问题

问题根源分析

核心问题在于SQS消费阶段的Span未正确绑定到线程上下文,且日志的MDC(映射诊断上下文)未注入traceId,导致日志无法打印;同时你之前手动创建Span的方式不符合OpenTelemetry上下文传递规范,没有正确管理Scope。

解决方案

1. 优先启用OpenTelemetry对SQS的自动Instrumentation

这是最省心的方案,无需手动编写Span创建逻辑,只需确保引入对应依赖并开启配置:

  • Maven依赖示例:
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-aws-sqs-2.0</artifactId>
    <version>1.32.0</version> <!-- 请使用与你的OpenTelemetry版本匹配的版本 -->
</dependency>
  • 开启SQS instrumentation(部分版本默认开启):
otel.instrumentation.aws-sqs.enabled=true

启用后,OpenTelemetry会自动为SQS消费创建根Span,并自动将traceId注入MDC,日志就能直接打印traceId。

2. 修正手动创建Span的代码(自动Instrumentation失效时使用)

如果必须手动创建Span,需确保正确绑定线程Scope并注入MDC,修正后的代码如下:

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.TraceContext;
import io.opentelemetry.context.Scope;
import org.slf4j.MDC;
import software.amazon.awssdk.services.sqs.model.Message;

@SqsListener(
        value = "${amazon.sqs.queueName}",
        deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void consumeEvent(Message message) throws JsonProcessingException {
    // 构建消费端Span
    SpanBuilder spanBuilder = tracer.spanBuilder("sqs-consumer:consume-event")
            .setSpanKind(SpanKind.CONSUMER);

    // 尝试从消息属性读取生产者传递的trace上下文(若生产者有注入)
    String traceParent = message.attributes().get("traceparent");
    if (traceParent != null) {
        SpanContext parentContext = TraceContext.fromTraceparent(traceParent);
        spanBuilder.setParent(tracer.getCurrentContext().with(Span.wrap(parentContext)));
    }

    Span span = spanBuilder.startSpan();
    // 用try-with-resources自动管理Scope,确保上下文绑定当前线程
    try (Scope scope = tracer.withSpan(span)) {
        // 将traceId、spanId放入MDC,让日志框架读取打印
        MDC.put("traceId", span.getSpanContext().getTraceId());
        MDC.put("spanId", span.getSpanContext().getSpanId());

        // --- 消息处理逻辑 ---
        // your message processing code here
        // --- 消息处理逻辑结束 ---

    } catch (Exception ex) {
        // 记录异常并标记Span为错误状态
        span.recordException(ex);
        span.setStatus(StatusCode.ERROR, ex.getMessage());
        throw ex;
    } finally {
        // 清理MDC,避免线程复用导致上下文污染
        MDC.remove("traceId");
        MDC.remove("spanId");
        // 结束Span
        span.end();
    }
}

3. 确认日志格式配置

确保日志框架(如Logback/Log4j2)配置中包含traceId和spanId的输出:

  • Logback示例(logback.xml):
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg traceId=%X{traceId} spanId=%X{spanId}%n</pattern>
    </encoder>
</appender>

4. 检查Micrometer与OpenTelemetry的整合配置

如果用Micrometer Tracing做桥接,确保配置正确传递trace上下文:

spring.micrometer.tracing.enabled=true
spring.micrometer.tracing.propagation.type=TRACE_ID,SPAN_ID
spring.micrometer.tracing.otel.enabled=true

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:01:16