Skip to content
Snippets Groups Projects
Commit a3d59b8d authored by ko_oler's avatar ko_oler
Browse files

Merge branch 'master' into feature/PRXS-951-2057-EventsName

# Conflicts:
#	logs/zap/example_test.go
#	pkg/items/middleware/logging_middleware.go
parents d7627a44 57c00ab4
No related branches found
No related tags found
No related merge requests found
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,25 @@ 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 {
enc := core.enc.Clone()
enc.AddFields(fields)
return &Core{
LevelEnabler: core.LevelEnabler,
writeSyncer: core.writeSyncer,
fields: append(core.fields, fields...),
ws: core.ws,
enc: enc,
}
}
......@@ -47,48 +45,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))
encodedEntry, err := core.enc.EncodeEntry(entry, fields)
if err != nil {
return err
}
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,
Level: logs.Level(entry.Level),
Message: entry.Message,
return core.ws.Write(encodedEntry)
}
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
func (core *Core) Sync() error {
return core.ws.Sync()
}
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 Encoder interface {
Clone() Encoder
AddFields([]zapcore.Field)
EncodeEntry(zapcore.Entry, []zapcore.Field) (*logs.Entry, error)
}
type entryEncoder struct {
fields []zapcore.Field
}
func NewEntryEncoder() Encoder {
return &entryEncoder{}
}
func (enc *entryEncoder) AddFields(fields []zapcore.Field) {
enc.fields = slices.Concat(enc.fields, fields)
}
func (enc *entryEncoder) Clone() Encoder {
return enc.clone()
}
func (enc *entryEncoder) clone() *entryEncoder {
return &entryEncoder{fields: slices.Clone(enc.fields)}
}
func (enc *entryEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*logs.Entry, error) {
ent := &logs.Entry{
ID: id.GenerateNewID(),
Timestamp: entry.Time,
Level: logs.Level(entry.Level),
Message: entry.Message,
}
clone := enc.clone()
clone.AddFields(fields)
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())
}
case "tags":
ent.Tags, _ = clone.fields[i].Interface.(zap.StringArray)
}
}
return ent, nil
}
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,
Level: 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
}
package zap
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 TestCore_getEntry(t *testing.T) {
core := NewCore(nil)
func TestEntryEncoder_EncodeEntry(t *testing.T) {
tests := []struct {
name string
input struct {
......@@ -54,12 +54,78 @@ func TestCore_getEntry(t *testing.T) {
},
}
enc := NewEntryEncoder()
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := core.getEntry(tc.input.entry, tc.input.fields)
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),
logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)),
logzap.Caller("/system"),
logzap.Tags("tag1", "tag2", "tag3"),
}
enc := NewEntryEncoderSlow()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
}
func BenchmarkEntryEncoderUnknownFields(b *testing.B) {
fields := []zapcore.Field{
logzap.Event(items.EventCreateItem),
logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)),
logzap.Caller("/system"),
logzap.Tags("tag1", "tag2", "tag3"),
}
for i := 0; i < 1000; i++ {
fields = append(fields, zap.String(fmt.Sprintf("Key: %d", i), fmt.Sprintf("Value: %d", i)))
}
enc := NewEntryEncoderSlow()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
}
func BenchmarkEntryEncoderV2Simple(b *testing.B) {
fields := []zapcore.Field{
logzap.Event(items.EventCreateItem),
logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)),
logzap.Caller("/system"),
logzap.Tags("tag1", "tag2", "tag3"),
}
enc := NewEntryEncoder()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
}
func BenchmarkEntryEncoderV2UnknownFields(b *testing.B) {
fields := []zapcore.Field{
logzap.Event(items.EventCreateItem),
logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)),
logzap.Caller("/system"),
logzap.Tags("tag1", "tag2", "tag3"),
}
for i := 0; i < 1000; i++ {
fields = append(fields, zap.String(fmt.Sprintf("Key: %d", i), fmt.Sprintf("Value: %d", i)))
}
enc := NewEntryEncoder()
for i := 0; i < b.N; i++ {
_, _ = enc.EncodeEntry(zapcore.Entry{Message: fmt.Sprintf("Msg: %d", i)}, fields)
}
}
......@@ -27,7 +27,7 @@ func TestExample(t *testing.T) {
wantEntries := []*logs.Entry{
{
Level: logs.Level(zapcore.InfoLevel),
Message: "Successfully created",
Message: "Item created",
Component: "Items",
Event: items.EventItemCreate,
ObjectID: id.MustObjectId(item),
......@@ -36,7 +36,7 @@ func TestExample(t *testing.T) {
},
{
Level: logs.Level(zapcore.WarnLevel),
Message: "Successfully updated",
Message: "Item updated",
Component: "Items",
Event: items.EventItemUpdate,
ObjectID: id.MustObjectId(item),
......@@ -74,18 +74,18 @@ func TestExample(t *testing.T) {
ctx := auth.WithPrincipal(context.Background(), factory.User("74d90aaf"))
// Отправка лога при создании item
logger.Info("Successfully created",
logger.Info("Item created",
logzap.Event(items.EventItemCreate),
logzap.Object(item),
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, item.SpaceID),
logzap.Tags("tag1", "tag2", "tag3"),
)
// Отправка лога при обновлении item
logger.Warn("Successfully updated",
logger.Warn("Item updated",
logzap.Event(items.EventItemUpdate),
logzap.Object(item),
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, item.SpaceID),
logzap.Attr(map[string]map[string]any{"title": {"old": "old title", "new": "new title"}}),
)
}
......
......@@ -25,8 +25,12 @@ func LoggingMiddleware(logger *zap.Logger) Middleware {
}
func (m *loggingMiddleware) Create(ctx context.Context, collection *collections.Collection) (created *collections.Collection, err error) {
var spaceID string
if collection != nil {
spaceID = collection.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(collections.EventCollectionCreate),
)
......@@ -36,13 +40,13 @@ func (m *loggingMiddleware) Create(ctx context.Context, collection *collections.
return
}
logger.Info("Successfully created", logzap.Object(created), logzap.Channels(logzap.Userlog))
logger.Info("Collection created", logzap.Object(created), logzap.Channels(logzap.Userlog))
return created, err
}
func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string, envId string, collectionId string) (err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Event(collections.EventCollectionDelete),
logzap.Object(id.NewCollectionId(spaceId, envId, collectionId)),
)
......@@ -53,13 +57,13 @@ func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string, envId st
return
}
logger.Info("Successfully deleted", logzap.Channels(logzap.Userlog))
logger.Info("Collection deleted", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, options ...*collections.GetOptions) (collection *collections.Collection, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
collection, err = m.next.Get(ctx, spaceId, envId, collectionId, options...)
......@@ -73,7 +77,7 @@ func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId strin
func (m *loggingMiddleware) List(ctx context.Context, spaceId string, envId string, filter *collections.Filter) (collections []*collections.Collection, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
collections, err = m.next.List(ctx, spaceId, envId, filter)
......@@ -87,7 +91,7 @@ func (m *loggingMiddleware) List(ctx context.Context, spaceId string, envId stri
func (m *loggingMiddleware) SetSchema(ctx context.Context, spaceId string, envId string, collectionId string, schema *schema.Schema) (err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Event(collections.EventCollectionSetSchema),
logzap.Object(id.NewCollectionId(spaceId, envId, collectionId)),
)
......@@ -98,13 +102,13 @@ func (m *loggingMiddleware) SetSchema(ctx context.Context, spaceId string, envId
return
}
logger.Info("Successfully set schema", logzap.Channels(logzap.Userlog))
logger.Info("Set collection's schema", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) SetState(ctx context.Context, spaceId string, envId string, collectionId string, state *collections.StateInfo) (err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
err = m.next.SetState(ctx, spaceId, envId, collectionId, state)
......@@ -113,13 +117,17 @@ func (m *loggingMiddleware) SetState(ctx context.Context, spaceId string, envId
return
}
logger.Info("Successfully set state", logzap.Channels(logzap.Userlog))
logger.Info("Set collection's state", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Update(ctx context.Context, coll *collections.Collection) (err error) {
var spaceID string
if coll != nil {
spaceID = coll.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(collections.EventCollectionUpdate),
logzap.Object(coll),
)
......@@ -130,6 +138,6 @@ func (m *loggingMiddleware) Update(ctx context.Context, coll *collections.Collec
return
}
logger.Info("Successfully updated", logzap.Channels(logzap.Userlog))
logger.Info("Collection updated", logzap.Channels(logzap.Userlog))
return err
}
......@@ -26,7 +26,7 @@ func LoggingMiddleware(logger *zap.Logger) Middleware {
func (m *loggingMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregateOptions) (result map[string]interface{}, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
result, err = m.next.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
......@@ -40,7 +40,7 @@ func (m *loggingMiddleware) Aggregate(ctx context.Context, spaceId string, envId
func (m *loggingMiddleware) AggregatePublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
result, err = m.next.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...)
......@@ -53,8 +53,12 @@ func (m *loggingMiddleware) AggregatePublished(ctx context.Context, spaceId stri
}
func (m *loggingMiddleware) Archive(ctx context.Context, item *items.Item, options ...*items.ArchiveOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemArchive),
logzap.Object(item),
)
......@@ -65,13 +69,17 @@ func (m *loggingMiddleware) Archive(ctx context.Context, item *items.Item, optio
return
}
logger.Info("Successfully archived", logzap.Channels(logzap.Userlog))
logger.Info("Item archived", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Create(ctx context.Context, item *items.Item, opts ...*items.CreateOptions) (created *items.Item, err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemCreate),
)
......@@ -81,13 +89,17 @@ func (m *loggingMiddleware) Create(ctx context.Context, item *items.Item, opts .
return
}
logger.Info("Successfully created", logzap.Channels(logzap.Userlog), logzap.Object(created))
logger.Info("Item created", logzap.Channels(logzap.Userlog), logzap.Object(created))
return created, err
}
func (m *loggingMiddleware) Delete(ctx context.Context, item *items.Item, options ...*items.DeleteOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemDelete),
logzap.Object(item),
)
......@@ -98,13 +110,13 @@ func (m *loggingMiddleware) Delete(ctx context.Context, item *items.Item, option
return
}
logger.Info("Successfully deleted", logzap.Channels(logzap.Userlog))
logger.Info("Item deleted", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Find(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindOptions) (items []*items.Item, total int, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
items, total, err = m.next.Find(ctx, spaceId, envId, collectionId, filter, options...)
......@@ -119,7 +131,7 @@ func (m *loggingMiddleware) Find(ctx context.Context, spaceId string, envId stri
func (m *loggingMiddleware) FindArchived(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindArchivedOptions) (items []*items.Item, total int, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
items, total, err = m.next.FindArchived(ctx, spaceId, envId, collectionId, filter, options...)
......@@ -133,7 +145,7 @@ func (m *loggingMiddleware) FindArchived(ctx context.Context, spaceId string, en
func (m *loggingMiddleware) FindPublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
)
items, total, err = m.next.FindPublished(ctx, spaceId, envId, collectionId, filter, options...)
......@@ -147,7 +159,7 @@ func (m *loggingMiddleware) FindPublished(ctx context.Context, spaceId string, e
func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetOptions) (item *items.Item, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)),
)
......@@ -162,7 +174,7 @@ func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId strin
func (m *loggingMiddleware) GetPublished(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)),
)
......@@ -177,7 +189,7 @@ func (m *loggingMiddleware) GetPublished(ctx context.Context, spaceId string, en
func (m *loggingMiddleware) GetRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, revisionId string, options ...*items.GetRevisionOptions) (item *items.Item, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)),
)
......@@ -191,8 +203,12 @@ func (m *loggingMiddleware) GetRevision(ctx context.Context, spaceId string, env
}
func (m *loggingMiddleware) Introspect(ctx context.Context, item *items.Item, opts ...*items.IntrospectOptions) (itm *items.Item, sch *schema.Schema, err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Object(item),
)
......@@ -207,7 +223,7 @@ func (m *loggingMiddleware) Introspect(ctx context.Context, item *items.Item, op
func (m *loggingMiddleware) ListRevisions(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.ListRevisionsOptions) (items []*items.Item, err error) {
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceId),
logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)),
)
......@@ -221,8 +237,12 @@ func (m *loggingMiddleware) ListRevisions(ctx context.Context, spaceId string, e
}
func (m *loggingMiddleware) Publish(ctx context.Context, item *items.Item, options ...*items.PublishOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemPublish),
logzap.Object(item),
)
......@@ -233,13 +253,17 @@ func (m *loggingMiddleware) Publish(ctx context.Context, item *items.Item, optio
return
}
logger.Info("Successfully published", logzap.Channels(logzap.Userlog))
logger.Info("Item published", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Unarchive(ctx context.Context, item *items.Item, options ...*items.UnarchiveOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemUnarchive),
logzap.Object(item),
)
......@@ -250,13 +274,17 @@ func (m *loggingMiddleware) Unarchive(ctx context.Context, item *items.Item, opt
return
}
logger.Info("Successfully unarchived", logzap.Channels(logzap.Userlog))
logger.Info("Item unarchived", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Undelete(ctx context.Context, item *items.Item, options ...*items.UndeleteOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemUndelete),
logzap.Object(item),
)
......@@ -267,13 +295,17 @@ func (m *loggingMiddleware) Undelete(ctx context.Context, item *items.Item, opti
return
}
logger.Info("Successfully undeleted", logzap.Channels(logzap.Userlog))
logger.Info("Item undeleted", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Unpublish(ctx context.Context, item *items.Item, options ...*items.UnpublishOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemUnpublish),
logzap.Object(item),
)
......@@ -284,13 +316,17 @@ func (m *loggingMiddleware) Unpublish(ctx context.Context, item *items.Item, opt
return
}
logger.Info("Successfully unpublished", logzap.Channels(logzap.Userlog))
logger.Info("Item unpublished", logzap.Channels(logzap.Userlog))
return err
}
func (m *loggingMiddleware) Update(ctx context.Context, item *items.Item, options ...*items.UpdateOptions) (err error) {
var spaceID string
if item != nil {
spaceID = item.SpaceID
}
logger := m.logger.With(
logzap.CallerFromContext(ctx),
logzap.CallerFromContext(ctx, spaceID),
logzap.Event(items.EventItemUpdate),
logzap.Object(item),
)
......@@ -301,6 +337,6 @@ func (m *loggingMiddleware) Update(ctx context.Context, item *items.Item, option
return
}
logger.Info("Successfully updated", logzap.Channels(logzap.Userlog))
logger.Info("Item updated", logzap.Channels(logzap.Userlog))
return err
}
......@@ -17,7 +17,7 @@ func ContainsChannels(channels ...string) FilterFunc {
return func(entry zapcore.Entry, fields []zapcore.Field) bool {
for _, f := range fields {
if f.Key == channelKey && f.Type == zapcore.SkipType {
for _, v := range f.Interface.(stringArray) {
for _, v := range f.Interface.(StringArray) {
if data.Contains(v, channels) {
return true
}
......
......@@ -10,9 +10,9 @@ import (
"go.uber.org/zap/zapcore"
)
type stringArray []string
type StringArray []string
func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
func (ss StringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ss {
arr.AppendString(ss[i])
}
......@@ -24,7 +24,7 @@ func Channels(channels ...string) zap.Field {
return zap.Field{
Key: channelKey,
Type: zapcore.SkipType, // используем тип zapcore.SkipType, чтобы при кодировании поле игнорировалось
Interface: stringArray(channels),
Interface: StringArray(channels),
}
}
......@@ -55,14 +55,20 @@ func Caller(v any) zap.Field {
}
// CallerFromContext извлекает auth.Principal из контекста и устанавливает его в качестве "вызывающего" в формате Object.
func CallerFromContext(ctx context.Context) zap.Field {
return Caller(auth.GetPrincipal(ctx))
// Вторым параметром передается идентификатор пространства, который требуется, если вызывающий является auth.SpaceAccessor.
// Если вызывающий не связан с пространством, следует передать пустую строку.
func CallerFromContext(ctx context.Context, spaceID string) zap.Field {
principal := auth.GetPrincipal(ctx)
if accessor, ok := principal.(auth.SpaceAccessor); ok && spaceID != "" {
principal = accessor.Space(spaceID)
}
return Caller(principal)
}
func Attr(attr any) zap.Field {
return zap.Any("attr", attr)
return zap.Reflect("attr", attr)
}
func Tags(tags ...string) zap.Field {
return zap.Strings("tags", tags)
return zap.Array("tags", StringArray(tags))
}
......@@ -19,8 +19,8 @@ func TestChannels(t *testing.T) {
field zap.Field
want zap.Field
}{
{name: "ok", field: Channels("master"), want: zap.Field{Key: channelKey, Type: zapcore.SkipType, Interface: stringArray{"master"}}},
{name: "invalid", field: Channels(), want: zap.Field{Key: channelKey, Type: zapcore.SkipType, Interface: stringArray(nil)}},
{name: "ok", field: Channels("master"), want: zap.Field{Key: channelKey, Type: zapcore.SkipType, Interface: StringArray{"master"}}},
{name: "invalid", field: Channels(), want: zap.Field{Key: channelKey, Type: zapcore.SkipType, Interface: StringArray(nil)}},
}
for _, tc := range tests {
......@@ -167,8 +167,8 @@ func TestCallerFromContext(t *testing.T) {
field zap.Field
want zap.Field
}{
{name: "ok", field: CallerFromContext(ctx), want: zap.Reflect("caller", oid)},
{name: "invalid", field: CallerFromContext(context.TODO()), want: zap.Reflect("caller", (*id.ObjectId)(nil))},
{name: "ok", field: CallerFromContext(ctx, ""), want: zap.Reflect("caller", oid)},
{name: "invalid", field: CallerFromContext(context.TODO(), ""), want: zap.Reflect("caller", (*id.ObjectId)(nil))},
}
for _, tc := range tests {
......@@ -208,13 +208,13 @@ func TestTags(t *testing.T) {
field zap.Field
want zap.Field
}{
{name: "ok", field: Tags("a", "b", "c"), want: zap.Strings("tags", []string{"a", "b", "c"})},
{name: "invalid", field: Tags(nil...), want: zap.Strings("tags", nil)},
{name: "ok", field: Tags("a", "b", "c"), want: zap.Array("tags", StringArray{"a", "b", "c"})},
{name: "invalid", field: Tags(nil...), want: zap.Array("tags", StringArray(nil))},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert.True(t, tc.want.Equals(tc.field))
assert.Equal(t, tc.want, tc.field)
})
}
}
package zap
import (
"slices"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
......@@ -51,9 +53,9 @@ type filterCore struct {
filters []FilterFunc
// fields хранит контекст записей ядра, передаваемых при вызове With.
// context хранит контекст записей ядра, передаваемых при вызове With.
// В методе Write передаются только поля конкретной записи, но мы также хотим учитывать поля контекста ядра.
fields []zap.Field
context []zap.Field
}
// WithFilters - добавить фильтры, которые будут применяться при записи лога (вызове `core.Write`)
......@@ -80,7 +82,7 @@ func (core *filterCore) With(fields []zapcore.Field) zapcore.Core {
return &filterCore{
Core: core.Core.With(fields),
filters: core.filters,
fields: append(core.fields, fields...),
context: slices.Concat(core.context, fields),
}
}
......@@ -92,15 +94,11 @@ func (core *filterCore) Check(entry zapcore.Entry, checkedEntry *zapcore.Checked
}
func (core *filterCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
if len(core.fields) > 0 {
fields = append(core.fields, fields...)
}
all := slices.Concat(core.context, fields)
for _, filter := range core.filters {
if !filter(entry, fields) {
if !filter(entry, all) {
return nil
}
}
return core.Core.Write(entry, fields)
}
......@@ -9,6 +9,20 @@ import (
"go.uber.org/zap/zaptest/observer"
)
func TestFilterCore_With(t *testing.T) {
core, logs := observer.New(zapcore.InfoLevel)
core = WithFilters(core)
field := zap.String("k", "v")
err := core.With([]zapcore.Field{field}).Write(zapcore.Entry{Message: "msg"}, nil)
require.NoError(t, err)
entries := logs.All()
require.Len(t, entries, 1)
require.Len(t, entries[0].Context, 1)
require.True(t, field.Equals(entries[0].Context[0]))
}
func TestFilterCore_Write(t *testing.T) {
core, logs := observer.New(zapcore.InfoLevel)
core = WithFilters(core, ContainsField(zap.Bool("check", true)))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment