119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
|
package logutils
|
||
|
|
||
|
import (
|
||
|
"sync/atomic"
|
||
|
|
||
|
"go.uber.org/zap"
|
||
|
"go.uber.org/zap/zapcore"
|
||
|
)
|
||
|
|
||
|
// encoderWrapper holds any zapcore.Encoder and ensures a consistent type for atomic.Value
|
||
|
type encoderWrapper struct {
|
||
|
zapcore.Encoder
|
||
|
}
|
||
|
|
||
|
// writeSyncerWrapper holds any zapcore.WriteSyncer and ensures a consistent type for atomic.Value
|
||
|
type writeSyncerWrapper struct {
|
||
|
zapcore.WriteSyncer
|
||
|
}
|
||
|
|
||
|
// Core wraps a zapcore.Core that can update its syncer and encoder at runtime
|
||
|
type Core struct {
|
||
|
encoder atomic.Value // encoderWrapper
|
||
|
syncer *atomic.Value // writeSyncerWrapper
|
||
|
level zap.AtomicLevel
|
||
|
|
||
|
next *Core
|
||
|
nextFields []zapcore.Field
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
_ zapcore.Core = (*Core)(nil)
|
||
|
)
|
||
|
|
||
|
func NewCore(encoder zapcore.Encoder, syncer zapcore.WriteSyncer, atomicLevel zap.AtomicLevel) *Core {
|
||
|
core := &Core{
|
||
|
syncer: &atomic.Value{},
|
||
|
level: atomicLevel,
|
||
|
}
|
||
|
core.encoder.Store(encoderWrapper{Encoder: encoder})
|
||
|
core.syncer.Store(writeSyncerWrapper{WriteSyncer: syncer})
|
||
|
return core
|
||
|
}
|
||
|
|
||
|
func (core *Core) getEncoder() zapcore.Encoder {
|
||
|
return core.encoder.Load().(zapcore.Encoder)
|
||
|
}
|
||
|
|
||
|
func (core *Core) getSyncer() zapcore.WriteSyncer {
|
||
|
return core.syncer.Load().(zapcore.WriteSyncer)
|
||
|
}
|
||
|
|
||
|
func (core *Core) Enabled(lvl zapcore.Level) bool {
|
||
|
return core.level.Enabled(lvl)
|
||
|
}
|
||
|
|
||
|
func (core *Core) With(fields []zapcore.Field) zapcore.Core {
|
||
|
clonedEncoder := encoderWrapper{Encoder: core.getEncoder().Clone()}
|
||
|
for i := range fields {
|
||
|
fields[i].AddTo(clonedEncoder)
|
||
|
}
|
||
|
|
||
|
clone := *core
|
||
|
clone.encoder.Store(clonedEncoder)
|
||
|
|
||
|
core.next = &clone
|
||
|
core.nextFields = fields
|
||
|
|
||
|
return &clone
|
||
|
}
|
||
|
|
||
|
func (core *Core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||
|
if core.Enabled(ent.Level) {
|
||
|
return ce.AddCore(ent, core)
|
||
|
}
|
||
|
return ce
|
||
|
}
|
||
|
|
||
|
func (core *Core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
|
||
|
buf, err := core.getEncoder().EncodeEntry(ent, fields)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = core.getSyncer().Write(buf.Bytes())
|
||
|
buf.Free()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if ent.Level > zapcore.ErrorLevel {
|
||
|
// Since we may be crashing the program, sync the output.
|
||
|
_ = core.Sync()
|
||
|
}
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (core *Core) Sync() error {
|
||
|
return core.getSyncer().Sync()
|
||
|
}
|
||
|
|
||
|
func (core *Core) UpdateSyncer(newSyncer zapcore.WriteSyncer) {
|
||
|
core.syncer.Store(writeSyncerWrapper{WriteSyncer: newSyncer})
|
||
|
}
|
||
|
|
||
|
func (core *Core) UpdateEncoder(newEncoder zapcore.Encoder) {
|
||
|
core.encoder.Store(encoderWrapper{Encoder: newEncoder})
|
||
|
|
||
|
// Update next Cores with newEncoder
|
||
|
current := core
|
||
|
for current.next != nil {
|
||
|
clonedEncoder := encoderWrapper{Encoder: core.getEncoder().Clone()}
|
||
|
for i := range core.nextFields {
|
||
|
current.nextFields[i].AddTo(clonedEncoder)
|
||
|
}
|
||
|
current.next.encoder.Store(clonedEncoder)
|
||
|
current = current.next
|
||
|
}
|
||
|
}
|