Skip to content
Closed
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ The
[`examples` directory](https://github.com/prometheus/client_golang/tree/main/examples)
contains simple examples of instrumented code.

If you need to bridge existing `client_golang` instrumentation into an
OpenTelemetry / OTLP pipeline, see the
[`tutorials/otlp-bridge`](https://github.com/prometheus/client_golang/tree/main/tutorials/otlp-bridge)
tutorial.

## Client for the Prometheus HTTP API

[![Go Reference](https://pkg.go.dev/badge/github.com/prometheus/client_golang/api.svg)](https://pkg.go.dev/github.com/prometheus/client_golang/api)
Expand Down
90 changes: 90 additions & 0 deletions tutorials/otlp-bridge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# client_golang Tutorial: Export Prometheus instrumentation with OpenTelemetry OTLP

`client_golang` is built around the Prometheus pull model. For most long-running
services, exposing `/metrics` with `promhttp` is still the recommended setup.

If you already instrumented your code with `client_golang` but need to send
metrics into an OpenTelemetry pipeline, you can bridge a Prometheus
`Gatherer` into the OpenTelemetry SDK and export it with OTLP.

This is useful for:

- short-lived batch jobs that may exit before being scraped
- environments standardized on OTLP and the OpenTelemetry Collector
- gradual migrations where existing Prometheus instrumentation should stay
unchanged

## Example

The example below keeps existing Prometheus instrumentation, bridges a custom
registry into the OpenTelemetry SDK, and exports the resulting metrics with the
OTLP HTTP exporter.

```go
package main

import (
"context"
"log"

bridgeprometheus "go.opentelemetry.io/contrib/bridges/prometheus"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"

"github.com/prometheus/client_golang/prometheus"
)

func main() {
ctx := context.Background()

reg := prometheus.NewRegistry()
jobsProcessed := prometheus.NewCounter(prometheus.CounterOpts{
Name: "jobs_processed_total",
Help: "Total number of processed jobs.",
})
reg.MustRegister(jobsProcessed)

exporter, err := otlpmetrichttp.New(
ctx,
otlpmetrichttp.WithEndpoint("localhost:4318"),
otlpmetrichttp.WithInsecure(),
)
if err != nil {
log.Fatal(err)
}

bridge := bridgeprometheus.NewMetricProducer(
bridgeprometheus.WithGatherer(reg),
)

meterProvider := sdkmetric.NewMeterProvider(
sdkmetric.WithReader(
sdkmetric.NewPeriodicReader(exporter, sdkmetric.WithProducer(bridge)),
),
)
defer func() {
if err := meterProvider.Shutdown(ctx); err != nil {
log.Printf("shutdown metric provider: %v", err)
}
}()

jobsProcessed.Inc()
}
```

## Notes

- If your application uses the default Prometheus registry, you can omit
`bridgeprometheus.WithGatherer(reg)` and `NewMetricProducer` will read from
`prometheus.DefaultGatherer`.
- `Shutdown` flushes pending metric data. For short-lived jobs, make sure you
shut the provider down before exit.
- If you also use native OpenTelemetry metrics, attach them to the same
`MeterProvider` so both pipelines are exported together.

## Related documentation

- Prometheus bridge package:
<https://pkg.go.dev/go.opentelemetry.io/contrib/bridges/prometheus>
- OTLP metric HTTP exporter:
<https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp>
Loading