将原生应用日志与 Trace 关联
当 OpenTelemetry Java 智能体为你的原生应用进行插桩时,它可以自动将当前活动的 trace 上下文 — trace_id、span_id 和 trace_flags — 添加到原生应用的日志上下文(MDC)中。通过在日志输出中打印这些值,你可以直接从某一条日志定位到对应的 trace,也可以从某个 trace 回溯到请求所生成的日志。
本页说明如何在 Java 原生应用的日志中暴露 trace 上下文。
先决条件: 本指南假定你的原生应用已经由 OpenTelemetry Java 智能体 2.x 进行插桩,并且是通过 Instrumentation 自定义资源和 instrumentation.opentelemetry.io/inject-java 注解注入的。下面描述的 MDC 键由智能体在运行时填充——如果未注入智能体,无论你如何配置日志模式,这些键都将为空。请先参阅 Java 自动插桩 以启用注入。
目录
工作原理在日志输出中暴露这些 IDSpring BootLogbackLog4j 2OpenTelemetry 智能体键 vs. Spring Boot / Micrometer 原生关联通过 OTLP 导出日志其他语言参考资料工作原理
Java 智能体提供了日志插桩,会将当前 span 上下文复制到日志库的 MDC(Mapped Diagnostic Context)中。你不需要解析 HTTP 头,也不需要编写任何代码来完成这件事——智能体会从传播头中提取上下文,并自动填充 MDC。注入的键如下:
这些键使用 snake_case,是智能体内置的默认值。注入默认启用,因此你只需要在日志输出模式中引用这些键即可。
插桩会与对应的日志库匹配:
如果你需要关闭(或重新启用)某个特定的注入,请在工作负载上设置相应的属性或环境变量。以下项的默认值均为 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 默认控制台 appender 的原生应用,你也可以改写 CONSOLE_LOG_PATTERN 属性,在模式中嵌入相同的 %X{trace_id} 标记。
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 日志记录的专用字段传递,而不是作为 MDC 属性,因此 OTLP 导出的日志无需将这些 ID 添加到日志模式中也能保持关联。
其他语言
其他 OpenTelemetry 语言在零代码(自动插桩)场景下也会将日志与 trace 关联,但注入的字段名称以及启用方式因语言而异。请参阅你所使用语言的上游指南:
这里特意没有列出 Go:它没有运行时智能体,并且基于 eBPF 的自动插桩不会将 trace 上下文注入到原生应用日志中。Go 中的日志与 trace 关联需要在代码中手动完成——例如,从 context.Context 中读取 span 上下文,或者通过 otelslog 桥接——因此这里没有可链接的零代码参考资料。
参考资料
- Logger MDC auto-instrumentation — 注入键和受支持日志库的权威列表。
- Logback MDC instrumentation README — 模式示例和配置选项。
- Java agent configuration 以及 suppressing specific instrumentation — 如何切换单个插桩。