Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
304 changes: 304 additions & 0 deletions proposals/0069_prometheus-exporters-otel-embedding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
## Embeddable Prometheus Exporters in OpenTelemetry Collectors

* **Owners:**
* [@ArthurSens](https://github.com/ArthurSens)

* **Implementation Status:** Not implemented

* **Related Issues and PRs:**
* https://github.com/prometheus/exporter-toolkit/pull/357 (proof of concept)
* https://github.com/prometheus/node_exporter/pull/3459 (proof of concept)
* https://github.com/ArthurSens/prometheus-opentelemetry-collector (proof of concept)

* **Other docs or links:**
* https://github.com/prometheus/opentelemetry-collector-bridge
* https://github.com/prometheus/prometheus-opentelemetry-collector

> TL;DR: This proposal introduces a mechanism to embed Prometheus exporters as native OpenTelemetry Collector receivers, reducing duplication of effort between the two ecosystems and enabling the "single binary" promise for telemetry collection without forcing reimplementation of hundreds of existing Prometheus exporters.

## Why

The OpenTelemetry Collector ecosystem faces a significant challenge: many components in collector-contrib are "drop-in" replacements for existing Prometheus exporters but often become unmaintained before reaching stability. This duplication of effort occurs because users increasingly adopt a "single binary to collect all telemetry" approach, leading to reimplementation of functionality that already exists in mature Prometheus exporters.

This issue became particularly visible during OpenTelemetry's CNCF Graduation attempt, where feedback highlighted that users often feel frustrated when upgrading versions. In response, the Collector SIG decided to be stricter about accepting new components and more proactive in removing unmaintained or low-quality ones.

Meanwhile, the Prometheus community has developed hundreds of exporters over many years, many of which are stable. Creating parallel implementations in the OpenTelemetry ecosystem wastes community resources and often results in "drive-by contributions" that are abandoned shortly after acceptance.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow, this section should mention that Prometheus exporters are "metrics only" for obvious reasons. Therefore, this is only talking about metrics collectors. To collect other telemetry signals, other collectors are still required.

This could, BTW, be another reason to go down this path: If you need an OTel style collector anyway for the non-metrics signals, the embedding approach still allows you to plug in Prometheus exporters for metrics. (While currently, if you are not happy with the metrics from the OTel native metrics collector, you needed to run the Prometheus exporter in addition to the OTel collector just for the metrics.)


### Pitfalls of the current solution

1. **Duplication of Work**: Infrastructure monitoring receivers are reimplemented in OpenTelemetry when functionally equivalent Prometheus exporters already exist.

2. **Unmaintained Components**: Many OpenTelemetry receivers that replicate Prometheus exporter functionality become unmaintained in early development stages.

3. **Quality and Stability Issues**: The pressure to provide comprehensive coverage leads to accepting components that may not meet quality standards, contributing to collector-contrib's stability problems.

4. **Diverging Ecosystems**: Two communities are solving the same problems independently, fragmenting effort and expertise.

5. **Maintenance Burden**: Both ecosystems must independently maintain similar functionality for monitoring the same infrastructure components.

## Goals

* Enable embedding of Prometheus exporters as native OpenTelemetry Collector receivers via the OpenTelemetry Collector Builder (OCB).
* Reduce duplication of effort between Prometheus and OpenTelemetry communities.
* Maintain the "single binary" promise for users who follow the single binary approach.
* Leverage existing, mature Prometheus exporters instead of reimplementing them in OTel Collector's side.
* Unify the two ecosystems to increase the likelihood of attracting more maintainers and contributors.

### Audience

* Prometheus exporter maintainers and developers
* OpenTelemetry Collector users and contributors
* Organizations using both Prometheus and OpenTelemetry in their observability stack
* Distribution builders (e.g., Grafana Alloy, OllyGarden Rose, AWS ADOT, DataDog DDOT, Elastic EDOT)

## Non-Goals

* Replace the existing OpenTelemetry Prometheus receiver (which scrapes Prometheus endpoints).
* Force all Prometheus exporters to implement embedding interfaces immediately.
* Automatically remove existing OpenTelemetry receivers that overlap with Prometheus exporters (this follows OpenTelemetry's own component removal policy).
* Mandate that OpenTelemetry collector-contrib includes embedded Prometheus exporters (distributions can be customized).

## How

### Overview

Prometheus exporters function similarly to OpenTelemetry Collector receivers: they gather information from infrastructure and expose it as metrics. The key difference is the output format and collection mechanism. Prometheus exporters expose an HTTP endpoint (typically `/metrics`) that is scraped, while OpenTelemetry receivers push metrics into a pipeline.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And Prometheus exporters are only concerned with metrics, no other telemetry signals.


This proposal introduces a bridge between these two paradigms by:

1. **Using a dedicated Go library** (`opentelemetry-collector-bridge`) that defines interfaces Prometheus exporters can implement
2. **Providing adapter code** that converts Prometheus Registry metrics to OpenTelemetry's pmetric format
3. **Implementing OpenTelemetry Collector receiver interfaces** that wrap the adapter and Prometheus exporter

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│ OpenTelemetry Collector │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Prometheus Exporter Receiver │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Prometheus Exporter │ │ │
│ │ │ (implements ExporterLifecycleManager) │ │ │
│ │ │ │ │ │
│ │ │ ┌──────────────────────────────────────┐ │ │ │
│ │ │ │ Prometheus Registry │ │ │ │
│ │ │ │ (Collectors gathering metrics) │ │ │ │
│ │ │ └──────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ OTel Collector Bridge │ │ │
│ │ │ (Periodic collection + conversion) │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ └──────────────────────┼─────────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Consumer.Metrics │ │
│ │ (Pipeline data) │ │
│ └──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Processors │ │
│ └──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Exporters │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```

### New Interfaces in opentelemetry-collector-bridge

The new `opentelemetry-collector-bridge` library would live in a dedicated repository under the Prometheus organization. Based on the integration model explored so far, it should define exporter lifecycle and configuration hooks along these lines:

#### ExporterLifecycleManager Interface

```go
// ExporterLifecycleManager is the interface that Prometheus exporters must implement
// to be embedded in the OTel Collector.
type ExporterLifecycleManager interface {
// Start sets up the exporter and returns a prometheus.Registry
// containing all the metrics collectors.
Start(ctx context.Context, exporterConfig Config) (*prometheus.Registry, error)

// Shutdown is used to release resources when the receiver is shutting down.
Shutdown(ctx context.Context) error
}
```

#### Configuration Interfaces

```go
// ConfigUnmarshaler is the interface used to unmarshal the exporter-specific
// configuration using mapstructure and struct tags.
type ConfigUnmarshaler interface {
// GetConfigStruct returns a pointer to the config struct that mapstructure
// will populate. The struct should have appropriate mapstructure tags.
GetConfigStruct() Config
}

// Config is the interface that exporter-specific configurations must implement.
type Config interface {
// Validate checks if the configuration is valid.
Validate() error
}
```

#### Receiver Configuration

```go
// ReceiverConfig holds the common configuration for all Prometheus exporter receivers.
type ReceiverConfig struct {
// ScrapeInterval defines how often to collect metrics from the exporter.
// Default: 30s
ScrapeInterval time.Duration `mapstructure:"scrape_interval"`

// ExporterConfig holds the exporter-specific configuration.
ExporterConfig map[string]interface{} `mapstructure:"exporter_config"`
}
```

### Prometheus Registry to pmetric Conversion

The `opentelemetry-collector-bridge` library would include a scraper component that:

1. Calls `registry.Gather()` to collect metrics from the Prometheus Registry
2. Converts Prometheus metric families to OpenTelemetry's pmetric format

This conversion logic can leverage or adapt existing conversion code from different projects from the OpenTelemetry community. An non-exhaustive list is presented below:
* https://github.com/open-telemetry/opentelemetry-collector/tree/main/scraper/scraperhelper
* https://pkg.go.dev/go.opentelemetry.io/contrib/bridges/prometheus

### OpenTelemetry Collector Receiver Implementation

The `opentelemetry-collector-bridge` library would provide a complete implementation of OpenTelemetry's receiver interfaces:

1. **component.Factory** - for component type and default configuration
2. **component.Component** - for lifecycle management
3. **receiver.Factory** - for creating receiver instances
4. **receiver.Metrics** - for producing pmetric data

This implementation would:
- Start the Prometheus exporter and obtain its Registry
- Run a periodic scrape loop based on the configured interval
- Convert scraped metrics to pmetric format
- Push metrics to the OpenTelemetry pipeline consumer

### Using with OpenTelemetry Collector Builder

Once a Prometheus exporter implements the new interfaces, it can be included in custom OpenTelemetry Collector distributions via OCB:

```yaml
# ocb-config.yaml
receivers:
- gomod: github.com/prometheus/node_exporter v1.x.x
```

The OCB would recognize the exporter as a valid receiver and include it in the built collector binary.

To keep dependency compatibility visible, a dedicated `prometheus-opentelemetry-collector` distribution would be created to continuously test dependency conflicts and compilation failures when embeddable exporters are added to a generated collector build.

### Example Configuration

In the OpenTelemetry Collector configuration:

```yaml
receivers:
node_exporter:
scrape_interval: 30s

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make use of the scraper or scraperhelper libraries?

https://github.com/open-telemetry/opentelemetry-collector/blob/5dea5ae7a4baa4b22305b01e075d81e0300c43c0/scraper/metrics.go#L23 would be pretty easy to implement using a prometheus.Registerer.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting. I wasn't even aware this existed. We should try this later @kgeckhart

exporter_config:
# Node exporter specific configuration
collectors:
- cpu
- diskstats
- filesystem

exporters:
otlp:
endpoint: otelcol:4317

service:
pipelines:
metrics:
receivers: [node_exporter]
exporters: [otlp]
```

### Implementation Steps

1. **Create the `opentelemetry-collector-bridge` repository** under the Prometheus organization
2. **Define the interfaces** in the bridge library based on the explored integration model
3. **Implement the Prometheus to pmetric converter** (potentially adapting existing code)
4. **Validate with reference exporters** such as `stackdriver_exporter` and `yet-another-cloudwatch-exporter`
5. **Create a dedicated `prometheus-opentelemetry-collector` distribution** to continuously test dependency conflicts and generated collector compilation
6. **Document** the integration pattern for other exporters
7. **Gradually adopt** across other Prometheus exporters based on community interest

### Migration and Compatibility

* **No breaking changes** to existing Prometheus exporters that don't adopt the interfaces
* **Opt-in adoption** - exporters can choose when/if to implement embedding support
* **Backward compatibility** - embedded exporters still work as standalone exporters

### Known Problems

1. **Dependency conflicts**: Prometheus exporters and OpenTelemetry collector-contrib use different dependency versions. Building a distribution with both may require dependency alignment or replace directives in the OCB yaml file. A dedicated `prometheus-opentelemetry-collector` distribution should be used to catch these issues continuously as new embeddable exporters are added.

2. **Scope of adoption**: It's unclear how many Prometheus exporters will adopt these interfaces. The proposal targets exporters in the `prometheus` and `prometheus-community` GitHub organizations initially.

3. **Metric semantics**: Subtle differences in how Prometheus and OpenTelemetry handle certain metric types may require careful mapping.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a source of friction in the different naming conventions.

The idea with naming schemas could complement this nicely and should maybe mentioned here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we could tackle this in other initiatives (e.g. Otel schema optional adoption/changes)


## Alternatives

### 1. Continue parallel implementation

Continue the current approach where OpenTelemetry community reimplements Prometheus exporter functionality.

**Rejected because**: This perpetuates the duplication of effort, maintenance burden, and quality issues that prompted this proposal.

### 2. Separate process managed by collector

Start Prometheus exporters as separate processes managed by the OpenTelemetry Collector, OpenAMP supervisor, or Kubernetes operator. The collector would scrape these processes' `/metrics` endpoints.

**Trade-offs**:
- Pros: No code changes needed to exporters; simpler dependency management
- Cons: Loses the "single binary" promise; increased operational complexity; higher resource usage; more complex deployment

This could serve as a complementary approach for exporters that cannot be embedded (e.g., those with complex dependencies or those requiring special privileges or written in languages that are not Go).

### 3. Use OpenTelemetry receiver exclusively

Rely solely on OpenTelemetry's existing Prometheus receiver that scrapes Prometheus exporters.

**Rejected because**: This doesn't solve the "single binary" goal and still requires running separate exporter processes. It also doesn't address the underlying duplication problem for new infrastructure integrations.

### 4. Use exporter-toolkit for adapter implementation

Extend the existing `exporter-toolkit` project to include the adapter code and interfaces for embedding exporters.

**Rejected because**: The exporter-toolkit was designed specifically to facilitate HTTP interactions (TLS, authentication, etc.) for Prometheus exporters. Adding adapter logic and OpenTelemetry receiver interfaces would expand its scope beyond its original purpose and design. A dedicated library with a clear focus on the bridge between Prometheus exporters and OpenTelemetry Collectors is more appropriate.

### 5. Wait for universal OTLP adoption

Wait until all infrastructure components natively export OTLP metrics.

**Rejected because**: This will take many years and may never fully happen. Prometheus exporters represent significant existing investment and will continue to be developed.

## Action Plan

The tasks to implement this proposal:

* [x] Create the `opentelemetry-collector-bridge` repository under the Prometheus organization
* [x] Define initial interfaces in the bridge library based on the explored integration model
* [x] Build an initial Prometheus to pmetric converter
* [x] Validate the approach with reference exporters such as `stackdriver_exporter` and `yet-another-cloudwatch-exporter`
* [x] Create a dedicated `prometheus-opentelemetry-collector` distribution to continuously test dependency conflicts and generated collector compilation
* [ ] Document the integration pattern for other exporters
* [ ] Reach out to exporter maintainers and gradually adopt across other Prometheus exporters based on community interest
Loading