Skip to content
Snippets Groups Projects
Commit 9641467f authored by Semyon Krestyaninov's avatar Semyon Krestyaninov
Browse files

refactor

parent eb7ed507
No related branches found
No related tags found
No related merge requests found
......@@ -28,14 +28,10 @@ func NewCore(writeSyncer WriteSyncer) *Core {
}
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,
ws: core.ws,
enc: clone,
enc: core.enc.With(fields),
}
}
......@@ -47,11 +43,11 @@ func (core *Core) Check(entry zapcore.Entry, checkedEntry *zapcore.CheckedEntry)
}
func (core *Core) Write(entry zapcore.Entry, fields []zapcore.Field) error {
encodeEntry, err := core.enc.EncodeEntry(entry, fields)
encodedEntry, err := core.enc.EncodeEntry(entry, fields)
if err != nil {
return err
}
return core.ws.Write(encodeEntry)
return core.ws.Write(encodedEntry)
}
func (core *Core) Sync() error {
......
......@@ -2,45 +2,37 @@ package zap
import (
"fmt"
"maps"
"slices"
oid "git.perx.ru/perxis/perxis-go/id"
"git.perx.ru/perxis/perxis-go/logs"
"git.perx.ru/perxis/perxis-go/pkg/id"
"git.perx.ru/perxis/perxis-go/zap"
"go.uber.org/zap/zapcore"
)
type Encoder interface {
zapcore.ObjectEncoder
Clone() Encoder
With([]zapcore.Field) Encoder
EncodeEntry(zapcore.Entry, []zapcore.Field) (*logs.Entry, error)
}
type entryEncoder struct {
*zapcore.MapObjectEncoder
fields []zapcore.Field
}
func NewEntryEncoder() Encoder {
return &entryEncoder{MapObjectEncoder: zapcore.NewMapObjectEncoder()}
return &entryEncoder{}
}
func (enc *entryEncoder) Clone() Encoder {
return enc.clone()
func (enc *entryEncoder) With(fields []zapcore.Field) Encoder {
return enc.with(fields)
}
func (enc *entryEncoder) clone() *entryEncoder {
objEnc := zapcore.NewMapObjectEncoder()
maps.Copy(objEnc.Fields, enc.MapObjectEncoder.Fields)
return &entryEncoder{MapObjectEncoder: objEnc}
func (enc *entryEncoder) with(fields []zapcore.Field) *entryEncoder {
return &entryEncoder{fields: slices.Concat(enc.fields, fields)}
}
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,
......@@ -48,22 +40,31 @@ func (enc *entryEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field
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"]
clone := enc.with(fields)
if err, _ := clone.Fields["error"].(error); err != nil {
for i := range clone.fields {
switch clone.fields[i].Key {
// При добавлении новых полей стоит учитывать, как zap хранит значения в структуре Field.
// Например:
// zap.Bool хранит bool как 1/0 в поле Field.Integer
case "category":
ent.Category = clone.fields[i].String
case "component":
ent.Component = clone.fields[i].String
case "event":
ent.Event = clone.fields[i].String
case "object":
ent.ObjectID, _ = clone.fields[i].Interface.(*oid.ObjectId)
case "caller":
ent.CallerID, _ = clone.fields[i].Interface.(*oid.ObjectId)
case "attr":
ent.Attr = clone.fields[i].Interface
case "error":
if err, _ := clone.fields[i].Interface.(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)
}
case "tags":
ent.Tags, _ = clone.fields[i].Interface.(zap.StringArray)
}
}
......
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 EncoderSlow interface {
zapcore.ObjectEncoder
Clone() EncoderSlow
EncodeEntry(zapcore.Entry, []zapcore.Field) (*logs.Entry, error)
}
type entryEncoderSlow struct {
*zapcore.MapObjectEncoder
}
func NewEntryEncoderSlow() EncoderSlow {
return &entryEncoderSlow{MapObjectEncoder: zapcore.NewMapObjectEncoder()}
}
func (enc *entryEncoderSlow) Clone() EncoderSlow {
return enc.clone()
}
func (enc *entryEncoderSlow) clone() *entryEncoderSlow {
objEnc := zapcore.NewMapObjectEncoder()
maps.Copy(objEnc.Fields, enc.MapObjectEncoder.Fields)
return &entryEncoderSlow{MapObjectEncoder: objEnc}
}
func (enc *entryEncoderSlow) 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
}
......@@ -4,12 +4,68 @@ import (
"fmt"
"testing"
"git.perx.ru/perxis/perxis-go/id"
"git.perx.ru/perxis/perxis-go/logs"
"git.perx.ru/perxis/perxis-go/pkg/items"
logzap "git.perx.ru/perxis/perxis-go/zap"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func TestEntryEncoder_EncodeEntry(t *testing.T) {
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"},
},
},
}
enc := NewEntryEncoder()
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got, _ := enc.EncodeEntry(tc.input.entry, tc.input.fields)
got.ID = tc.want.ID // игнорируем ID
got.Timestamp = tc.want.Timestamp // игнорируем Timestamp
require.Equal(t, tc.want, got)
})
}
}
func BenchmarkEntryEncoderSimple(b *testing.B) {
fields := []zapcore.Field{
logzap.Event(items.EventCreateItem),
......@@ -18,7 +74,7 @@ func BenchmarkEntryEncoderSimple(b *testing.B) {
logzap.Tags("tag1", "tag2", "tag3"),
}
enc := NewEntryEncoder()
enc := NewEntryEncoderSlow()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
......@@ -36,7 +92,7 @@ func BenchmarkEntryEncoderUnknownFields(b *testing.B) {
fields = append(fields, zap.String(fmt.Sprintf("Key: %d", i), fmt.Sprintf("Value: %d", i)))
}
enc := NewEntryEncoder()
enc := NewEntryEncoderSlow()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
......@@ -50,7 +106,7 @@ func BenchmarkEntryEncoderV2Simple(b *testing.B) {
logzap.Tags("tag1", "tag2", "tag3"),
}
enc := NewEntryEncoderV2()
enc := NewEntryEncoder()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
......@@ -68,7 +124,7 @@ func BenchmarkEntryEncoderV2UnknownFields(b *testing.B) {
fields = append(fields, zap.String(fmt.Sprintf("Key: %d", i), fmt.Sprintf("Value: %d", i)))
}
enc := NewEntryEncoderV2()
enc := NewEntryEncoder()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
......
package zap
import (
"fmt"
"slices"
oid "git.perx.ru/perxis/perxis-go/id"
"git.perx.ru/perxis/perxis-go/logs"
"git.perx.ru/perxis/perxis-go/pkg/id"
"git.perx.ru/perxis/perxis-go/zap"
"go.uber.org/zap/zapcore"
)
type EncoderV2 interface {
With([]zapcore.Field) EncoderV2
EncodeEntry(zapcore.Entry, []zapcore.Field) (*logs.Entry, error)
}
type entryEncoderV2 struct {
fields []zapcore.Field
}
func NewEntryEncoderV2() EncoderV2 {
return &entryEncoderV2{}
}
func (enc *entryEncoderV2) With(fields []zapcore.Field) EncoderV2 {
return enc.with(fields)
}
func (enc *entryEncoderV2) with(fields []zapcore.Field) *entryEncoderV2 {
return &entryEncoderV2{fields: slices.Concat(enc.fields, fields)}
}
func (enc *entryEncoderV2) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*logs.Entry, error) {
ent := &logs.Entry{
ID: id.GenerateNewID(),
Timestamp: entry.Time,
LogLevel: logs.Level(entry.Level),
Message: entry.Message,
}
clone := enc.with(fields)
for i := range clone.fields {
switch clone.fields[i].Key {
case "category":
ent.Category = clone.fields[i].String
case "component":
ent.Component = clone.fields[i].String
case "event":
ent.Event = clone.fields[i].String
case "object":
ent.ObjectID, _ = clone.fields[i].Interface.(*oid.ObjectId)
case "caller":
ent.CallerID, _ = clone.fields[i].Interface.(*oid.ObjectId)
case "attr":
ent.Attr = clone.fields[i].Interface
case "error":
if err, _ := clone.fields[i].Interface.(error); err != nil {
ent.Message = fmt.Sprintf("%s. Error: %s", ent.Message, err.Error())
}
case "tags":
ent.Tags, _ = clone.fields[i].Interface.(zap.StringArray)
}
}
return ent, nil
}
......@@ -60,7 +60,7 @@ func CallerFromContext(ctx context.Context) zap.Field {
}
func Attr(attr any) zap.Field {
return zap.Any("attr", attr)
return zap.Reflect("attr", attr)
}
func Tags(tags ...string) zap.Field {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment