Skip to content

Commit d79b995

Browse files
authored
Merge pull request #7 from sunjunnan79/main
优化gin结构
2 parents a6b2df4 + da3f3c2 commit d79b995

29 files changed

Lines changed: 1165 additions & 887 deletions

File tree

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test:
2+
go test -v ./...

example/logger/logger.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ func SearchUser(id int) error {
2626
}
2727

2828
func main() {
29-
l := zapx.NewDefaultZapLogger("./logs", logger.EnvTest)
29+
l := zapx.NewDefaultZapLogger()
3030
id := 1
3131
A(id, l)
32-
l.Info("查询出错id:", logger.Int("id", id))
32+
l.Info("查询出错id:", logger.Field{"id": id})
3333
}
3434

3535
func A(id int, l logger.Logger) {
3636
err := SearchUser(id)
37-
l.Error("查询数据库出错:", logger.Error(err))
37+
l.Error("查询数据库出错:" + err.Error())
3838
}

go.mod

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ require (
2222
github.com/stretchr/testify v1.11.0
2323
github.com/uber/jaeger-client-go v2.30.0+incompatible
2424
github.com/ulule/limiter/v3 v3.11.2
25-
go.uber.org/zap v1.21.0
25+
go.uber.org/zap v1.27.0
2626
golang.org/x/sync v0.16.0
2727
google.golang.org/grpc v1.74.2
2828
google.golang.org/grpc/examples v0.0.0-20250830142414-29ba00196bb8
@@ -62,6 +62,8 @@ require (
6262
github.com/cespare/xxhash/v2 v2.3.0 // indirect
6363
github.com/clbanning/mxj/v2 v2.5.5 // indirect
6464
github.com/cloudwego/base64x v0.1.6 // indirect
65+
github.com/coreos/go-semver v0.3.1 // indirect
66+
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
6567
github.com/davecgh/go-spew v1.1.1 // indirect
6668
github.com/deckarep/golang-set v1.7.1 // indirect
6769
github.com/eapache/go-resiliency v1.7.0 // indirect
@@ -77,11 +79,13 @@ require (
7779
github.com/go-sql-driver/mysql v1.8.1 // indirect
7880
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
7981
github.com/goccy/go-json v0.10.5 // indirect
82+
github.com/gogo/protobuf v1.3.2 // indirect
8083
github.com/golang/mock v1.6.0 // indirect
8184
github.com/golang/protobuf v1.5.4 // indirect
8285
github.com/golang/snappy v0.0.4 // indirect
8386
github.com/google/uuid v1.6.0 // indirect
8487
github.com/google/wire v0.7.0 // indirect
88+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
8589
github.com/hashicorp/go-uuid v1.0.3 // indirect
8690
github.com/inconshreveable/mousetrap v1.1.0 // indirect
8791
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
@@ -122,15 +126,19 @@ require (
122126
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
123127
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
124128
github.com/ugorji/go/codec v1.3.0 // indirect
129+
go.etcd.io/etcd/api/v3 v3.6.5 // indirect
130+
go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect
131+
go.etcd.io/etcd/client/v3 v3.6.5 // indirect
125132
go.uber.org/atomic v1.9.0 // indirect
126133
go.uber.org/mock v0.6.0 // indirect
127-
go.uber.org/multierr v1.9.0 // indirect
134+
go.uber.org/multierr v1.11.0 // indirect
128135
golang.org/x/arch v0.20.0 // indirect
129136
golang.org/x/crypto v0.41.0 // indirect
130137
golang.org/x/net v0.43.0 // indirect
131138
golang.org/x/sys v0.35.0 // indirect
132139
golang.org/x/text v0.28.0 // indirect
133140
golang.org/x/time v0.12.0 // indirect
141+
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect
134142
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
135143
google.golang.org/protobuf v1.36.8 // indirect
136144
gopkg.in/ini.v1 v1.67.0 // indirect

go.sum

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
108108
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
109109
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
110110
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
111+
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
112+
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
113+
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
114+
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
111115
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
112116
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
113117
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -192,6 +196,7 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
192196
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
193197
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
194198
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
199+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
195200
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
196201
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
197202
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
@@ -240,7 +245,10 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
240245
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
241246
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
242247
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
248+
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
243249
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
250+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
251+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
244252
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
245253
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
246254
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -417,6 +425,12 @@ github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
417425
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
418426
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
419427
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
428+
go.etcd.io/etcd/api/v3 v3.6.5 h1:pMMc42276sgR1j1raO/Qv3QI9Af/AuyQUW6CBAWuntA=
429+
go.etcd.io/etcd/api/v3 v3.6.5/go.mod h1:ob0/oWA/UQQlT1BmaEkWQzI0sJ1M0Et0mMpaABxguOQ=
430+
go.etcd.io/etcd/client/pkg/v3 v3.6.5 h1:Duz9fAzIZFhYWgRjp/FgNq2gO1jId9Yae/rLn3RrBP8=
431+
go.etcd.io/etcd/client/pkg/v3 v3.6.5/go.mod h1:8Wx3eGRPiy0qOFMZT/hfvdos+DjEaPxdIDiCDUv/FQk=
432+
go.etcd.io/etcd/client/v3 v3.6.5 h1:yRwZNFBx/35VKHTcLDeO7XVLbCBFbPi+XV4OC3QJf2U=
433+
go.etcd.io/etcd/client/v3 v3.6.5/go.mod h1:ZqwG/7TAFZ0BJ0jXRPoJjKQJtbFo/9NIY8uoFFKcCyo=
420434
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
421435
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
422436
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
@@ -442,9 +456,13 @@ go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
442456
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
443457
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
444458
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
459+
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
460+
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
445461
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
446462
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
447463
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
464+
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
465+
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
448466
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
449467
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
450468
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
@@ -626,6 +644,9 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG
626644
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
627645
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
628646
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
647+
google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyTZAvMaSyAxccZZdraiSAGvqOczVvk=
648+
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
649+
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
629650
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
630651
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
631652
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

pkg/logger/logger.go

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,59 +10,4 @@ type Logger interface {
1010
Sync() error
1111
}
1212

13-
type Field struct {
14-
Key string
15-
Val any
16-
}
17-
18-
func Any(key string, val any) Field {
19-
return Field{
20-
Key: key,
21-
Val: val,
22-
}
23-
}
24-
25-
func Error(err error) Field {
26-
return Field{
27-
Key: "error",
28-
Val: err,
29-
}
30-
}
31-
32-
func Int64(key string, val int64) Field {
33-
return Field{
34-
Key: key,
35-
Val: val,
36-
}
37-
}
38-
39-
func Int(key string, val int) Field {
40-
return Field{
41-
Key: key,
42-
Val: val,
43-
}
44-
}
45-
46-
func String(key string, val string) Field {
47-
return Field{
48-
Key: key,
49-
Val: val,
50-
}
51-
}
52-
53-
func Int32(key string, val int32) Field {
54-
return Field{
55-
Key: key,
56-
Val: val,
57-
}
58-
}
59-
60-
// ---------- 环境枚举 ----------
61-
type Env int8
62-
63-
const (
64-
EnvUnknown Env = iota
65-
EnvDev // 开发:彩色多行栈,仅控制台
66-
EnvTest // 测试:彩色多行栈到控制台 + JSON 到文件
67-
EnvProd // 生产:全 JSON 单行
68-
)
13+
type Field map[string]interface{}

pkg/logger/logx/logs_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package logx
2+
3+
import (
4+
"bytes"
5+
"log"
6+
"strings"
7+
"testing"
8+
9+
"github.com/muxi-Infra/muxi-micro/pkg/logger"
10+
)
11+
12+
func TestNewStdLogger(t *testing.T) {
13+
l := NewStdLogger()
14+
if l == nil {
15+
t.Fatal("expected logger, got nil")
16+
}
17+
if l.logger == nil {
18+
t.Fatal("expected underlying log.Logger initialized")
19+
}
20+
}
21+
22+
func TestOutputLevels(t *testing.T) {
23+
l := NewStdLogger()
24+
25+
fields := logger.Field{"key": "value"}
26+
l.Info("info msg", fields)
27+
l.Debug("debug msg")
28+
l.Warn("warn msg")
29+
l.Error("error msg")
30+
31+
}
32+
33+
func TestWithFields(t *testing.T) {
34+
l := NewStdLogger()
35+
36+
// 添加初始字段
37+
l2 := l.With(logger.Field{"request_id": "1234"}).(*StdLogger)
38+
if v, ok := l2.fields["request_id"]; !ok || v != "1234" {
39+
t.Fatalf("expected field request_id=1234, got %v", l2.fields)
40+
}
41+
42+
// 再添加新字段(测试合并)
43+
l3 := l2.With(logger.Field{"user": "alice"}).(*StdLogger)
44+
if v, ok := l3.fields["user"]; !ok || v != "alice" {
45+
t.Fatalf("expected user=alice, got %v", l3.fields)
46+
}
47+
}
48+
49+
func TestOutputFieldMerging(t *testing.T) {
50+
l := NewStdLogger()
51+
buf := &bytes.Buffer{}
52+
l.logger = log.New(buf, "", 0)
53+
54+
l.fields["base"] = "yes"
55+
l.output("INFO", "test", logger.Field{"child": "ok"})
56+
57+
out := buf.String()
58+
if !strings.Contains(out, "\"base\":\"yes\"") || !strings.Contains(out, "\"child\":\"ok\"") {
59+
t.Fatalf("field merge failed: %s", out)
60+
}
61+
}
62+
63+
func TestSync(t *testing.T) {
64+
l := NewStdLogger()
65+
if err := l.Sync(); err != nil {
66+
t.Fatalf("expected nil, got %v", err)
67+
}
68+
}

pkg/logger/logx/logx.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package logx
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"github.com/muxi-Infra/muxi-micro/pkg/logger"
7+
"log"
8+
"os"
9+
"runtime"
10+
"strings"
11+
"sync"
12+
"time"
13+
)
14+
15+
type StdLogger struct {
16+
logger *log.Logger
17+
fields logger.Field
18+
mu sync.RWMutex
19+
}
20+
21+
// NewStdLogger 创建一个基于标准库 log 的 Logger 实现,非常轻量,适合简单场景/日志的兜底场景使用
22+
func NewStdLogger() *StdLogger {
23+
return &StdLogger{
24+
logger: log.New(os.Stdout, "", 0),
25+
fields: make(logger.Field),
26+
}
27+
}
28+
29+
func (l *StdLogger) Info(msg string, fields ...logger.Field) {
30+
l.output("INFO", msg, fields...)
31+
}
32+
33+
func (l *StdLogger) Debug(msg string, fields ...logger.Field) {
34+
l.output("DEBUG", msg, fields...)
35+
}
36+
37+
func (l *StdLogger) Warn(msg string, fields ...logger.Field) {
38+
l.output("WARN", msg, fields...)
39+
}
40+
41+
func (l *StdLogger) Error(msg string, fields ...logger.Field) {
42+
l.output("ERROR", msg, fields...)
43+
}
44+
45+
func (l *StdLogger) Fatal(msg string, fields ...logger.Field) {
46+
l.output("FATAL", msg, fields...)
47+
os.Exit(1)
48+
}
49+
50+
// With 创建带上下文的 logger
51+
func (l *StdLogger) With(fields ...logger.Field) logger.Logger {
52+
l.mu.RLock()
53+
base := make(logger.Field, len(l.fields))
54+
for k, v := range l.fields {
55+
base[k] = v
56+
}
57+
l.mu.RUnlock()
58+
59+
for _, f := range fields {
60+
for k, v := range f {
61+
base[k] = v
62+
}
63+
}
64+
65+
return &StdLogger{
66+
logger: l.logger,
67+
fields: base,
68+
}
69+
}
70+
71+
// Sync 在标准库中没有缓冲区,这里直接返回 nil
72+
func (l *StdLogger) Sync() error {
73+
return nil
74+
}
75+
76+
func (l *StdLogger) output(level, msg string, fields ...logger.Field) {
77+
l.mu.RLock()
78+
defer l.mu.RUnlock()
79+
80+
// 合并全局与传入字段
81+
merged := make(logger.Field)
82+
for k, v := range l.fields {
83+
merged[k] = v
84+
}
85+
for _, f := range fields {
86+
for k, v := range f {
87+
merged[k] = v
88+
}
89+
}
90+
91+
// 获取时间与调用信息
92+
now := time.Now().Format("2006-01-02T15:04:05.000-0700")
93+
_, file, line, ok := runtime.Caller(2)
94+
caller := "unknown"
95+
if ok {
96+
short := file
97+
if idx := strings.LastIndex(file, "/"); idx != -1 {
98+
short = file[idx+1:]
99+
}
100+
caller = fmt.Sprintf("%s:%d", short, line)
101+
}
102+
103+
// 构建 JSON map
104+
logMap := map[string]interface{}{
105+
"level": level,
106+
"@timestamp": now,
107+
"caller": caller,
108+
"msg": msg,
109+
}
110+
111+
// 合并自定义字段
112+
for k, v := range merged {
113+
logMap[k] = v
114+
}
115+
116+
// 序列化为 JSON
117+
jsonBytes, err := json.Marshal(logMap)
118+
if err != nil {
119+
// 兜底输出
120+
l.logger.Printf("[LOGGING_ERROR] level=%s msg=%s err=%v", level, msg, err)
121+
return
122+
}
123+
124+
// 输出单行 JSON 日志
125+
l.logger.Println(string(jsonBytes))
126+
}

0 commit comments

Comments
 (0)