pkg/metrics/prometheus_exporter.go (50 lines of code) (raw):
package metrics
import (
"fmt"
"net/http"
"time"
cgprometheus "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/aggregation"
"monis.app/mlog"
)
const (
metricsEndpoint = "metrics"
)
func initPrometheusExporter(metricsAddress string) error {
exporter, err := prometheus.New()
if err != nil {
return err
}
meterProvider := metric.NewMeterProvider(
metric.WithReader(exporter),
metric.WithView(
metric.NewView(
metric.Instrument{
Kind: metric.InstrumentKindHistogram,
},
metric.Stream{
Aggregation: aggregation.ExplicitBucketHistogram{
// Use custom buckets to avoid the default buckets which are too small for our use case.
// Start 100ms with last bucket being [~4m, +Inf)
Boundaries: cgprometheus.ExponentialBucketsRange(0.1, 2, 11),
},
},
),
),
)
global.SetMeterProvider(meterProvider)
http.HandleFunc(fmt.Sprintf("/%s", metricsEndpoint), promhttp.Handler().ServeHTTP)
go func() {
server := &http.Server{
Addr: fmt.Sprintf(":%s", metricsAddress),
ReadHeaderTimeout: 5 * time.Second,
}
if err := server.ListenAndServe(); err != nil {
mlog.Fatal(err, "failed to register prometheus endpoint", "metricsAddress", metricsAddress)
}
}()
mlog.Always("Prometheus metrics server running", "address", metricsAddress)
return nil
}