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 }