如何在SpringBoot+GraphQL中获取OTEL的TraceId与SpanID
解决SpringBoot+GraphQL+OTEL获取TraceId/SpanId全0的问题
问题根源
你拿到全0的TraceId/SpanId,是因为当前代码执行时没有绑定OTEL创建的有效Span上下文——要么是OTEL的GraphQL链路追踪未正确初始化,要么是上下文没有传递到你的Resolver代码中。
正确配置与实现步骤
1. 确保依赖与自动配置生效
首先要引入正确的OTEL依赖,让它自动接管GraphQL的链路追踪:
- 核心依赖(Maven):
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-spring-boot-starter</artifactId> <version>1.28.0</version> <!-- 保持所有OTEL依赖版本一致 --> </dependency> <dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-spring-graphql-1.10</artifactId> <version>1.28.0</version> <!-- 与starter版本严格匹配 --> </dependency> - 配置文件(application.yml)中指定服务名(必须,否则OTEL可能不生成有效Span):
otel: service: name: your-graphql-service-name traces: exporter: logging # 本地测试用logging,生产可改为otlp/zipkin
2. 正确获取TraceId/SpanId的代码方式
不要直接用Span.current()(上下文未绑定时会返回无效的默认Span),应该通过OTEL的Tracer实例来获取当前Span:
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class YourQueryResolver { private final Tracer tracer; @Autowired public YourQueryResolver(Tracer tracer) { this.tracer = tracer; } public String yourQueryMethod() { Span currentSpan = tracer.currentSpan(); // 先判断Span是否有效 if (currentSpan.getSpanContext().isValid()) { String traceId = currentSpan.getSpanContext().getTraceId(); String spanId = currentSpan.getSpanContext().getSpanId(); // 可直接使用或写入日志 System.out.printf("TraceId: %s, SpanId: %s%n", traceId, spanId); } // 业务逻辑 return "query-result"; } }
3. 自动将TraceId/SpanId注入日志(推荐)
手动打印太繁琐,通过OTEL的MDC扩展可以自动将TraceId/SpanId注入日志上下文,无需修改业务代码:
- 引入日志适配依赖(以Logback为例):
<dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-logback-mdc-1.0</artifactId> <version>1.28.0</version> </dependency> - 修改Logback配置(logback-spring.xml),在日志格式中添加TraceId和SpanId字段:
配置完成后,所有日志都会自动带上有效TraceId和SpanId。<configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId:%X{trace_id}, spanId:%X{span_id} - %msg%n</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="CONSOLE"/> </root> </configuration>
4. 常见排查点
- 检查OTEL版本是否统一:所有OTEL相关依赖的版本必须一致,否则会出现上下文绑定失败的问题。
- 确认自定义GraphQL Instrumentation的执行顺序:如果有自定义Instrumentation,需通过
@Order(Ordered.HIGHEST_PRECEDENCE)保证OTEL的Instrumentation先执行,确保Span先被创建。 - 检查OTEL SDK是否被禁用:若配置了
otel.sdk.disabled=true,OTEL不会生成任何Span,需确保该配置为false(默认值)。 - 确保请求通过GraphQL入口触发:直接调用Resolver方法不会触发OTEL的Instrumentation,必须通过GraphQL的HTTP接口发送请求才能生成有效Span。
内容的提问来源于stack exchange,提问作者Aayush
相关产品推荐
相关产品推荐

