Files
grpc-toolkit/otel/metrics.go
2025-06-09 10:28:42 +02:00

81 lines
2.3 KiB
Go

package otel
import (
"context"
"time"
"go.opentelemetry.io/contrib/bridges/prometheus"
runtimemetrics "go.opentelemetry.io/contrib/instrumentation/runtime"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.linka.cloud/grpc-toolkit/logger"
)
func configureMetrics(ctx context.Context, conf *config) *sdkmetric.MeterProvider {
log := logger.C(ctx)
opts := conf.metricOptions
if res := conf.newResource(ctx); res != nil {
opts = append(opts, sdkmetric.WithResource(res))
}
for _, dsn := range conf.dsn {
dsn, err := ParseDSN(dsn)
if err != nil {
log.WithError(err).Error("ParseDSN failed")
continue
}
exp, err := otlpmetricClient(ctx, conf, dsn)
if err != nil {
log.WithError(err).Warn("otlpmetricClient")
continue
}
ropts := []sdkmetric.PeriodicReaderOption{sdkmetric.WithInterval(5 * time.Second)}
if conf.metricPrometheusBridge {
ropts = append(ropts, sdkmetric.WithProducer(prometheus.NewMetricProducer()))
}
opts = append(opts, sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exp, ropts...)))
}
provider := sdkmetric.NewMeterProvider(opts...)
otel.SetMeterProvider(provider)
if err := runtimemetrics.Start(); err != nil {
log.WithError(err).Error("runtimemetrics.Start failed")
}
return provider
}
func otlpmetricClient(ctx context.Context, conf *config, dsn *DSN) (sdkmetric.Exporter, error) {
options := []otlpmetrichttp.Option{
otlpmetrichttp.WithEndpoint(dsn.OTLPHttpEndpoint()),
otlpmetrichttp.WithHeaders(dsn.Headers()),
otlpmetrichttp.WithCompression(otlpmetrichttp.GzipCompression),
otlpmetrichttp.WithTemporalitySelector(preferDeltaTemporalitySelector),
}
if conf.tlsConf != nil {
options = append(options, otlpmetrichttp.WithTLSClientConfig(conf.tlsConf))
} else if dsn.Scheme == "http" {
options = append(options, otlpmetrichttp.WithInsecure())
}
return otlpmetrichttp.New(ctx, options...)
}
func preferDeltaTemporalitySelector(kind sdkmetric.InstrumentKind) metricdata.Temporality {
switch kind {
case sdkmetric.InstrumentKindCounter,
sdkmetric.InstrumentKindObservableCounter,
sdkmetric.InstrumentKindHistogram:
return metricdata.DeltaTemporality
default:
return metricdata.CumulativeTemporality
}
}