diff --git a/core_coverage_test.go b/core_coverage_test.go index b4f1436..2394b8a 100644 --- a/core_coverage_test.go +++ b/core_coverage_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "net/http" "net/http/httptest" @@ -14,6 +15,7 @@ import ( "time" "github.com/go-coldbrew/core/config" + "github.com/go-coldbrew/log" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" @@ -1306,10 +1308,49 @@ func TestVTProtoCodec_Name(t *testing.T) { // --- Group 8: Standalone Initializer Tests --- func TestSetupLogger_ValidLevel(t *testing.T) { + prevSlog := slog.Default() + prevHandler := log.GetHandler() + t.Cleanup(func() { + log.SetDefault(prevHandler) + slog.SetDefault(prevSlog) + }) + err := SetupLogger("info", false) if err != nil { t.Fatalf("SetupLogger with valid level failed: %v", err) } + + // Verify slog.Default is wired through ColdBrew's Handler so native + // slog calls get context fields injected. + handler := slog.Default().Handler() + if _, ok := handler.(*log.Handler); !ok { + t.Errorf("expected slog.Default handler to be *log.Handler, got %T", handler) + } +} + +func TestSetupLogger_RespectsExistingHandler(t *testing.T) { + prevSlog := slog.Default() + prevHandler := log.GetHandler() + t.Cleanup(func() { + log.SetDefault(prevHandler) + slog.SetDefault(prevSlog) + }) + + // User sets a custom handler before core runs. + customInner := slog.NewJSONHandler(io.Discard, nil) + customHandler := log.NewHandlerWithInner(customInner) + log.SetDefault(customHandler) + + // SetupLogger should respect it and only update the level. + err := SetupLogger("debug", true) + if err != nil { + t.Fatalf("SetupLogger failed: %v", err) + } + + // The handler should still be our custom one, not a new default. + if log.GetHandler() != customHandler { + t.Error("expected SetupLogger to preserve the custom handler") + } } func TestSetupLogger_InvalidLevel(t *testing.T) { diff --git a/go.mod b/go.mod index 0556f72..f02e69f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-coldbrew/errors v0.2.14 github.com/go-coldbrew/hystrixprometheus v0.1.2 github.com/go-coldbrew/interceptors v0.1.24 - github.com/go-coldbrew/log v0.3.2 + github.com/go-coldbrew/log v0.4.1 github.com/go-coldbrew/options v0.3.0 github.com/go-coldbrew/tracing v0.2.2 github.com/golang/protobuf v1.5.4 diff --git a/go.sum b/go.sum index 36e50ae..b1556eb 100644 --- a/go.sum +++ b/go.sum @@ -199,8 +199,8 @@ github.com/go-coldbrew/hystrixprometheus v0.1.2 h1:WSt4FtYr8xNDKgdGWYpMfXGFIK7zd github.com/go-coldbrew/hystrixprometheus v0.1.2/go.mod h1:OrNRHHxZagpmQXNp//oHKOemGSU0ScOqEcJgeKbJ+wg= github.com/go-coldbrew/interceptors v0.1.24 h1:z24O4TRxT/+fHTJIILml9ulmK2cYGKKCENpxxL8pGaA= github.com/go-coldbrew/interceptors v0.1.24/go.mod h1:YkAmxYZ7R3Sjif0WpzhuhGjv2j67CwUoqnq9K8XgpBY= -github.com/go-coldbrew/log v0.3.2 h1:CoHa0PGX7a7o/Cv/ke7PdQfq4LKtbPVypUf3uXcRLMs= -github.com/go-coldbrew/log v0.3.2/go.mod h1:tumRNCmLWRep5wnhS/vzDQ7UMinF6OZ7WW8K/qlXAzc= +github.com/go-coldbrew/log v0.4.1 h1:ZvTU7YXBFfe9QD9diY8lVD/WhkvpyoyixpFJAMq4+Ps= +github.com/go-coldbrew/log v0.4.1/go.mod h1:HqGpOhI4nCnl8OjM3awye4joR7m2tducjQBltMb0QiY= github.com/go-coldbrew/options v0.3.0 h1:JwyVntb9bzBeFdaHFK6yGVVz30G3aVlqJJ6uVyYQfCc= github.com/go-coldbrew/options v0.3.0/go.mod h1:8JlmgVJXFoY1KiDLsyMmR//q1U1aBItCexvTrVT2Y60= github.com/go-coldbrew/tracing v0.2.2 h1:pvRMSwla5txZgtQOi18OqsuJhtsqPbfeC1arH9tJMys= @@ -219,10 +219,6 @@ github.com/go-git/go-git/v5 v5.17.1 h1:WnljyxIzSj9BRRUlnmAU35ohDsjRK0EKmL0evDqi5 github.com/go-git/go-git/v5 v5.17.1/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE= -github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/initializers.go b/initializers.go index 0806621..48b19a1 100644 --- a/initializers.go +++ b/initializers.go @@ -18,7 +18,6 @@ import ( "github.com/go-coldbrew/interceptors" "github.com/go-coldbrew/log" "github.com/go-coldbrew/log/loggers" - cbslog "github.com/go-coldbrew/log/loggers/slog" nrutil "github.com/go-coldbrew/tracing/newrelic" protov1 "github.com/golang/protobuf/proto" //nolint:staticcheck newrelic "github.com/newrelic/go-agent/v3/newrelic" @@ -67,19 +66,23 @@ func SetupNewRelic(serviceName, apiKey string, tracing bool) error { return nil } -// SetupLogger sets up the logger -// It uses the coldbrew logger to log messages to stdout +// SetupLogger sets up the logger using ColdBrew's slog-native Handler. +// It calls log.SetDefault which also wires slog.SetDefault, so native +// slog.LogAttrs calls automatically get ColdBrew context fields. // logLevel is the log level to set for the logger // jsonlogs is a boolean to enable or disable json logs func SetupLogger(logLevel string, jsonlogs bool) error { - log.SetLogger(log.NewLogger(cbslog.NewLogger(loggers.WithJSONLogs(jsonlogs)))) - ll, err := loggers.ParseLevel(logLevel) if err != nil { - log.Error(context.Background(), "err", "could not set log level", "level", logLevel) + log.Error(context.Background(), "msg", "could not set log level", "level", logLevel, "err", err) return err } - log.SetLevel(ll) + if log.DefaultIsSet() { + // User already configured a custom handler via log.SetDefault — respect it. + log.SetLevel(ll) + return nil + } + log.SetDefault(log.NewHandler(loggers.WithJSONLogs(jsonlogs), loggers.WithLevel(ll))) return nil }