Skip to content

OpenTelemetry export

The native_observability_otel submodule provides the OTLP push exporter. It is part of the INTEGRATIONS preset (drush no:preset:integrations), which also enables native_observability_eca_bridge.

Routes

Route Path Permission
native_observability_otel.settings /admin/config/development/native-observability/settings/otel administer native observability otel

OTLP settings

NativeObservabilityOtelSettingsForm configures the push-side exporter: enable/disable, the OTLP HTTP endpoint, request timeout, service name/namespace/version, and additional HTTP headers sent on every export request. Current defaults are documented in Configuration.

The Prometheus scrape endpoint and its bearer token live in the separate native_observability_export module; see Prometheus and Elastic export.

Exporter plugins

Exporters implement ExporterInterface and are discovered through the NativeObservabilityExporter attribute (namespace Drupal\native_observability_otel\Plugin\NativeObservabilityExporter), managed by ExporterManager and exposed through the native_observability_otel.exporter_registry service. Three plugins ship with the module:

Plugin ID Class Role
opentelemetry OpenTelemetryExporter Pushes each completed request trace to the configured OTLP HTTP endpoint
prometheus PrometheusExporter No-op export(). Registers Prometheus in the plugin list because scraping is pull-based, not pushed by this subsystem
null_exporter NullExporter No-op exporter used to validate exporter discovery

OpenTelemetryTraceSubscriber always resolves the opentelemetry plugin ID through the registry; there is no settings field to switch the active exporter. The plugin type exists as an extension point: a custom module can register an additional NativeObservabilityExporter plugin and call it through ExporterRegistry::get() or ExporterRegistry::getAvailableExporters().

flowchart LR
    A[kernel.response] --> B[OpenTelemetryTraceSubscriber]
    B --> C{Own route excluded?}
    C -- yes --> Z[No export]
    C -- no --> D[ExporterRegistry.get 'opentelemetry']
    D --> E{Exporter available?}
    E -- no, disabled or empty endpoint --> Z
    E -- yes --> F[OpenTelemetryPayloadBuilder]
    F --> G[POST OTLP endpoint]

OTLP bearer token

When the collector requires authentication, generate and store the collector token with Drush:

drush native_observability:token:generate otlp
# alias:
drush no:token:generate otlp

The command prints the generated value once and stores it in the state key native_observability_otel.otlp_bearer_token. OpenTelemetryExporter reads it and sends Authorization: Bearer <token> on every OTLP export request. The token field on the settings form is write-only: an empty submission keeps the current token, and the sentinel value __clear__ removes it. For collectors that expect a different header name, use the Additional HTTP headers field instead.

Example target: OTLP collector or Tempo

drush config:set native_observability_otel.settings endpoint 'http://collector:4318/v1/traces' -y
drush config:set native_observability_otel.settings enabled true -y

A Grafana Alloy collector forwarding to Tempo needs a matching OTLP HTTP receiver, for example a otelcol.receiver.otlp block listening on 4318 with the http protocol enabled, exporting to otelcol.exporter.otlp pointed at Tempo's gRPC or HTTP ingest port.