From 34b8cd09e6737e4023a1a1e4a7d23d6ca3ecc7b2 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 28 Apr 2026 14:02:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(logger):=20expose=20AddSource=20option;=20F?= =?UTF-8?q?romEnv=20enables=20caller=20in=20non-dev=20(spec=20=C2=A78.2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/infra/logger/logger.go | 17 +++++++++------- internal/infra/logger/logger_test.go | 30 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/internal/infra/logger/logger.go b/internal/infra/logger/logger.go index e0da03c..7fd6156 100644 --- a/internal/infra/logger/logger.go +++ b/internal/infra/logger/logger.go @@ -28,12 +28,14 @@ const ( LevelError = slog.LevelError ) -// Options 控制日志器的输出格式、最低级别与目标 Writer。 +// Options 控制日志器的输出格式、最低级别、目标 Writer 与是否记录调用位置。 // Writer 留空时默认写入 os.Stdout。 +// AddSource 为 true 时日志附带调用文件:行号;零值 false(开发环境噪声大,按需开启)。 type Options struct { - Format Format - Level Level - Writer io.Writer + Format Format + Level Level + Writer io.Writer + AddSource bool } // New 按 Options 构造一个 *slog.Logger。Format 非 FormatText 时一律使用 JSON handler。 @@ -42,7 +44,7 @@ func New(opt Options) *slog.Logger { if w == nil { w = os.Stdout } - hopts := &slog.HandlerOptions{Level: opt.Level, AddSource: false} + hopts := &slog.HandlerOptions{Level: opt.Level, AddSource: opt.AddSource} var h slog.Handler switch opt.Format { case FormatText: @@ -54,10 +56,11 @@ func New(opt Options) *slog.Logger { } // FromEnv 根据环境名返回合适默认: -// development → text + debug;其他 → json + info。 +// - development → text + debug,不含 source(开发噪声大) +// - 其他(production/staging/test)→ json + info,含 source(spec §8.2 caller 必填) func FromEnv(env string, w io.Writer) *slog.Logger { if env == "development" { return New(Options{Format: FormatText, Level: LevelDebug, Writer: w}) } - return New(Options{Format: FormatJSON, Level: LevelInfo, Writer: w}) + return New(Options{Format: FormatJSON, Level: LevelInfo, Writer: w, AddSource: true}) } diff --git a/internal/infra/logger/logger_test.go b/internal/infra/logger/logger_test.go index 8b46553..f98bb97 100644 --- a/internal/infra/logger/logger_test.go +++ b/internal/infra/logger/logger_test.go @@ -57,3 +57,33 @@ func TestFromEnv_NonDevelopmentUsesJSON(t *testing.T) { require.NoError(t, json.Unmarshal(buf.Bytes(), &got)) require.Equal(t, "prod", got["msg"]) } + +func TestNew_AddSourceTrue_IncludesSourceField(t *testing.T) { + var buf bytes.Buffer + log := New(Options{Format: FormatJSON, Level: LevelInfo, Writer: &buf, AddSource: true}) + log.Info("with source") + + var got map[string]any + require.NoError(t, json.Unmarshal(buf.Bytes(), &got)) + require.Contains(t, got, "source", "AddSource:true 时应有 source 字段") +} + +func TestNew_AddSourceFalse_OmitsSourceField(t *testing.T) { + var buf bytes.Buffer + log := New(Options{Format: FormatJSON, Level: LevelInfo, Writer: &buf, AddSource: false}) + log.Info("without source") + + var got map[string]any + require.NoError(t, json.Unmarshal(buf.Bytes(), &got)) + require.NotContains(t, got, "source") +} + +func TestFromEnv_NonDevelopmentEnablesSource(t *testing.T) { + var buf bytes.Buffer + log := FromEnv("production", &buf) + log.Info("prod log") + + var got map[string]any + require.NoError(t, json.Unmarshal(buf.Bytes(), &got)) + require.Contains(t, got, "source", "production 应自动开 AddSource (spec §8.2)") +}