将原生应用日志与 Traces 关联
当 OpenTelemetry Java 智能体为你的原生应用进行插桩时,它可以自动将活动的 trace 上下文 — trace_id、span_id 和 trace_flags — 添加到原生应用的日志上下文(MDC)中。通过在日志输出中打印这些值,你可以直接从一条日志行跳转到对应的 trace,也可以从某个 trace 反向找到该请求生成的日志。
本页说明如何在 Java 原生应用的日志中显示 trace 上下文。
前提条件: 本指南假定你的原生应用已经通过 Instrumentation 自定义资源和 instrumentation.opentelemetry.io/inject-java 注解,由 OpenTelemetry Java 智能体 2.x 完成插桩并注入。下面描述的 MDC 键会在运行时由智能体填充——如果没有注入智能体,无论你如何配置日志格式,这些键都将为空。请先参阅 Java 自动插桩 以启用注入。
目录
工作原理在日志输出中显示这些 IDSpring BootLogbackLog4j 2OpenTelemetry 智能体键 vs. Spring Boot / Micrometer 原生关联通过 OTLP 导出日志其他语言参考资料工作原理
Java 智能体提供了日志插桩,它会将当前 span 上下文复制到日志库的 MDC(Mapped Diagnostic Context)中。你无需解析 HTTP 头,也无需编写任何代码来完成这件事——智能体会从传播头中提取上下文,并自动填充 MDC。注入的键如下:
这些键使用 snake_case,并且是智能体的内置默认值。注入默认启用,因此你只需要在日志输出格式中引用这些键即可。
该插桩会与您的日志库相匹配:
如果你需要关闭某个特定注入(或重新开启),请在 workload 上设置相应的属性或环境变量。每项默认值都是 true:
在日志输出中显示这些 ID
请选择与你的原生应用配置方式相匹配的选项。这三种方式都引用相同的 snake_case MDC 键,因此被采样的请求会生成类似如下的日志行:
Spring Boot
对于 Spring Boot 原生应用,最简单的方法是覆盖 logging.pattern.level,这样这些 ID 就会以前缀形式出现在每条日志行之前,而无需重写整个格式:
这正是上游 OpenTelemetry 插桩 README 中记录的精确形式(参见 参考资料)。覆盖 logging.pattern.level 是 Spring Boot 的约定;而 snake_case 键则是智能体提供的内容。
Logback
如果你管理自己的 logback.xml 或 logback-spring.xml,请在格式中使用 %X{...} 引用这些键(在 Logback 中它等同于 %mdc{...}):
对于依赖 Spring Boot 默认 console appender 的原生应用,也可以改为覆盖 CONSOLE_LOG_PATTERN 属性,在格式中嵌入相同的 %X{trace_id} token。
Log4j 2
对于 Log4j 2,请在 PatternLayout 中使用 %X{...} 引用这些键:
OpenTelemetry 智能体键 vs. Spring Boot / Micrometer 原生关联
snake_case 键(trace_id、span_id、trace_flags)适用于 OpenTelemetry Java 智能体 是 trace 上下文来源的场景——这也是本文档始终采用的假设。
搭配 Micrometer Tracing 的 Spring Boot 3 有自己独立的日志关联功能,它通过 logging.pattern.correlation 使用 camelCase 键(traceId、spanId)。这与智能体使用的是不同机制。
请使用与您的 trace 来源相匹配的键。如果在由智能体(而不是 Micrometer)提供上下文时引用 %X{traceId},该字段会打印为空;同样地,当仅 Micrometer 处于活动状态时,%X{trace_id} 也会为空。不要混用这两种约定。
通过 OTLP 导出日志
上面的格式适用于文本日志(控制台或文件),这些日志会以文本形式读取或抓取。如果你改为直接通过 OTLP 导出日志,那么 trace_id 和 span_id 会通过 OTLP log record 的专用字段传递,而不是作为 MDC 属性,因此 OTLP 导出的日志无需将这些 ID 添加到日志格式中,也能保持关联。
其他语言
其他 OpenTelemetry 语言在零代码(自动插桩)场景下也可以将日志与 trace 关联,但注入的字段名称以及启用方式因语言而异。请参考你所使用语言对应的上游指南:
这里刻意省略了 Go:它没有运行时智能体,而且其基于 eBPF 的自动插桩不会将 trace 上下文注入到原生应用日志中。Go 中的 log-trace 关联需要在代码中手动完成——例如,从 context.Context 读取 span 上下文,或通过 otelslog bridge——因此这里没有可链接的零代码参考。
参考资料
- Logger MDC 自动插桩 — 已注入键和受支持日志库的权威列表。
- Logback MDC 插桩 README — 格式示例和配置选项。
- Java 智能体配置 和 禁用特定插桩 — 如何切换各个插桩。