Files
spend-sparrow/internal/otel.go
Tim Wundenberg 661a3ba79f
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 4m29s
fix(observabillity): include otel logs
2025-06-07 15:20:16 +02:00

127 lines
3.3 KiB
Go

package internal
import (
"context"
"errors"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/trace"
)
var (
otelEndpoint = "192.168.188.155:4317"
)
// setupOTelSDK bootstraps the OpenTelemetry pipeline.
// If it does not return an error, make sure to call shutdown for proper cleanup.
func setupOTelSDK(ctx context.Context) (func(context.Context) error, error) {
var shutdownFuncs []func(context.Context) error
// shutdown calls cleanup functions registered via shutdownFuncs.
// The errors from the calls are joined.
// Each registered cleanup will be invoked once.
shutdown := func(ctxInternal context.Context) error {
var err error
for _, fn := range shutdownFuncs {
err = errors.Join(err, fn(ctxInternal))
}
shutdownFuncs = nil
return err
}
var err error
// handleErr calls shutdown for cleanup and makes sure that all errors are returned.
handleErr := func(ctxInternal context.Context, inErr error) {
err = errors.Join(inErr, shutdown(ctxInternal))
}
// Set up propagator.
prop := newPropagator()
otel.SetTextMapPropagator(prop)
// Set up trace provider.
tracerProvider, err := newTracerProvider(ctx)
if err != nil {
handleErr(ctx, err)
return nil, err
}
shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown)
otel.SetTracerProvider(tracerProvider)
// Set up meter provider.
meterProvider, err := newMeterProvider(ctx)
if err != nil {
handleErr(ctx, err)
return nil, err
}
shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown)
otel.SetMeterProvider(meterProvider)
// Set up logger provider.
loggerProvider, err := newLoggerProvider(ctx)
if err != nil {
handleErr(ctx, err)
return nil, err
}
shutdownFuncs = append(shutdownFuncs, loggerProvider.Shutdown)
global.SetLoggerProvider(loggerProvider)
return shutdown, nil
}
func newPropagator() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
)
}
func newTracerProvider(ctx context.Context) (*trace.TracerProvider, error) {
exp, err := otlptracegrpc.New(ctx,
otlptracegrpc.WithEndpoint(otelEndpoint),
otlptracegrpc.WithInsecure(),
)
if err != nil {
return nil, err
}
return trace.NewTracerProvider(trace.WithBatcher(exp)), nil
}
func newMeterProvider(ctx context.Context) (*metric.MeterProvider, error) {
exp, err := otlpmetricgrpc.New(ctx,
otlpmetricgrpc.WithInsecure(),
otlpmetricgrpc.WithEndpoint(otelEndpoint))
if err != nil {
return nil, err
}
return metric.NewMeterProvider(
metric.WithReader(
metric.NewPeriodicReader(
exp, metric.WithInterval(15*time.Second)))), nil
}
func newLoggerProvider(ctx context.Context) (*log.LoggerProvider, error) {
logExporter, err := otlploggrpc.New(
ctx,
otlploggrpc.WithInsecure(),
otlploggrpc.WithEndpoint(otelEndpoint))
if err != nil {
return nil, err
}
loggerProvider := log.NewLoggerProvider(
log.WithProcessor(log.NewBatchProcessor(logExporter)),
)
return loggerProvider, nil
}