Files
codevault/internal/observability/metrics/configure.go

84 lines
2.2 KiB
Go

package metrics
import (
"context"
"fmt"
"net"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/prometheus"
otelmetric "go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
"github.com/kanootoko/codevault/internal"
"github.com/kanootoko/codevault/internal/config"
"github.com/kanootoko/codevault/internal/observability"
"github.com/kanootoko/codevault/internal/utils/gshutdown"
)
// Configure starts a Prometheus server which serves metrics and finishes on context finish
func Configure(ctx context.Context, cfg config.MetricsConfig) error {
if cfg.Host == "" {
return nil
}
res, err := observability.GetOtelResource()
if err != nil {
return fmt.Errorf("cannot get OpenTelemetry resource: %w", err)
}
meterProvider, err := newMeterProvider(res)
if err != nil {
return fmt.Errorf("cannot instanciate OpenTelemetry meter provider: %w", err)
}
otel.SetMeterProvider(meterProvider)
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
server := http.Server{
Addr: fmt.Sprintf(":%d", cfg.Port),
Handler: mux,
ReadTimeout: time.Second * 20,
ReadHeaderTimeout: time.Second * 10,
WriteTimeout: time.Second * 20,
}
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
if err != nil {
return fmt.Errorf("error on creating listener for prometheus metrics: %w", err)
}
go func() { _ = server.Serve(listener) }()
_ = gshutdown.SubtaskStarted(ctx, "prometheus")
go func() {
defer func() {
_ = listener.Close()
_ = gshutdown.SubtaskFinished(ctx, "prometheus")
}()
<-ctx.Done()
_ = server.Shutdown(context.Background())
}()
return nil
}
func GetMeter() otelmetric.Meter {
mp := otel.GetMeterProvider()
return mp.Meter(internal.PackageName, otelmetric.WithInstrumentationVersion(internal.Version))
}
func newMeterProvider(res *resource.Resource) (*metric.MeterProvider, error) {
metricExporter, err := prometheus.New()
if err != nil {
return nil, err
}
meterProvider := metric.NewMeterProvider(
metric.WithResource(res),
metric.WithReader(metricExporter),
)
return meterProvider, nil
}