Telemetry system
This commit is contained in:
101
internal/telemetry/telemetry.go
Normal file
101
internal/telemetry/telemetry.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/contrib/bridges/otelslog"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/log/global"
|
||||
sdklog "go.opentelemetry.io/otel/sdk/log"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/sdk/trace"
|
||||
)
|
||||
|
||||
func newResource(serviceName string) *resource.Resource {
|
||||
return resource.NewWithAttributes(
|
||||
resource.Default().SchemaURL(),
|
||||
attribute.String("service.name", serviceName),
|
||||
)
|
||||
}
|
||||
|
||||
// Init sets up OpenTelemetry tracing, metrics, and logs via OTLP Push.
|
||||
// It returns a shutdown function that should be deferred in main.
|
||||
func Init(ctx context.Context, endpoint string, serviceName string) (func(context.Context) error, error) {
|
||||
res := newResource(serviceName)
|
||||
|
||||
var shutdownFuncs []func(context.Context) error
|
||||
shutdown := func(ctx context.Context) error {
|
||||
var err error
|
||||
for _, fn := range shutdownFuncs {
|
||||
if fnErr := fn(ctx); fnErr != nil {
|
||||
err = errors.Join(err, fnErr)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var traceOpts []otlptracehttp.Option
|
||||
var metricOpts []otlpmetrichttp.Option
|
||||
var logOpts []otlploghttp.Option
|
||||
|
||||
if endpoint != "" {
|
||||
endpoint = strings.TrimSuffix(endpoint, "/")
|
||||
traceOpts = append(traceOpts, otlptracehttp.WithEndpointURL(endpoint+"/v1/traces"))
|
||||
metricOpts = append(metricOpts, otlpmetrichttp.WithEndpointURL(endpoint+"/v1/metrics"))
|
||||
logOpts = append(logOpts, otlploghttp.WithEndpointURL(endpoint+"/v1/logs"))
|
||||
} else {
|
||||
// Default to insecure localhost if no endpoint is specified
|
||||
traceOpts = append(traceOpts, otlptracehttp.WithInsecure())
|
||||
metricOpts = append(metricOpts, otlpmetrichttp.WithInsecure())
|
||||
logOpts = append(logOpts, otlploghttp.WithInsecure())
|
||||
}
|
||||
|
||||
// Trace setup
|
||||
traceExporter, err := otlptracehttp.New(ctx, traceOpts...)
|
||||
if err != nil {
|
||||
return shutdown, err
|
||||
}
|
||||
tp := trace.NewTracerProvider(
|
||||
trace.WithBatcher(traceExporter),
|
||||
trace.WithResource(res),
|
||||
)
|
||||
otel.SetTracerProvider(tp)
|
||||
shutdownFuncs = append(shutdownFuncs, tp.Shutdown)
|
||||
|
||||
// Metrics setup
|
||||
metricExporter, err := otlpmetrichttp.New(ctx, metricOpts...)
|
||||
if err != nil {
|
||||
return shutdown, err
|
||||
}
|
||||
mp := metric.NewMeterProvider(
|
||||
metric.WithReader(metric.NewPeriodicReader(metricExporter)),
|
||||
metric.WithResource(res),
|
||||
)
|
||||
otel.SetMeterProvider(mp)
|
||||
shutdownFuncs = append(shutdownFuncs, mp.Shutdown)
|
||||
|
||||
// Logs setup
|
||||
logExporter, err := otlploghttp.New(ctx, logOpts...)
|
||||
if err != nil {
|
||||
return shutdown, err
|
||||
}
|
||||
lp := sdklog.NewLoggerProvider(
|
||||
sdklog.WithProcessor(sdklog.NewBatchProcessor(logExporter)),
|
||||
sdklog.WithResource(res),
|
||||
)
|
||||
global.SetLoggerProvider(lp)
|
||||
shutdownFuncs = append(shutdownFuncs, lp.Shutdown)
|
||||
|
||||
// Route slog to OpenTelemetry
|
||||
slog.SetDefault(otelslog.NewLogger(serviceName))
|
||||
|
||||
return shutdown, nil
|
||||
}
|
||||
Reference in New Issue
Block a user