插桩生态系统

OpenTelemetry Java 中的插桩生态系统

插桩(Instrumentation)使用 API 记录遥测数据。 SDK 是 API 的内置参考实现,并且经过配置来处理和导出插桩 API 调用生成的遥测数据。 本页将探讨 OpenTelemetry Java 中的 OpenTelemetry 生态系统,包括面向终端用户的资源以及跨领域的插桩相关主题:

  • 插桩类别针对不同的使用场景和安装模式。
  • 上下文传播实现了链路、指标和日志之间的关联,使这些信号能够相互补充。
  • 语义约定定义了如何为标准操作生成遥测数据。
  • 日志插桩用于将现有 Java 日志框架中的日志接入 OpenTelemetry。

插桩类别

插桩分为以下几类:

  • 零代码: Java 代理是一种零代码插桩形式 [1],可动态操作应用的字节码。
  • 零代码: Spring Boot 启动器是一种零代码插桩形式 [1], 它利用 Spring 自动配置来安装库插桩.
  • 库插桩 通过包装或使用扩展点来对库进行插桩, 这要求用户手动安装和/或调整库的使用方式。
  • 原生插桩是直接内置在库和框架中的。
  • 手动插桩是由应用开发者编写的,且通常特定于应用的业务领域。
  • 适配层用于将数据从一个可观测性库桥接到另一个,通常是某些库导入到 OpenTelemetry 中。

[1]: 零代码插桩会根据检测到的库或框架自动安装。

opentelemetry-java-instrumentation 项目包含了 Java 代理、Spring Boot 启动器和库插桩的源代码。

零代码: Java 代理

Java 代理是一种零代码的自动插桩形式,可动态操作应用的字节码。

要查看 Java 代理已插桩库列表,请参考支持的库中 “自动插桩版本” 一栏。

更多详情请参见 Java 代理

零代码: Spring Boot 启动器

Spring Boot 启动器是一种零代码的自动插桩形式, 它利用 Spring 自动配置来安装库插桩

详情请参见 Spring Boot 启动器

库插桩

库插桩 通过包装或使用扩展点来对库进行插桩,这要求用户安装和/或调整库的使用方式。

关于插桩库的列表,请参见支持的库中的 “独立库插桩” 列。

原生插桩

原生插桩是直接内置在库或框架中的。 OpenTelemetry 鼓励库的作者使用 API(../api/) 添加原生插桩。 从长远来看,我们希望原生插桩能成为行业常态, 同时将 OpenTelemetry 在 opentelemetry-java-instrumentation 中维护的插桩方案视为填补当前空白的临时手段。

手动插桩

手动插桩是由应用开发者编写的,且通常特定于应用的业务领域。

适配层

适配层是一种插桩组件,用于将数据从一个可观测性库桥接到另一个,通常是从某些库导入到 OpenTelemetry 中。

OpenTelemetry Java 生态中维护的适配层包括:

描述文档信号构件
OpenTracing 桥接到 OpenTelemetryREADME链路io.opentelemetry:opentelemetry-opentracing-shim:1.42.1
Opencensus 桥接到 OpenTelemetryREADME链路, 指标io.opentelemetry:opentelemetry-opencensus-shim:1.42.1-alpha
Micrometer 桥接到 OpenTelemetryREADME指标io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5:2.7.0-alpha
JMX 桥接到 OpenTelemetryREADME指标io.opentelemetry.instrumentation:opentelemetry-jmx-metrics:2.7.0-alpha
将 OpenTelemetry 桥接到 Prometheus Java clientREADME指标io.opentelemetry.contrib:opentelemetry-prometheus-client-bridge:1.38.0-alpha
将 OpenTelemetry 桥接到 MicrometerREADME指标io.opentelemetry.contrib:opentelemetry-micrometer-meter-provider:1.38.0-alpha
Log4j 桥接到 OpenTelemetryREADME日志io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17:2.7.0-alpha
Logback 桥接到 OpenTelemetryREADME日志io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0:2.7.0-alpha
将 OpenTelemetry 上下文桥接到 Log4jREADME上下文io.opentelemetry.instrumentation:opentelemetry-log4j-context-data-2.17-autoconfigure:2.7.0-alpha
将 OpenTelemetry 上下文桥接到 LogbackREADME上下文io.opentelemetry.instrumentation:opentelemetry-logback-mdc-1.0:2.7.0-alpha

上下文传播

OpenTelemetry 的各类 API 旨在实现互补协同,其整体效用远大于各部分单独作用之和。 每种信号都有其独特优势,它们共同构建出一个完整且有价值的可观测性图景。

重要的是,来自各类信号的数据通过链路上下文关联在一起:

  • Span 通过父级 Span 和链接与其他 Span 相关联,而这两者均记录了相关 Span 的链路上下文。
  • 指标通过示例(exemplars)与 Span 相关联,这些示例记录了特定度量的链路上下文。
  • 日志通过在日志记录中包含链路上下文,与 Span 建立关联。

要使这种关联机制生效,链路上下文必须在整个应用内部(跨函数调用和线程)以及应用边界之间进行传播。 上下文 API 为此提供了支持。插桩代码的编写需具备上下文感知能力,具体而言:

  • 作为应用入口点的库(即 HTTP 服务器、消息消费者等)应当从传入的消息中提取上下文
  • 作为应用出口点的库(即 HTTP 客户端、消息生产者等)应当将上下文注入到传出的消息中。
  • 库应当以隐式或显式的方式,在调用栈中以及跨线程传递上下文

语义约定

语义约定定义了如何为标准操作生成遥测数据。 具体而言,语义约定规定了跨度名称、跨度类型、指标工具、指标单位、指标类型,以及属性键、属性值和属性要求级别等内容。

编写插桩代码时,请参考语义约定并遵循所有适用于该领域的规范。

OpenTelemetry Java 发布了一些构件来帮助遵循语义约定,其中包括为属性键和属性值生成的常量。

日志插桩

尽管 LoggerProviderLogger 的 API 在结构上 与对应的链路指标 的API 相似, 但它们适用于不同的使用场景。 截至目前,LoggerProviderLogger 及相关类代表了日志桥接 API, 其存在的目的是编写日志附加器(log appenders),以便将通过其他日志 API 或框架记录的日志桥接到 OpenTelemetry 中。 它们并非供终端用户用作 Log4j、SLF4J、Logback 等日志工具的替代品。

在 OpenTelemetry 中,针对不同的应用需求,有两种典型的日志插桩使用流程:

直接发送至收集器(collector)

在 “直接发送至收集器” 流程中,日志通过网络协议(例如 OTLP)直接从应用发送到收集器。 这种流程设置简单,因为它不需要任何额外的日志转发组件, 并且允许应用能够轻松地输出符合日志数据模型的结构化日志。 然而,应用将日志进行队列处理并导出到网络地址所产生的开销,可能并非适用于所有应用。

要使用此流程,步骤如下:

  • 安装合适的日志附加器(appender)。[1]
  • 配置 OpenTelemetry 日志 SDK, 将日志记录导出至期望的目标地址(收集器 或其他位置)。

[1]:日志附加器是一种适配层(shim),用于将来自日志框架的日志桥接到 OpenTelemetry 日志 SDK 中。 参见 “将 Log4j 桥接到 OpenTelemetry”、“将 Logback 桥接到 OpenTelemetry” 条目。 有关多种场景的演示,可参考 日志附加器示例

通过文件或标准输出(stdout)

在“通过文件或标准输出”流程中,日志会被写入文件或标准输出。 另一个组件(例如 FluentBit)负责读取或跟踪(tailing)这些日志,将其解析为更结构化的格式,并将其转发到目标位置(如收集器)。 在应用的需求不允许因直接发送至收集器而产生额外开销的情况下,这种流程可能更为适用。 然而,这种流程要求所有下游所需的日志字段都必须编码到日志中,并且读取日志的组件需要将数据解析为[日志数据模型]格式(/docs/specs/otel/logs/data-model)。 日志转发组件的安装与配置不在本文档的讨论范围内。

通过安装适配层将 OpenTelemetry 上下文桥接到日志框架中,即可实现日志与链路的关联。 参见 “将 OpenTelemetry 上下文桥接到 Log4j”、“将 OpenTelemetry 上下文桥接到 Logback” 条目。