feat(config): exporter plugin loading via entry points for declarative config#5128
feat(config): exporter plugin loading via entry points for declarative config#5128MikeGoldsmith wants to merge 7 commits into
Conversation
SpanExporter, LogRecordExporter, and PushMetricExporter are changed from @DataClass to TypeAlias = dict[str, Any] in models.py, preserving unknown exporter names as dict keys through the config pipeline. Each signal's factory function (_create_span_exporter, _create_log_record_exporter, _create_push_metric_exporter) now has a registry of known exporter names (otlp_http, otlp_grpc, console) with fallback to load_entry_point for unknown names via the opentelemetry_{traces,logs,metrics}_exporter entry point groups. _parse_headers in _common.py is updated to handle both NameStringValuePair objects (typed config) and raw dicts (YAML path), making the full dict path testable end-to-end. Assisted-by: Claude Opus 4.6
The generated models are unchanged. Python dataclasses don't enforce field types at runtime, so parent fields like BatchSpanProcessor.exporter naturally accept raw dicts (from the YAML loader) alongside typed instances. Tests updated to pass raw dicts consistently. Assisted-by: Claude Opus 4.6
Use typed SpanExporterConfig, LogRecordExporterConfig, and
PushMetricExporterConfig with additional_properties from the
@_additional_properties decorator instead of raw dict iteration.
Known exporter types are checked via typed fields and their
registries. Unknown plugin names from additional_properties are
loaded via the opentelemetry_{traces,logs,metrics}_exporter
entry point groups.
Assisted-by: Claude Opus 4.6
| _SPAN_EXPORTER_REGISTRY: dict = { | ||
| "otlp_http": _create_otlp_http_span_exporter, | ||
| "otlp_grpc": _create_otlp_grpc_span_exporter, | ||
| "console": lambda _: ConsoleSpanExporter(), |
There was a problem hiding this comment.
Why does "console" for this and logger have to be lambda but regular named function for metrics?
There was a problem hiding this comment.
Traces and logs console exporters have simple constructors with args so a lambda works. Metrics needs a named function because _create_console_metric_exporter processes temporality_preference and default_histogram_aggregation from the config before constructing the exporter.
I also fixed the logs console entry — it was unnecessarily wrapping a helper function. Now both traces and logs use lambda _: Console*Exporter() consistently too.
| Known exporter types are checked via typed fields on the LogRecordExporter | ||
| dataclass. Unknown exporter names captured in additional_properties |
There was a problem hiding this comment.
Curiousity/Nit: are "known" vs "unknown" the official terms for declarative config? Overall it works fine, while something like "core"/"standard" vs "custom"/"additional" is just me thinking aloud as "unknown" is sometimes but not always used as a fallback.
There was a problem hiding this comment.
known/unknown are not declarative config terms and I agree the naming could be a little friendlier 😄
I've opened #5195 to do the rename across all the plugin loading code once the structural PRs have landed. That way we can batch it in one pass rather than updating each open PR 👍🏻
Make console exporter registration consistent across signals: - traces: lambda _: ConsoleSpanExporter() (simple constructor) - logs: lambda _: ConsoleLogRecordExporter() (was wrapping a helper) - metrics: _create_console_metric_exporter (named function, takes temporality/aggregation config) Metrics uses a named function because it needs to process config args. Traces and logs are simple constructors — no wrapper needed. Assisted-by: Claude Opus 4.6
Description
Extends exporter support in declarative file configuration to handle custom (plugin) exporters across all three signals, matching the spec's PluginComponentProvider mechanism.
Depends on #5131 (
additional_propertiessupport for generated models).Solution
Each signal's factory function uses typed exporter config with
additional_properties:SpanExporterConfig_SPAN_EXPORTER_REGISTRYopentelemetry_traces_exporterPushMetricExporterConfig_METRIC_EXPORTER_REGISTRYopentelemetry_metrics_exporterLogRecordExporterConfig_LOG_EXPORTER_REGISTRYopentelemetry_logs_exporterKnown exporter types (
otlp_http,otlp_grpc,console) are checked via typed fields and their registries. Unknown plugin names fromadditional_propertiesare loaded via entry points.Custom exporter example
Remaining work
The OTLP factory functions still use typed attribute access (
config.endpoint, etc.) internally. Converting them to accept raw dicts from the YAML loader is tracked in #5127.Closes #5069