> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo OTel Col Prometheus Exporter

> Guide to configure OpenTelemetry Collector, Prometheus and Jaeger with Docker Compose to push metrics to Prometheus using its remote write receiver and validate metrics in Prometheus UI

This guide shows how to push metrics from an OpenTelemetry Collector to Prometheus using Prometheus' remote write receiver. The stack uses Docker Compose to run the Collector, Prometheus, and Jaeger (for traces). You'll learn how to:

* Add Prometheus to Docker Compose and enable the remote write receiver
* Provide a Prometheus configuration suitable for receiving pushed metrics
* Configure the OpenTelemetry Collector to export metrics via `prometheusremotewrite`
* Start the stack and validate metrics in the Prometheus UI

<Callout icon="lightbulb" color="#1CB2FE">
  This demonstration uses Prometheus' remote write API so the OpenTelemetry Collector can push metrics directly into Prometheus. Use this when you want the Collector to push metrics rather than having Prometheus scrape targets.
</Callout>

## Overview

* Add a Prometheus service to your Docker Compose file and enable the remote-write HTTP receiver.
* Mount a simple `prometheus.yml` that sets global intervals (no `scrape_configs` needed if the Collector pushes metrics).
* Configure the Collector with a `prometheusremotewrite` exporter that targets Prometheus at `http://prometheus:9090/api/v1/write`.
* Start the stack and verify metrics at `http://localhost:9090`.

## 1) Add Prometheus to Docker Compose

Update `docker-compose.yml` to include Jaeger and Prometheus services, and configure Prometheus to enable the remote write receiver:

```yaml theme={null}
version: "3.8"

services:
  jaeger:
    image: jaegertracing/all-in-one:latest
    container_name: jaeger
    ports:
      - "6831:6831/udp"  # Jaeger agent - thrift compact
      - "6832:6832/udp"  # Jaeger agent - thrift binary
      - "5778:5778"      # Configs
      - "16686:16686"    # Jaeger UI (http://localhost:16686)
      - "14268:14268"    # Collector (HTTP)
      - "14250:14250"    # gRPC

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--web.enable-remote-write-receiver"
```

Ports exposed by the stack:

| Service    | Purpose / UI | Port (host:container)            |
| ---------- | ------------ | -------------------------------- |
| Jaeger     | UI / tracing | `16686:16686`                    |
| Prometheus | UI / metrics | `9090:9090`                      |
| Jaeger     | gRPC         | `14250:14250`                    |
| Jaeger     | HTTP         | `14268:14268`                    |
| Jaeger     | Agent (UDP)  | `6831:6831/udp`, `6832:6832/udp` |

Notes:

* The `--web.enable-remote-write-receiver` flag enables Prometheus to accept pushed metrics at `/api/v1/write`.
* We mount a local `prometheus.yml` to control Prometheus behavior from your project directory.

## 2) Create Prometheus configuration (prometheus.yml)

If the Collector is pushing metrics to Prometheus, you do not need `scrape_configs`. Create `prometheus.yml` beside your `docker-compose.yml`:

```yaml theme={null}
global:
  scrape_interval: 15s
  evaluation_interval: 15s

# No scrape_configs are required if the collector pushes metrics directly.
# The remote-write receiver is enabled via the Prometheus process flag:
# --web.enable-remote-write-receiver
```

Why no `remote_write` section? The `remote_write` stanza in Prometheus is for sending metrics out to remote storage. In this setup, Prometheus acts as the receiver — the HTTP endpoint `/api/v1/write` — which is enabled by the CLI flag above, not by `prometheus.yml`.

Helpful reference:

* Prometheus remote write receiver docs: [https://prometheus.io/docs/prometheus/latest/storage/#remote-endpoints-and-storage](https://prometheus.io/docs/prometheus/latest/storage/#remote-endpoints-and-storage)

## 3) Configure the OpenTelemetry Collector to export metrics via Prometheus remote\_write

Add a `prometheusremotewrite` exporter to your Collector configuration (example filename: `collector-config.yaml` or `otel-collector-config.yaml`) and include it in the metrics pipeline.

Example Collector config:

```yaml theme={null}
receivers:
  prometheus:
    # default Prometheus receiver config that scrapes instrumented targets
  otlp:
    protocols:
      grpc:
      http:

exporters:
  prometheusremotewrite:
    # Prometheus service hostname as visible from Docker Compose network
    endpoint: "http://prometheus:9090/api/v1/write"

  otlp/jaeger:
    # Forward traces to Jaeger (gRPC)
    endpoint: "jaeger:14250"
    tls:
      insecure: true

  debug:
    # Debug exporter that prints pipeline output to the Collector logs
    verbosity: detailed

processors:
  attributes:
    actions:
      - action: insert
        key: environment
        value: "dev"
  filter:
    # configure metric/log filters as needed
  batch:
    timeout: 10s

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [attributes, batch]
      exporters: [debug, otlp/jaeger]
    metrics:
      receivers: [prometheus, otlp]
      processors: [filter, batch]
      exporters: [prometheusremotewrite, debug]
    logs:
      receivers: [otlp]
      processors: [filter, batch]
      exporters: [debug]
```

Key points:

* Exporter name: `prometheusremotewrite` (this is the Collector exporter that POSTs to Prometheus' `/api/v1/write`).
* Endpoint: `http://prometheus:9090/api/v1/write`. When running under Docker Compose, the Collector can resolve the `prometheus` hostname (service name) on the default network.
* Keep a `debug` exporter if you want to inspect metrics in the Collector logs while simultaneously pushing them to Prometheus.
* The `otlp/jaeger` exporter forwards traces to Jaeger on port `14250`.

## 4) Bring up the stack

Start the services in detached mode:

```bash theme={null}
docker-compose up -d
```

Verify containers are running:

```bash theme={null}
docker-compose ps
```

Useful container logs and checks:

| Action                  | Command                                        |
| ----------------------- | ---------------------------------------------- |
| Prometheus logs         | `docker-compose logs prometheus`               |
| Collector logs          | `docker-compose logs <collector-service-name>` |
| Show running containers | `docker-compose ps`                            |

Prometheus UI: [http://localhost:9090](http://localhost:9090)\
Jaeger UI: [http://localhost:16686](http://localhost:16686)

## 5) Validate metrics in Prometheus UI

1. Open [http://localhost:9090](http://localhost:9090).
2. In the "Expression" input, search for metrics emitted by your application. Example metric names from a sample app:
   * `current_temperature_fahrenheit_degF`
   * `current_humidity_percentage`
3. Run queries to confirm metrics are visible and being updated.

<Callout icon="lightbulb" color="#1CB2FE">
  If metrics are missing, check:

  * The Collector is running and its metrics pipeline includes the `prometheusremotewrite` exporter.
  * The `endpoint` in the Collector exporter is `http://prometheus:9090/api/v1/write`.
  * Prometheus was started with `--web.enable-remote-write-receiver` and the mounted `prometheus.yml` is valid.
  * Services are on the same Docker Compose network so hostnames resolve between containers.
</Callout>

Troubleshooting tips

* Use the Collector debug exporter (configured above) to see metric payloads in logs.
* Inspect Prometheus logs for errors related to `/api/v1/write`.
* Confirm the Collector and Prometheus containers can reach each other by running a quick `curl` from within the Collector container:
  * Enter the container: `docker exec -it <collector-container> /bin/sh`
  * Test connectivity: `curl -v http://prometheus:9090/api/v1/write`
* Ensure no firewall or host port conflicts exist on `9090`.

References and further reading

* OpenTelemetry Collector: [https://opentelemetry.io/docs/collector/](https://opentelemetry.io/docs/collector/)
* Prometheus remote write docs: [https://prometheus.io/docs/prometheus/latest/storage/](https://prometheus.io/docs/prometheus/latest/storage/)
* Jaeger: [https://www.jaegertracing.io/](https://www.jaegertracing.io/)

This completes the end-to-end setup for pushing metrics from an OpenTelemetry Collector to Prometheus using Prometheus' remote write receiver.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/prep-course-opentelemetry-certified-associate-certification-otca/module/f6507634-836f-4fe9-b29d-047d84bfcce7/lesson/bd50c58e-2742-4b53-80d7-95063578edc4" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/prep-course-opentelemetry-certified-associate-certification-otca/module/f6507634-836f-4fe9-b29d-047d84bfcce7/lesson/c9d44c13-fd59-4f7b-978a-75c136505053" />
</CardGroup>
