From 20f56ae1d059f15a259b6f0bfa662bfc21648dae Mon Sep 17 00:00:00 2001 From: Qiying Wang <781345688@qq.com> Date: Wed, 20 Aug 2025 20:11:45 +0800 Subject: [PATCH] feat: support customize of log keys (#5103) --- core/logx/config.go | 21 ++++++++++++++ core/logx/logs.go | 28 ++++++++++++++++++ core/logx/logs_test.go | 65 ++++++++++++++++++++++++++++++++++++++++++ core/logx/vars.go | 27 ++++++++++++------ 4 files changed, 133 insertions(+), 8 deletions(-) diff --git a/core/logx/config.go b/core/logx/config.go index 8e6eb7f83..ffa4c3f94 100644 --- a/core/logx/config.go +++ b/core/logx/config.go @@ -44,4 +44,25 @@ type LogConf struct { Rotation string `json:",default=daily,options=[daily,size]"` // FileTimeFormat represents the time format for file name, default is `2006-01-02T15:04:05.000Z07:00`. FileTimeFormat string `json:",optional"` + // LogKey represents the log key. + LogKey logKeyConf `json:",optional"` +} + +type logKeyConf struct { + // CallerKey represents the caller key. + CallerKey string `json:",default=caller"` + // ContentKey represents the content key. + ContentKey string `json:",default=content"` + // DurationKey represents the duration key. + DurationKey string `json:",default=duration"` + // LevelKey represents the level key. + LevelKey string `json:",default=level"` + // SpanKey represents the span key. + SpanKey string `json:",default=span"` + // TimestampKey represents the timestamp key. + TimestampKey string `json:",default=@timestamp"` + // TraceKey represents the trace key. + TraceKey string `json:",default=trace"` + // TruncatedKey represents the truncated key. + TruncatedKey string `json:",default=truncated"` } diff --git a/core/logx/logs.go b/core/logx/logs.go index 404f47fab..f3c872d1d 100644 --- a/core/logx/logs.go +++ b/core/logx/logs.go @@ -277,6 +277,7 @@ func SetUp(c LogConf) (err error) { // Need to wait for the first caller to complete the execution. setupOnce.Do(func() { setupLogLevel(c) + setupLogKey(c.LogKey) if !c.Stat { DisableStat() @@ -579,3 +580,30 @@ func writeStack(msg string) { func writeStat(msg string) { getWriter().Stat(msg, mergeGlobalFields(addCaller())...) } + +func setupLogKey(c logKeyConf) { + if c.CallerKey != "" { + callerKey = c.CallerKey + } + if c.ContentKey != "" { + contentKey = c.ContentKey + } + if c.DurationKey != "" { + durationKey = c.DurationKey + } + if c.LevelKey != "" { + levelKey = c.LevelKey + } + if c.SpanKey != "" { + spanKey = c.SpanKey + } + if c.TimestampKey != "" { + timestampKey = c.TimestampKey + } + if c.TraceKey != "" { + traceKey = c.TraceKey + } + if c.TruncatedKey != "" { + truncatedKey = c.TruncatedKey + } +} diff --git a/core/logx/logs_test.go b/core/logx/logs_test.go index 1c3c00de2..59eb114f6 100644 --- a/core/logx/logs_test.go +++ b/core/logx/logs_test.go @@ -17,6 +17,8 @@ import ( "time" "github.com/stretchr/testify/assert" + "go.opentelemetry.io/otel" + sdktrace "go.opentelemetry.io/otel/sdk/trace" ) var ( @@ -1157,3 +1159,66 @@ func (s *countingStringer) String() string { atomic.AddInt32(&s.count, 1) return "countingStringer" } + +func TestLogKey(t *testing.T) { + setupOnce = sync.Once{} + MustSetup(LogConf{ + ServiceName: "any", + Mode: "console", + Encoding: "json", + TimeFormat: timeFormat, + LogKey: logKeyConf{ + CallerKey: "_caller", + ContentKey: "_content", + DurationKey: "_duration", + LevelKey: "_level", + SpanKey: "_span", + TimestampKey: "_timestamp", + TraceKey: "_trace", + TruncatedKey: "_truncated", + }, + }) + + t.Cleanup(func() { + setupLogKey(logKeyConf{ + CallerKey: defaultCallerKey, + ContentKey: defaultContentKey, + DurationKey: defaultDurationKey, + LevelKey: defaultLevelKey, + SpanKey: defaultSpanKey, + TimestampKey: defaultTimestampKey, + TraceKey: defaultTraceKey, + TruncatedKey: defaultTruncatedKey, + }) + }) + + const message = "hello there" + w := new(mockWriter) + old := writer.Swap(w) + defer writer.Store(old) + + otp := otel.GetTracerProvider() + tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample())) + otel.SetTracerProvider(tp) + defer otel.SetTracerProvider(otp) + + ctx, span := tp.Tracer("trace-id").Start(context.Background(), "span-id") + defer span.End() + + WithContext(ctx).WithDuration(time.Second).Info(message) + now := time.Now() + + var m map[string]string + if err := json.Unmarshal([]byte(w.String()), &m); err != nil { + t.Error(err) + } + assert.Equal(t, "info", m["_level"]) + assert.Equal(t, message, m["_content"]) + assert.Equal(t, "1000.0ms", m["_duration"]) + assert.Regexp(t, `logx/logs_test.go:\d+`, m["_caller"]) + assert.NotEmpty(t, m["_trace"]) + assert.NotEmpty(t, m["_span"]) + parsedTime, err := time.Parse(timeFormat, m["_timestamp"]) + assert.True(t, err == nil) + assert.Equal(t, now.Minute(), parsedTime.Minute()) +} diff --git a/core/logx/vars.go b/core/logx/vars.go index a2788d08f..62dc96177 100644 --- a/core/logx/vars.go +++ b/core/logx/vars.go @@ -53,14 +53,25 @@ const ( ) const ( - callerKey = "caller" - contentKey = "content" - durationKey = "duration" - levelKey = "level" - spanKey = "span" - timestampKey = "@timestamp" - traceKey = "trace" - truncatedKey = "truncated" + defaultCallerKey = "caller" + defaultContentKey = "content" + defaultDurationKey = "duration" + defaultLevelKey = "level" + defaultSpanKey = "span" + defaultTimestampKey = "@timestamp" + defaultTraceKey = "trace" + defaultTruncatedKey = "truncated" +) + +var ( + callerKey = defaultCallerKey + contentKey = defaultContentKey + durationKey = defaultDurationKey + levelKey = defaultLevelKey + spanKey = defaultSpanKey + timestampKey = defaultTimestampKey + traceKey = defaultTraceKey + truncatedKey = defaultTruncatedKey ) var (