Envoy OpenTelemetry 自定义 Exporter 扩展点:接入专属 OTLP 导出器的完整指南
2026/9/12 13:20:35 网站建设 项目流程

Envoy OpenTelemetry 自定义 Exporter 扩展点:接入专属 OTLP 导出器的完整指南

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

导读

本指南围绕 Envoy 的 OpenTelemetry tracer 新增的exporter扩展点展开,介绍如何在OpenTelemetryConfig中通过TypedExtensionConfig挂载自定义 tracing exporter,从而突破内置 gRPC/HTTP 两种 OTLP 导出方式的限制。读完本文,你将掌握envoy.tracers.opentelemetry.exporters扩展点的配置语法、互斥约束与默认行为,并了解如何基于源码级工厂接口开发自己的 exporter。

特性背景:从固定两种导出方式到可插拔扩展点

Envoy 内置的 OpenTelemetry tracer(扩展名envoy.tracers.opentelemetry)原本只支持两种向 OTLP Collector 上报 trace 的方式:

  • 通过grpc_service走 gRPC 通道上报 OTLP traces(对应源码 grpc_trace_exporter.h 中的OpenTelemetryGrpcTraceExporter);
  • 通过http_service走 HTTP 通道上报 OTLP traces(对应源码 http_trace_exporter.h 中的OpenTelemetryHttpTraceExporter)。

本次新增的exporter扩展点允许使用者接入自定义 tracing exporter,例如对接私有采集服务、特殊的鉴权体系或定制的批处理管道,而不再局限于 Envoy 内置的两种传输协议。该字段在 opentelemetry.proto 中定义:

// Specifies the custom exporter to be used by the OpenTelemetry tracer. // Only one of ``grpc_service``, ``http_service``, ``exporter`` may be used. // // [#extension-category: envoy.tracers.opentelemetry.exporters] // [#not-implemented-hide:] core.v3.TypedExtensionConfig exporter = 10 [(udpa.annotations.field_migrate).oneof_promotion = "otlp_exporter"];

从定义可见,该字段使用标准的TypedExtensionConfig(名称 +typed_config),扩展类别为envoy.tracers.opentelemetry.exportersoneof_promotion迁移注解说明它未来会被并入名为otlp_exporter的 oneof 字段。

配置形态:三选一的互斥约束

约束规则与校验逻辑

grpc_servicehttp_serviceexporter三者最多只能配置一个,且 OpenTelemetry tracer 必须恰好配置其中一种,否则 Envoy 启动会直接抛异常。该约束在 opentelemetry_tracer_impl.cc 中实现:

const int exporter_count = (opentelemetry_config.has_grpc_service() ? 1 : 0) + (opentelemetry_config.has_http_service() ? 1 : 0) + (opentelemetry_config.has_exporter() ? 1 : 0); if (exporter_count != 1) { throw EnvoyException("OpenTelemetry Tracer must have exactly one of gRPC, HTTP, or custom " "exporter configured."); }

对应的异常信息在 config_test.cc 中被测试断言为"OpenTelemetry Tracer must have exactly one of gRPC, HTTP, or custom exporter configured."

完整的自定义 exporter 配置示例

以下 YAML 展示了在 HTTP tracing 配置中挂载自定义 exporter 的标准写法(出自 config_test.cc 的测试用例):

http: name: envoy.tracers.opentelemetry typed_config: "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig exporter: name: envoy.tracers.opentelemetry.exporters.dummy_config_test typed_config: "@type": type.googleapis.com/google.protobuf.Empty

字段说明:

字段说明
exporter.name自定义 exporter 工厂在注册表中注册的扩展名,必须以envoy.tracers.opentelemetry.exporters.为前缀(对应工厂的category()返回值)
exporter.typed_config传给该工厂的自定义配置,@type必须与该工厂声明的configType匹配,经translateOpaqueConfig反序列化后传给createExporter

创建流程与校验链

在 opentelemetry_tracer_impl.cc 中,当配置了exporter时,Driver 构造流程如下:

  1. 通过Envoy::Config::Utility::getFactory<OpenTelemetryTraceExporterFactory>(exporter_config)按名称查找工厂,找不到则抛出"OpenTelemetry trace exporter factory not found: '<name>'"
  2. 调用createEmptyConfigProto()得到空配置原型,若返回nullptr则抛出"OpenTelemetry trace exporter factory '<name>' returned nullptr from createEmptyConfigProto()"(该分支由 config_test.cc 的NullConfigTraceExporterFactory用例覆盖);
  3. 调用translateOpaqueConfigtyped_config反序列化为工厂声明的配置类型,失败则抛出翻译错误;
  4. 在主线程完成校验后,为 worker 线程构造使用NullValidationVisitorTracerFactoryContextImpl,以保证多线程安全;
  5. 在 TLS 初始化回调中调用custom_exporter_factory->createExporter(*shared_unpacked_config, *worker_factory_context)创建 exporter 实例(见 opentelemetry_tracer_impl.cc)。

若 exporter 创建失败或未配置任何有效 exporter,tracer 会记录警告日志"OpenTelemetry tracer initialized without a valid exporter; spans will be dropped.",Span 将被丢弃而不会崩溃。

扩展点源码剖析:Exporter 抽象与工厂接口

基类OpenTelemetryTraceExporter

所有 OTLP exporter 的基类定义在 trace_exporter.h,核心接口只有一个:

class OpenTelemetryTraceExporter : public Logger::Loggable<Logger::Id::tracing> { public: /** * @brief Exports the trace request to the configured OTLP service. * @param request The protobuf-encoded OTLP trace request. * @return true When the request was sent. * @return false When sending the request failed. */ virtual bool log(const ExportTraceServiceRequest& request) = 0; ... };
  • 入参ExportTraceServiceRequest是 OTLP 协议collector/trace/v1的 protobuf 请求,由@opentelemetry-proto//:trace_service_proto_cc提供(见 BUILD);
  • 返回值bool表示请求是否成功发出;返回false即视为导出失败;
  • 基类还提供logExportedSpans()帮助方法,用于在 debug 日志中输出本次导出的 Span 数量。

内置的 OpenTelemetryGrpcTraceExporter 继承自该基类并实现了Grpc::AsyncRequestCallbacks<ExportTraceServiceResponse>,将请求包装为对ExportTraceService的 gRPC 异步调用;而 OpenTelemetryHttpTraceExporter 则实现Http::AsyncClient::Callbacks,通过 ClusterManager 发起 HTTP 异步请求,并用Http::AsyncClientRequestTracker跟踪在途请求以便析构时取消。

工厂接口OpenTelemetryTraceExporterFactory

自定义 exporter 的扩展入口是 trace_exporter.h 中定义的工厂抽象:

class OpenTelemetryTraceExporterFactory : public Envoy::Config::TypedFactory { public: /** * @brief Creates an OpenTelemetryTraceExporter. * * `createExporter` is invoked concurrently from multiple worker threads * during TLS initialization and implementations MUST be stateless, * re-entrant, and thread-safe. */ virtual absl::StatusOr<OpenTelemetryTraceExporterPtr> createExporter(const Protobuf::Message& config, Server::Configuration::TracerFactoryContext& context) const PURE; std::string category() const override { return "envoy.tracers.opentelemetry.exporters"; } };

编写自定义 exporter 时必须遵守以下契约:

  • 继承OpenTelemetryTraceExporterFactory并实现createExporter
  • 实现name()返回形如envoy.tracers.opentelemetry.exporters.<your_name>的扩展名;
  • 实现createEmptyConfigProto()返回配置原型,不得返回nullptr
  • createExporter在 worker 线程 TLS 初始化阶段会被并发调用,实现必须是无状态、可重入且线程安全的;
  • 错误必须通过absl::StatusOr返回,禁止抛出 C++ 异常。

测试中注册了两个示范工厂作为参考实现:config_test.cc 中的DummyTraceExporterFactory(configType 为google.protobuf.Empty)与NullConfigTraceExporterFactory(configType 为google.protobuf.Struct,用于验证空配置原型报错路径)。

运行时行为与 Span 上报链路

Driver 将 tracer 存储在 TLS(Thread Local Storage)槽位中,每个 worker 线程持有独立的 tracer 实例(opentelemetry_tracer_impl.cc)。startSpan()会先通过SpanContextExtractor尝试从传播头提取父 SpanContext:

  • 若存在传播头且提取成功,则以父 SpanContext 为上下文创建子 Span;
  • 若提取失败,返回Tracing::NullSpan(空 Span),不导出;
  • 若不存在传播头,则根据 tracing 决策直接创建全新 Span,未采样时调用setSampled(false)丢弃。

Span 的导出由Tracer调用exporter->log(request)完成,期间 Envoy 会按max_cache_size(默认 1024,见 opentelemetry_tracer_impl.cc 的DEFAULT_MAX_CACHE_SIZE)在内存中缓存 Span,以应对后端暂时不可用的场景。

与 OpenTelemetryConfig 其他字段的搭配

exporter扩展点可与以下字段自由组合(完整定义见 opentelemetry.proto):

字段作用默认值
service_name填充到 ResourceSpan 的 Resource 属性,service.name缺省为"unknown_service:envoy""unknown_service:envoy"
resource_detectors有序的资源探测器列表,类别envoy.tracers.opentelemetry.resource_detectors,仓库内置 dynatrace、environment、static 三类(见 resource_detectors 目录)
sampler采样器,类别envoy.tracers.opentelemetry.samplers,内置 always_on、parent_based、trace_id_ratio_based、cel、dynatrace 等(见 samplers 目录);不配置时使用 Envoy 默认采样决策
max_cache_size后端不可用时的 Span 内存缓存上限1024
set_telemetry_sdk_resource_attributes是否设置telemetry.sdk.language/name/version属性true
set_service_name_resource_attribute是否设置service.name资源属性true
set_instrumentation_scope是否在 trace 上设置 instrumentation scope 名称("envoy")与版本true

需要特别说明的是,exporter采用TypedExtensionConfig机制(见 extension.proto 中TypedExtensionConfig的定义),配置会经过 Envoy 严格的 message validation;主线程校验通过后,worker 线程复用已翻译好的配置,避免重复校验带来的竞态问题。

测试覆盖与验证

仓库对 exporter 扩展点提供了完整的测试验证(位于 test/extensions/tracers/opentelemetry 目录):

  • config_test.cc:验证三选一互斥约束的异常抛出、自定义 exporter 的正常创建流程、createEmptyConfigProto()返回空指针时的报错路径;
  • grpc_trace_exporter_test.cc 与 http_trace_exporter_test.cc:分别覆盖内置 gRPC/HTTP exporter 的请求组装、成功/失败回调;
  • grpc_trace_exporter_integration_test.cc 与 http_trace_exporter_integration_test.cc:集成环境下验证真实上报链路;
  • opentelemetry_tracer_impl_test.cc:验证 Driver 生命周期、Span 采样决策与导出行为。

适用前提与限制

  • exporter字段在 proto 中带有[#not-implemented-hide:]标注,表示该扩展点面向自定义实现开放;启用自定义 exporter 需要将对应扩展编译进 Envoy(通过bazel的扩展构建系统注册到envoy.tracers.opentelemetry.exporters类别下);
  • 当前版本中grpc_servicehttp_serviceexporter三者互斥且必须恰好其一,未来按oneof_promotion = "otlp_exporter"迁移后会成为真正的 oneof 字段,配置语义保持一致;
  • 若自定义 exporter 未就绪或创建失败,Span 会被静默丢弃(仅记录 warn 日志),生产环境应配合监控日志确保 exporter 持续可用。

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询