将原生应用日志与 Trace 关联

当 OpenTelemetry Java 智能体为你的原生应用进行插桩时,它可以自动将当前活动的 trace 上下文 — trace_idspan_idtrace_flags — 添加到原生应用的日志上下文(MDC)中。通过在日志输出中打印这些值,你可以直接从某一条日志定位到对应的 trace,也可以从某个 trace 回溯到请求所生成的日志。

本页说明如何在 Java 原生应用的日志中暴露 trace 上下文。

WARNING

先决条件: 本指南假定你的原生应用已经由 OpenTelemetry Java 智能体 2.x 进行插桩,并且是通过 Instrumentation 自定义资源和 instrumentation.opentelemetry.io/inject-java 注解注入的。下面描述的 MDC 键由智能体在运行时填充——如果未注入智能体,无论你如何配置日志模式,这些键都将为空。请先参阅 Java 自动插桩 以启用注入。

工作原理

Java 智能体提供了日志插桩,会将当前 span 上下文复制到日志库的 MDC(Mapped Diagnostic Context)中。你不需要解析 HTTP 头,也不需要编写任何代码来完成这件事——智能体会从传播头中提取上下文,并自动填充 MDC。注入的键如下:

描述
trace_id活动 span 的 32 字符 trace ID。
span_id活动 span 的 16 字符 span ID。
trace_flags以十六进制表示的 W3C trace flags(例如,当 span 被采样时为 01)。

这些键使用 snake_case,是智能体内置的默认值。注入默认启用,因此你只需要在日志输出模式中引用这些键即可。

插桩会与对应的日志库匹配:

日志库插桩模块最低版本
Logbacklogback-mdc-1.01.0+
Log4j 2log4j-context-data-2.172.7+
Log4j 1log4j-mdc-1.21.2+

如果你需要关闭(或重新启用)某个特定的注入,请在工作负载上设置相应的属性或环境变量。以下项的默认值均为 true

系统属性环境变量
otel.instrumentation.logback-mdc.enabledOTEL_INSTRUMENTATION_LOGBACK_MDC_ENABLED
otel.instrumentation.log4j-context-data.enabledOTEL_INSTRUMENTATION_LOG4J_CONTEXT_DATA_ENABLED
otel.instrumentation.log4j-mdc.enabledOTEL_INSTRUMENTATION_LOG4J_MDC_ENABLED

在日志输出中暴露这些 ID

请选择与你的原生应用配置方式相匹配的选项。三者都引用相同的 snake_case MDC 键,因此一次经过采样的请求会生成如下所示的日志行:

2026-06-12 10:15:42.123 trace_id=4bf92f3577b34da6a3ce929d0e0e4736 span_id=00f067aa0ba902b7 trace_flags=01 INFO  ProviderController - request /hello

Spring Boot

对于 Spring Boot 原生应用,最简单的方法是覆盖 logging.pattern.level,这样就能在每一行日志前添加这些 ID,而无需重写整个模式:

logging.pattern.level = trace_id=%mdc{trace_id} span_id=%mdc{span_id} trace_flags=%mdc{trace_flags} %5p
NOTE

这正是上游 OpenTelemetry 插桩 README 中记录的形式(参见 参考资料)。覆盖 logging.pattern.level 是 Spring Boot 的一种约定;snake_case 键则由智能体提供。

Logback

如果你管理自己的 logback.xmllogback-spring.xml,请在模式中使用 %X{...} 引用这些键(在 Logback 中它等同于 %mdc{...}):

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} %-5level %logger{36} - %msg%n</pattern>
  </encoder>
</appender>

对于依赖 Spring Boot 默认控制台 appender 的原生应用,你也可以改写 CONSOLE_LOG_PATTERN 属性,在模式中嵌入相同的 %X{trace_id} 标记。

Log4j 2

对于 Log4j 2,请在 PatternLayout 中使用 %X{...} 引用这些键:

<Console name="Console" target="SYSTEM_OUT">
  <PatternLayout
    pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} %-5p %c{1} - %m%n"/>
</Console>

OpenTelemetry 智能体键 vs. Spring Boot / Micrometer 原生关联

WARNING

snake_case 键(trace_idspan_idtrace_flags)适用于 OpenTelemetry Java 智能体 作为 trace 上下文来源的场景——这也是本文档默认假设的情况。

使用 Micrometer Tracing 的 Spring Boot 3 有自己独立的日志关联功能,它通过 logging.pattern.correlation 使用 camelCase 键(traceIdspanId)。这与智能体采用的是不同机制。

请使用与 trace 来源相匹配的键。如果智能体(而不是 Micrometer)提供上下文,而你引用了 %X{traceId},该字段就会输出为空;同样地,当只有 Micrometer 处于活动状态时,%X{trace_id} 也会为空。不要混用这两种约定。

通过 OTLP 导出日志

上面的模式适用于作为文本读取或抓取的 文本日志(控制台或文件)。如果你改为直接通过 OTLP 导出日志,则 trace_idspan_id 会作为 OTLP 日志记录的专用字段传递,而不是作为 MDC 属性,因此 OTLP 导出的日志无需将这些 ID 添加到日志模式中也能保持关联。

其他语言

其他 OpenTelemetry 语言在零代码(自动插桩)场景下也会将日志与 trace 关联,但注入的字段名称以及启用方式因语言而异。请参阅你所使用语言的上游指南:

语言参考资料关联方式
PythonLogs auto-instrumentation exampleopentelemetry-instrument 会向日志记录添加 otelTraceID / otelSpanID;将 OTEL_PYTHON_LOG_CORRELATION=true 设为启用后,它们会被注入到文本日志输出中。
Node.jsinstrumentation-pino, instrumentation-winston, instrumentation-bunyan@opentelemetry/auto-instrumentations-node 一起提供;每个组件默认都会将 trace_id / span_id / trace_flags 注入到日志记录中。
.NETLog to trace correlation.NET Automatic Instrumentation 会自动为 ILogger 记录填充 TraceId / SpanId / TraceState,无需任何配置。
NOTE

这里特意没有列出 Go:它没有运行时智能体,并且基于 eBPF 的自动插桩不会将 trace 上下文注入到原生应用日志中。Go 中的日志与 trace 关联需要在代码中手动完成——例如,从 context.Context 中读取 span 上下文,或者通过 otelslog 桥接——因此这里没有可链接的零代码参考资料。

参考资料