如何在Quarkus中结合请求上下文及DataDog Trace ID记录日志
在Quarkus服务中为日志添加DataDog Trace ID(来自请求头)
推荐方案:使用MDC+JAX-RS拦截器(通用无侵入)
这种方式能自动为每个请求注入Trace ID,业务代码无需修改即可在日志中带上追踪ID。
1. 编写请求拦截器,从请求头获取Trace ID并放入MDC
MDC(Mapped Diagnostic Context)是SLF4J提供的线程绑定上下文,用于存储请求级别的日志变量。
import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.container.ContainerResponseContext; import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.ext.Provider; import org.slf4j.MDC; @Provider public class TraceIdFilter implements ContainerRequestFilter, ContainerResponseFilter { // DataDog默认的Trace ID请求头 private static final String DATADOG_TRACE_ID_HEADER = "x-datadog-trace-id"; // MDC中存储Trace ID的键名 private static final String MDC_TRACE_KEY = "traceId"; @Override public void filter(ContainerRequestContext requestContext) { // 从请求头提取Trace ID String traceId = requestContext.getHeaderString(DATADOG_TRACE_ID_HEADER); if (traceId != null && !traceId.isBlank()) { MDC.put(MDC_TRACE_KEY, traceId); } } @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { // 请求结束后清理MDC,避免线程复用导致的ID串问题 MDC.remove(MDC_TRACE_KEY); } }
2. 配置日志格式,输出MDC中的Trace ID
在application.properties中修改日志格式,加入%X{traceId}占位符(对应MDC中的键名):
# Logback/Log4j2通用配置 quarkus.log.console.format=%d{HH:mm:ss} %-5level [%thread] %logger{36} [%X{traceId}] - %msg%n # 若需要输出到文件,同样修改文件日志格式 quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} [%X{traceId}] - %msg%n
3. 业务代码无需修改,正常打日志即可
原有的Logger使用方式完全不变,日志会自动带上当前请求的Trace ID:
@ApplicationScoped public class FooServiceImpl implements FooService { private static final Logger LOG = LoggerFactory.getLogger(FooServiceImpl.class); public void doBusinessLogic() { // 日志会自动包含traceId,示例输出:14:35:22 ERROR [executor-thread-0] c.e.s.FooServiceImpl [123456789] - 发生错误时 LOG.error("发生错误时"); } }
备选方案:手动注入HttpHeaders(适合简单场景)
如果不想用拦截器,也可以在业务Bean中直接注入HttpHeaders,手动提取Trace ID并放入MDC:
import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.HttpHeaders; import org.slf4j.MDC; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ApplicationScoped public class FooServiceImpl implements FooService { private static final Logger LOG = LoggerFactory.getLogger(FooServiceImpl.class); @Context HttpHeaders httpHeaders; public void doSomething() { String traceId = httpHeaders.getHeaderString("x-datadog-trace-id"); MDC.put("traceId", traceId); try { LOG.error("发生错误时"); } finally { // 必须手动清理,避免污染后续请求 MDC.remove("traceId"); } } }
注意事项
- 确认请求头名称:若你的DataDog Trace ID使用自定义请求头,需同步修改代码中的
DATADOG_TRACE_ID_HEADER值 - 异步场景:Quarkus默认会自动传递MDC上下文到异步线程,无需额外配置
- 空值处理:若请求头中无Trace ID,日志中
[%X{traceId}]会显示为[],可根据需求添加默认值(比如MDC.put(MDC_TRACE_KEY, traceId != null ? traceId : "unknown"))
内容的提问来源于stack exchange,提问作者GeauxEric
相关产品推荐
相关产品推荐

