将原生应用日志与 Traces 关联

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

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

WARNING

前提条件: 本指南假定你的原生应用已经通过 Instrumentation 自定义资源和 instrumentation.opentelemetry.io/inject-java 注解,由 OpenTelemetry Java 智能体 2.x 完成插桩并注入。下面描述的 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 标志(例如,当 span 被采样时为 01)。

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

该插桩会与您的日志库相匹配:

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

如果你需要关闭某个特定注入(或重新开启),请在 workload 上设置相应的属性或环境变量。每项默认值都是 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 默认 console appender 的原生应用,也可以改为覆盖 CONSOLE_LOG_PATTERN 属性,在格式中嵌入相同的 %X{trace_id} token。

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 log record 的专用字段传递,而不是作为 MDC 属性,因此 OTLP 导出的日志无需将这些 ID 添加到日志格式中,也能保持关联。

其他语言

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

语言参考关联方式
Python日志自动插桩示例opentelemetry-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
.NET日志到 trace 的关联.NET Automatic Instrumentation 会自动在 ILogger 记录上填充 TraceId / SpanId / TraceState,无需任何配置。
NOTE

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

参考资料