replace handler, connection and account log fields instead of duplicating

This commit is contained in:
Pavel 2024-09-26 16:48:52 +03:00
parent ac8765ef1e
commit 324a3dac5f
6 changed files with 88 additions and 10 deletions

View File

@ -85,12 +85,18 @@ func Body(val any) zap.Field {
return zap.Any(BodyAttr, m) return zap.Any(BodyAttr, m)
} }
return zap.String(BodyAttr, item) return zap.String(BodyAttr, item)
case []byte: case []byte, json.RawMessage:
var val []byte
if msg, ok := item.(json.RawMessage); ok {
val = msg
} else {
val = item.([]byte)
}
var m interface{} var m interface{}
if err := json.Unmarshal(item, &m); err == nil { if err := json.Unmarshal(val, &m); err == nil {
return zap.Any(BodyAttr, m) return zap.Any(BodyAttr, m)
} }
return zap.String(BodyAttr, string(item)) return zap.String(BodyAttr, string(val))
case io.Reader: case io.Reader:
data, err := io.ReadAll(item) data, err := io.ReadAll(item)
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package logger
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -125,6 +126,11 @@ func TestBody(t *testing.T) {
input: []byte("test body"), input: []byte("test body"),
result: "test body", result: "test body",
}, },
{
name: "json.RawMessage input",
input: json.RawMessage("test body"),
result: "test body",
},
{ {
name: "json byte slice input", name: "json byte slice input",
input: []byte(`{"success":true}`), input: []byte(`{"success":true}`),

View File

@ -85,16 +85,19 @@ func (l *bufferLogger) WithLazy(fields ...zapcore.Field) Logger {
} }
} }
// ForHandler returns a new logger that is associated with the given handler.
func (l *bufferLogger) ForHandler(handler any) Logger { func (l *bufferLogger) ForHandler(handler any) Logger {
return l.WithLazy(zap.Any(HandlerAttr, handler)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(HandlerAttr, handler)))
} }
// ForConnection returns a new logger that is associated with the given connection.
func (l *bufferLogger) ForConnection(conn any) Logger { func (l *bufferLogger) ForConnection(conn any) Logger {
return l.WithLazy(zap.Any(ConnectionAttr, conn)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(ConnectionAttr, conn)))
} }
// ForAccount returns a new logger that is associated with the given account.
func (l *bufferLogger) ForAccount(acc any) Logger { func (l *bufferLogger) ForAccount(acc any) Logger {
return l.WithLazy(zap.Any(AccountAttr, acc)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(AccountAttr, acc)))
} }
// Read bytes from the logger buffer. io.Reader implementation. // Read bytes from the logger buffer. io.Reader implementation.
@ -117,6 +120,28 @@ func (l *bufferLogger) Reset() {
l.buf.Reset() l.buf.Reset()
} }
// clone creates a copy of the given logger.
func (l *bufferLogger) clone(log *zap.Logger) Logger {
parent := l.parent
if parent == nil {
parent = l.Logger
}
return &bufferLogger{
Default: Default{
Logger: log,
parent: parent,
},
}
}
// parentOrCurrent returns parent logger if it exists or current logger otherwise.
func (l *bufferLogger) parentOrCurrent() *zap.Logger {
if l.parent != nil {
return l.parent
}
return l.Logger
}
type lockableBuffer struct { type lockableBuffer struct {
buf bytes.Buffer buf bytes.Buffer
rw sync.RWMutex rw sync.RWMutex

View File

@ -47,6 +47,7 @@ type Logger interface {
// Default is a default logger implementation. // Default is a default logger implementation.
type Default struct { type Default struct {
*zap.Logger *zap.Logger
parent *zap.Logger
} }
// NewDefault creates a new default logger with the given format and debug level. // NewDefault creates a new default logger with the given format and debug level.
@ -68,22 +69,34 @@ func (l *Default) WithLazy(fields ...zap.Field) Logger {
// ForHandler returns a new logger that is associated with the given handler. // ForHandler returns a new logger that is associated with the given handler.
func (l *Default) ForHandler(handler any) Logger { func (l *Default) ForHandler(handler any) Logger {
return l.WithLazy(zap.Any(HandlerAttr, handler)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(HandlerAttr, handler)))
} }
// ForConnection returns a new logger that is associated with the given connection. // ForConnection returns a new logger that is associated with the given connection.
func (l *Default) ForConnection(conn any) Logger { func (l *Default) ForConnection(conn any) Logger {
return l.WithLazy(zap.Any(ConnectionAttr, conn)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(ConnectionAttr, conn)))
} }
// ForAccount returns a new logger that is associated with the given account. // ForAccount returns a new logger that is associated with the given account.
func (l *Default) ForAccount(acc any) Logger { func (l *Default) ForAccount(acc any) Logger {
return l.WithLazy(zap.Any(AccountAttr, acc)) return l.clone(l.parentOrCurrent().WithLazy(zap.Any(AccountAttr, acc)))
} }
// clone creates a copy of the given logger. // clone creates a copy of the given logger.
func (l *Default) clone(log *zap.Logger) Logger { func (l *Default) clone(log *zap.Logger) Logger {
return &Default{Logger: log} parent := l.parent
if parent == nil {
parent = l.Logger
}
return &Default{Logger: log, parent: parent}
}
// parentOrCurrent returns parent logger if it exists or current logger otherwise.
func (l *Default) parentOrCurrent() *zap.Logger {
if l.parent != nil {
return l.parent
}
return l.Logger
} }
// AnyZapFields converts an array of values to zap fields. // AnyZapFields converts an array of values to zap fields.

View File

@ -61,6 +61,14 @@ func (s *TestDefaultSuite) TestForHandler() {
s.Assert().Equal("Handler", items[0].Handler) s.Assert().Equal("Handler", items[0].Handler)
} }
func (s *TestDefaultSuite) TestForHandlerNoDuplicate() {
log := newBufferLogger()
log.ForHandler("handler1").ForHandler("handler2").Info("test")
s.Assert().Contains(log.String(), "handler2")
s.Assert().NotContains(log.String(), "handler1")
}
func (s *TestDefaultSuite) TestForConnection() { func (s *TestDefaultSuite) TestForConnection() {
log := newBufferLogger() log := newBufferLogger()
log.ForConnection("connection").Info("test") log.ForConnection("connection").Info("test")
@ -71,6 +79,14 @@ func (s *TestDefaultSuite) TestForConnection() {
s.Assert().Equal("connection", items[0].Connection) s.Assert().Equal("connection", items[0].Connection)
} }
func (s *TestDefaultSuite) TestForConnectionNoDuplicate() {
log := newBufferLogger()
log.ForConnection("conn1").ForConnection("conn2").Info("test")
s.Assert().Contains(log.String(), "conn2")
s.Assert().NotContains(log.String(), "conn1")
}
func (s *TestDefaultSuite) TestForAccount() { func (s *TestDefaultSuite) TestForAccount() {
log := newBufferLogger() log := newBufferLogger()
log.ForAccount("account").Info("test") log.ForAccount("account").Info("test")
@ -81,6 +97,14 @@ func (s *TestDefaultSuite) TestForAccount() {
s.Assert().Equal("account", items[0].Account) s.Assert().Equal("account", items[0].Account)
} }
func (s *TestDefaultSuite) TestForAccountNoDuplicate() {
log := newBufferLogger()
log.ForAccount("acc1").ForAccount("acc2").Info("test")
s.Assert().Contains(log.String(), "acc2")
s.Assert().NotContains(log.String(), "acc1")
}
func TestAnyZapFields(t *testing.T) { func TestAnyZapFields(t *testing.T) {
fields := AnyZapFields([]interface{}{zap.String("k0", "v0"), "ooga", "booga"}) fields := AnyZapFields([]interface{}{zap.String("k0", "v0"), "ooga", "booga"})
require.Len(t, fields, 3) require.Len(t, fields, 3)

View File

@ -44,6 +44,10 @@ var _jsonWithContextPool = NewPool(func() *jsonWithContextEncoder {
}) })
func init() { func init() {
registerJSONWithContext()
}
func registerJSONWithContext() {
err := zap.RegisterEncoder("json-with-context", func(config zapcore.EncoderConfig) (zapcore.Encoder, error) { err := zap.RegisterEncoder("json-with-context", func(config zapcore.EncoderConfig) (zapcore.Encoder, error) {
return NewJSONWithContextEncoder(config), nil return NewJSONWithContextEncoder(config), nil
}) })