配置 SDK

状态: 开发中

概述

配置 SDK 是 声明式配置接口 的一部分。

SDK 是 Instrumentation Config API 和其他面向用户的声明式配置功能的实现。它包含以下主要组件:

内存中配置模型

SDK 应提供 配置模型 的内存表示。虽然 ConfigProperties 是任何映射节点的无模式表示,但内存中配置模型应反映配置模型的模式。

鼓励 SDK 以语言惯用的方式提供此内存中表示。如果 SDK 需要公开类或接口,则推荐使用名称 Configuration

ConfigProvider

ConfigProvider API 的 SDK 实现必须使用代表配置模型的 .instrumentation 映射节点.instrumentationConfigProperties 来创建。

SDK 扩展组件

SDK 支持多种扩展 插件接口,允许用户和库自定义行为,包括数据的采样、处理和导出。通常,配置数据模型 为这些插件接口的内置实现定义了特定类型。例如,BatchSpanProcessor 类型引用了内置的 Batching span processor。模式还应支持指定库或用户定义的插件接口自定义实现的能力。

例如,自定义 span exporter 可以按如下方式配置:

tracer_provider:
  processors:
    - batch:
        exporter:
          my-exporter:
            config-parameter: value

在此,我们指定 tracer provider 具有一个与名为 my-exporter 的自定义 span exporter 配对的 batch span processor,该 exporter 使用 config-parameter: value 进行配置。为了使此配置成功,必须将 ComponentProvider 注册,其中 type: SpanExportername: my-exporter。当调用 parse 时,实现将遇到 my-exporter 并将相应配置转换为等效的 ConfigProperties 表示(即 properties: {config-parameter: value})。当调用 create 时,实现将遇到 my-exporter 并使用 parse 期间确定的 ConfigProperties 调用已注册的 ComponentProvider 上的 create plugin

考虑到不同语言固有的差异,扩展组件机制的细节可能比 OpenTelemetry 定义的其他 API 有更大的差异。这是可以预料的,并且是可以接受的,只要实现能产生预定义的行为。

ComponentProvider

ComponentProvider 负责解释配置并返回 SDK 扩展插件接口的实现。

ComponentProvider 通过 register 注册到配置的 SDK 实现中。这可以自动完成,也可以根据语言生态系统中可能的情况和惯例要求用户手动干预。例如,在 Java 中,ComponentProvider 可以使用 服务提供者接口 (SPI) 机制自动注册。

请参阅 create,其中详细介绍了 ComponentProvider 在配置模型解释中的用法。

支持的 SDK 扩展插件

配置数据模型应支持所有 SDK 扩展插件接口的配置。SDK 应支持通过 ComponentProvider 机制 注册 SDK 扩展插件接口的自定义实现。

下表列出了配置数据模型中所有 SDK 扩展插件接口的当前状态:

SDK 扩展插件接口状态
资源探测器+
文本映射传播器+
span 导出器+
span 处理器+
采样器+
ID 生成器- #70
拉取指标读取器+
推送指标导出器+
指标生成器+
样本蓄水池- #189
日志记录导出器+
日志记录处理器+
ComponentsProvider 操作

ComponentsProvider 必须提供以下功能:

创建插件

解释配置以创建 SDK 扩展插件接口的实例。

参数

  • properties - 代表在 配置模型 中为组件指定的配置的 ConfigProperties

返回: 配置好的 SDK 扩展插件接口实现。

插件接口可能具有可选或必需的属性,并且在类型或格式方面有特定要求。ComponentProvider 接受的属性集及其要求级别和预期类型构成了配置模式。ComponentProvider 应记录其配置模式并包含示例。

调用 Create Plugin 时,ComponentProvider 会解释 properties 并尝试根据其配置模式提取数据。如果失败(例如,缺少必需属性、类型不匹配等),Create Plugin 应返回错误。

SDK 操作

配置的 SDK 实现必须提供以下操作。

注意:由于这些操作是无状态的纯函数,因此它们不作为任何类型、类、接口等的一部分进行定义。SDK 可以以适合该语言的方式组织它们。

TODO:添加操作以使用新配置更新 SDK 组件,以供 OpAmp 使用

解析

解析并验证 配置文件

参数

  • file:要解析的 配置文件。这可以是文件路径、特定于语言的文件数据结构或文件内容的流。
  • file_formatfile 的文件格式(例如 yaml)。实现可以接受 file_format 参数,或从 file 扩展名推断,或包含特定于文件格式的 parse 重载,例如 parseYaml(file)。如果 parse 接受 file_format,则 API 的结构应使用户必须提供它。

返回: 配置模型

Parse 必须执行 环境变量替换

Parse 必须区分缺失的属性和存在的但为 null 的属性。例如,考虑以下片段,注意 .meter_provider.views[0].stream.drop 存在但为 null

meter_provider:
  views:
    - selector:
        name: some.metric.name
      stream:
        aggregation:
          drop:

因此,view stream 应配置为使用 drop 聚合。请注意,某些聚合具有其他参数,但 drop 没有。在此类情况下,用户不必指定空对象(即 drop: {})。

当遇到对 SDK 中未内置的 SDK 扩展组件 的引用时,Parse 必须将相应配置解析为通用的 ConfigProperties 表示,如 Create Plugin 中所述。

Parse 在以下情况下应返回错误:

  • file 不存在或无效
  • 解析后的 file 内容不符合 配置模型 模式。

创建

解释配置模型并返回 SDK 组件。

参数

返回: 顶级 SDK 组件

多个响应可以通过元组或其他封装组件的数据结构返回。

如果某个属性具有定义的默认值(即不是必需的)并且缺失或存在但为 null,Create 必须确保 SDK 组件配置为默认值。如果某个属性是必需的,并且缺失或存在但为 null,Create 应返回错误。例如,如果配置 span batching processor 并且 scheduleDelayMillis 属性缺失或存在但为 null,则该组件将配置为默认值 5000。但是,如果 exporter 属性缺失或存在但为 null,Create 将因 exporter 没有默认值而快速失败。

当遇到对 SDK 中未内置的 SDK 扩展组件 的引用时,Create 必须使用相应 typenameComponentProviderCreate Plugin 来解析组件,包括配置 properties 作为参数。如果未注册具有 typenameComponentProvider,Create 应返回错误。如果 Create Plugin 返回错误,Create 应传播该错误。

根据初始化 错误处理原则,如果遇到 configuration 中的错误(即快速失败),则应返回错误。

TODO:定义如果配置模型的部分内容不受支持时的行为

注册 ComponentProvider

SDK 必须提供注册 ComponentProvider 的机制。该机制可以是特定于语言的自动化的。例如,Java 实现可能会使用 服务提供者接口 机制来注册特定接口的实现作为 ComponentProvider

参数

  • component_provider - ComponentProvider
  • type - 用于提供插件接口的类型(例如 SpanExporter、Sampler 等)。
  • name - 用于标识组件类型的名称。这在 配置模型 中用于指定相应的 component_provider 提供该组件。

typename 构成一个唯一的键。如果使用相同的 typename 组合多次调用 Register,则必须返回错误。

示例

通过配置 API

ParseCreate 配置操作与 配置模型 可以结合使用,以实现简单或复杂的配置目标。

例如,一个简单的场景包括使用配置文件调用 Parse,然后将结果传递给 Create 以获取配置好的 SDK 组件。

OpenTelemetry openTelemetry = OpenTelemetry.noop();
try {
    // Parse configuration file to configuration model
    OpenTelemetryConfiguration configurationModel = parse(new File("/app/sdk-config.yaml"));
    // Create SDK components from configuration model
    openTelemetry = create(configurationModel);
} catch (Throwable e) {
    log.error("Error initializing SDK from configuration file", e);
}

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLogsBridge();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();

一个更复杂的场景可能包括从不同来源解析多个配置文件,使用自定义逻辑合并它们,并从合并后的配置模型创建 SDK 组件。

OpenTelemetry openTelemetry = OpenTelemetry.noop();
try {
    // Parse local and remote configuration files to configuration models
    OpenTelemetryConfiguration localConfigurationModel = parse(new File("/app/sdk-config.yaml"));
    OpenTelemetryConfiguration remoteConfigurationModel = parse(getRemoteConfiguration("http://example-host/config/my-application"));

    // Merge the configuration models using custom logic
    OpenTelemetryConfiguration resolvedConfigurationModel = merge(localConfigurationModel, remoteConfigurationModel);

    // Create SDK components from resolved configuration model
    openTelemetry = create(resolvedConfigurationModel);
} catch (Throwable e) {
    log.error("Error initializing SDK from configuration file", e);
}

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLogsBridge();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();

通过 OTEL_EXPERIMENTAL_CONFIG_FILE

设置 OTEL_EXPERIMENTAL_CONFIG_FILE 环境变量(对于支持它的语言)为用户提供了一种方便的方式来初始化 OpenTelemetry 组件,而无需学习特定于语言的配置细节或使用大量环境变量。访问配置的组件并安装到仪器中的模式将因语言而异。例如,Java 中的用法可能类似于:

# Set the required env var to the location of the configuration file
export OTEL_EXPERIMENTAL_CONFIG_FILE="/app/sdk-config.yaml"
// Initialize SDK using autoconfigure model, which recognizes that OTEL_EXPERIMENTAL_CONFIG_FILE is set and configures the SDK accordingly
OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();

// Access SDK components and install instrumentation
TracerProvider tracerProvider = openTelemetry.getTracerProvider();
MeterProvider meterProvider = openTelemetry.getMeterProvider();
LoggerProvider loggerProvider = openTelemetry.getLogsBridge();
ContextPropagators propagators = openTelemetry.getPropagators();
ConfigProvider configProvider = openTelemetry.getConfigProvider();

如果使用自动仪器,此初始化流程可能会自动发生。

参考