Spring Boot中@SqsListener注解方法日志缺失TraceId问题咨询
问题根因
@SqsListener的消息处理线程由AWS SQS SDK独立维护,默认没有接入Spring Cloud Sleuth的链路上下文传播机制。Sleuth的TraceId、SpanId默认存储在线程本地变量(ThreadLocal)中,跨线程传递链路信息时没有对应钩子做传递,就会出现监听方法内链路ID丢失的问题。
解决方案
方案1:启用Sleuth对AWS SQS的原生支持(适用Sleuth 3.x+版本)
- 确认Spring Cloud Sleuth版本在3.0及以上,该版本已经内置了对spring-cloud-aws的SQS集成支持
- 引入Sleuth的AWS集成依赖即可,Maven配置示例:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-integration-aws</artifactId> </dependency>
- 无需额外代码配置,依赖引入后Sleuth会自动给@SqsListener方法添加链路传播切面,自动从SQS消息属性中读取链路信息,没有的话会自动生成新的链路ID,打印日志时会自动携带。
方案2:手动传递链路上下文(低版本Sleuth适配方案)
如果使用的是Sleuth 2.x等低版本,没有内置SQS集成,可通过自定义切面拦截所有@SqsListener修饰的方法,在方法执行前初始化链路上下文:
@Aspect @Component public class SqsListenerTraceAspect { private final Tracer tracer; public SqsListenerTraceAspect(Tracer tracer) { this.tracer = tracer; } @Around("@annotation(org.springframework.cloud.aws.messaging.listener.annotation.SqsListener)") public Object wrapSqsListenerTrace(ProceedingJoinPoint pjp) throws Throwable { // 尝试从消息属性中获取已有的TraceId,没有的话新建链路 Span span = tracer.nextSpan().name("sqs-receive").start(); try (Tracer.SpanInScope ignored = tracer.withSpan(span)) { return pjp.proceed(); } finally { span.end(); } } }
- 如果需要上下游链路打通,只需要在发送SQS消息时,将当前TraceId、SpanId放到消息属性中,拦截器中读取对应属性构建Span即可。
方案3:配置SQS线程池接入Sleuth装饰器
如果自定义了SQS的监听线程池,需要给线程池添加Sleuth的线程装饰器,确保所有线程池调度的任务都自动传递链路上下文:
@Bean public AsyncTaskExecutor sqsListenerExecutor(TraceRunnableDecorator traceDecorator) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(20); executor.setQueueCapacity(100); executor.setThreadNamePrefix("sqs-listener-"); // 关键:添加Sleuth的链路装饰器 executor.setTaskDecorator(traceDecorator); executor.initialize(); return executor; }
验证方式
在@SqsListener方法内打印日志,确认日志中已经出现traceId、spanId字段即可。
内容的提问来源于stack exchange,提问作者Yaseen
相关产品推荐
相关产品推荐

