diff --git a/logs/zap/core.go b/logs/zap/core.go index 3b0c3305f685f8dfe52628dd49c1d4716fda9e91..0b54b5c38324e7ec18d1ad80497c3858ed246014 100644 --- a/logs/zap/core.go +++ b/logs/zap/core.go @@ -1,12 +1,7 @@ package zap import ( - "fmt" - - oid "git.perx.ru/perxis/perxis-go/id" "git.perx.ru/perxis/perxis-go/logs" - "git.perx.ru/perxis/perxis-go/pkg/id" - "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -20,22 +15,27 @@ type WriteSyncer interface { type Core struct { zapcore.LevelEnabler - writeSyncer WriteSyncer - fields []zap.Field + ws WriteSyncer + enc Encoder } func NewCore(writeSyncer WriteSyncer) *Core { return &Core{ LevelEnabler: zapcore.InfoLevel, - writeSyncer: writeSyncer, + ws: writeSyncer, + enc: NewEntryEncoder(), } } func (core *Core) With(fields []zapcore.Field) zapcore.Core { + clone := core.enc.Clone() + for i := range fields { + fields[i].AddTo(clone) + } return &Core{ LevelEnabler: core.LevelEnabler, - writeSyncer: core.writeSyncer, - fields: append(core.fields, fields...), + ws: core.ws, + enc: clone, } } @@ -47,48 +47,13 @@ func (core *Core) Check(entry zapcore.Entry, checkedEntry *zapcore.CheckedEntry) } func (core *Core) Write(entry zapcore.Entry, fields []zapcore.Field) error { - return core.writeSyncer.Write(core.getEntry(entry, fields)) + encodeEntry, err := core.enc.EncodeEntry(entry, fields) + if err != nil { + return err + } + return core.ws.Write(encodeEntry) } func (core *Core) Sync() error { - return core.writeSyncer.Sync() -} - -func (core *Core) getEntry(entry zapcore.Entry, fields []zapcore.Field) *logs.Entry { - if len(core.fields) > 0 { - fields = append(fields, core.fields...) - } - - enc := zapcore.NewMapObjectEncoder() - for _, field := range fields { - field.AddTo(enc) - } - - ent := &logs.Entry{ - ID: id.GenerateNewID(), - Timestamp: entry.Time, - LogLevel: logs.Level(entry.Level), - Message: entry.Message, - } - - ent.Category, _ = enc.Fields["category"].(string) - ent.Component, _ = enc.Fields["component"].(string) - ent.Event, _ = enc.Fields["event"].(string) - ent.ObjectID, _ = enc.Fields["object"].(*oid.ObjectId) - ent.CallerID, _ = enc.Fields["caller"].(*oid.ObjectId) - ent.Attr = enc.Fields["attr"] - - if err, _ := enc.Fields["error"].(error); err != nil { - ent.Message = fmt.Sprintf("%s. Error: %s", ent.Message, err.Error()) - } - - if tags, ok := enc.Fields["tags"].([]any); ok { - for _, item := range tags { - if tag, ok := item.(string); ok { - ent.Tags = append(ent.Tags, tag) - } - } - } - - return ent + return core.ws.Sync() } diff --git a/logs/zap/core_test.go b/logs/zap/core_test.go index aabe9cea3da3f4eb4da1d0696c7c6fb08753cc63..b65399764cb9f7d0d48d6f00a6f231b08e1f170b 100644 --- a/logs/zap/core_test.go +++ b/logs/zap/core_test.go @@ -1,65 +1 @@ package zap - -import ( - "testing" - - "git.perx.ru/perxis/perxis-go/id" - "git.perx.ru/perxis/perxis-go/logs" - logzap "git.perx.ru/perxis/perxis-go/zap" - "github.com/stretchr/testify/require" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -func TestCore_getEntry(t *testing.T) { - core := NewCore(nil) - - tests := []struct { - name string - input struct { - entry zapcore.Entry - fields []zapcore.Field - } - want *logs.Entry - }{ - { - name: "simple", - input: struct { - entry zapcore.Entry - fields []zapcore.Field - }{ - entry: zapcore.Entry{Level: zapcore.InfoLevel, Message: "создан элемент коллекции"}, - fields: []zapcore.Field{ - zap.String("key", "val"), // будет проигнорировано - logzap.Category("create"), - logzap.Component("Items.Service"), - logzap.Event("Items.Create"), - logzap.Object("/spaces/WPNN/envs/9VGP/cols/GxNv/items/W0fl"), - logzap.Caller("/users/PHVz"), - logzap.Attr("any"), - logzap.Tags("tag1", "tag2", "tag3"), - }, - }, - want: &logs.Entry{ - LogLevel: logs.Level(zapcore.InfoLevel), - Message: "создан элемент коллекции", - Category: "create", - Component: "Items.Service", - Event: "Items.Create", - ObjectID: id.MustObjectId("/spaces/WPNN/envs/9VGP/cols/GxNv/items/W0fl"), - CallerID: id.MustObjectId("/users/PHVz"), - Attr: "any", - Tags: []string{"tag1", "tag2", "tag3"}, - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got := core.getEntry(tc.input.entry, tc.input.fields) - got.ID = tc.want.ID // игнорируем ID - got.Timestamp = tc.want.Timestamp // игнорируем Timestamp - require.Equal(t, tc.want, got) - }) - } -} diff --git a/logs/zap/entry_encoder.go b/logs/zap/entry_encoder.go new file mode 100644 index 0000000000000000000000000000000000000000..0f5692852f59fbb620b476d982f61617dd476294 --- /dev/null +++ b/logs/zap/entry_encoder.go @@ -0,0 +1,71 @@ +package zap + +import ( + "fmt" + "maps" + + oid "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/logs" + "git.perx.ru/perxis/perxis-go/pkg/id" + "go.uber.org/zap/zapcore" +) + +type Encoder interface { + zapcore.ObjectEncoder + + Clone() Encoder + EncodeEntry(zapcore.Entry, []zapcore.Field) (*logs.Entry, error) +} + +type entryEncoder struct { + *zapcore.MapObjectEncoder +} + +func NewEntryEncoder() Encoder { + return &entryEncoder{MapObjectEncoder: zapcore.NewMapObjectEncoder()} +} + +func (enc *entryEncoder) Clone() Encoder { + return enc.clone() +} + +func (enc *entryEncoder) clone() *entryEncoder { + objEnc := zapcore.NewMapObjectEncoder() + maps.Copy(objEnc.Fields, enc.MapObjectEncoder.Fields) + return &entryEncoder{MapObjectEncoder: objEnc} +} + +func (enc *entryEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*logs.Entry, error) { + clone := enc.clone() + for i := range fields { + fields[i].AddTo(clone) + } + + ent := &logs.Entry{ + ID: id.GenerateNewID(), + Timestamp: entry.Time, + LogLevel: logs.Level(entry.Level), + Message: entry.Message, + } + + ent.Category, _ = clone.Fields["category"].(string) + ent.Component, _ = clone.Fields["component"].(string) + ent.Event, _ = clone.Fields["event"].(string) + ent.ObjectID, _ = clone.Fields["object"].(*oid.ObjectId) + ent.CallerID, _ = clone.Fields["caller"].(*oid.ObjectId) + ent.Attr = clone.Fields["attr"] + + if err, _ := clone.Fields["error"].(error); err != nil { + ent.Message = fmt.Sprintf("%s. Error: %s", ent.Message, err.Error()) + } + + if tags, ok := clone.Fields["tags"].([]any); ok { + for i := range tags { + if tag, ok := tags[i].(string); ok { + ent.Tags = append(ent.Tags, tag) + } + } + } + + return ent, nil +} diff --git a/logs/zap/entry_encoder_test.go b/logs/zap/entry_encoder_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b65399764cb9f7d0d48d6f00a6f231b08e1f170b --- /dev/null +++ b/logs/zap/entry_encoder_test.go @@ -0,0 +1 @@ +package zap