package observability
import (
"context"
"fmt"
"log/slog"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log/global"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
corelog "tangled.org/core/log"
"tangled.org/core/spindle/config"
)
func InitLogging(ctx context.Context, cfg config.Logging) (slog.Handler, func(context.Context) error, error) {
if cfg.Endpoint == "" {
return nil, func(context.Context) error { return nil }, nil
}
opts := []otlploghttp.Option{
otlploghttp.WithEndpoint(cfg.Endpoint),
otlploghttp.WithURLPath("/otlp/v1/logs"),
}
if cfg.Insecure {
opts = append(opts, otlploghttp.WithInsecure())
}
exporter, err := otlploghttp.New(ctx, opts...)
if err != nil {
return nil, nil, fmt.Errorf("creating OTLP log exporter: %w", err)
}
res, err := resource.Merge(
resource.Default(),
resource.NewSchemaless(attribute.String("service.name", cfg.ServiceName)),
)
if err != nil {
return nil, nil, fmt.Errorf("creating logging resource: %w", err)
}
processor := sdklog.NewBatchProcessor(exporter)
provider := sdklog.NewLoggerProvider(
sdklog.WithProcessor(processor),
sdklog.WithResource(res),
)
global.SetLoggerProvider(provider)
otelH := corelog.NewOtelHandler(provider, cfg.ServiceName)
shutdown := func(shutdownCtx context.Context) error {
if err := provider.Shutdown(shutdownCtx); err != nil {
return fmt.Errorf("shutting down logger provider: %w", err)
}
return nil
}
return otelH, shutdown, nil
}