[#1619] logger: Filter entries by tags provided in config

Change-Id: Ia2a79d6cb2a5eb263fb2e6db3f9cf9f2a7d57118
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
This commit is contained in:
Anton Nikiforov 2025-01-28 15:14:45 +03:00
parent dfdf2a9f58
commit cacf3dc113
8 changed files with 194 additions and 9 deletions

View file

@ -2,6 +2,7 @@ package logger
import (
"fmt"
"sync/atomic"
"time"
"git.frostfs.info/TrueCloudLab/zapjournald"
@ -15,6 +16,12 @@ import (
type Logger struct {
z *zap.Logger
lvl zap.AtomicLevel
// Tag used by Logger
t Tag
// Contains map of Tag to log level, overrides lvl
tl *atomic.Value
// Parent zap.Logger, required to override field zapTagFieldName in the output
pz *zap.Logger
}
// Prm groups Logger's parameters.
@ -36,12 +43,17 @@ type Prm struct {
// PrependTimestamp specifies whether to prepend a timestamp in the log
PrependTimestamp bool
// map of tag's bit masks to log level, overrides lvl
tl map[Tag]zapcore.Level
}
const (
DestinationUndefined = ""
DestinationStdout = "stdout"
DestinationJournald = "journald"
zapTagFieldName = "tag"
)
// SetLevelString sets the minimum logging level. Default is
@ -65,6 +77,12 @@ func (p *Prm) SetDestination(d string) error {
return nil
}
// SetTags parses list of tags with log level.
func (p *Prm) SetTags(tags [][]string) (err error) {
p.tl, err = parseTags(tags)
return err
}
// NewLogger constructs a new zap logger instance. Constructing with nil
// parameters is safe: default values will be used then.
// Passing non-nil parameters after a successful creation (non-error) allows
@ -88,10 +106,8 @@ func NewLogger(prm Prm) (*Logger, error) {
}
func newConsoleLogger(prm Prm) (*Logger, error) {
lvl := zap.NewAtomicLevelAt(prm.level)
c := zap.NewProductionConfig()
c.Level = lvl
c.Level = zap.NewAtomicLevelAt(zapcore.DebugLevel)
c.Encoding = "console"
if prm.SamplingHook != nil {
c.Sampling.Hook = prm.SamplingHook
@ -110,15 +126,19 @@ func newConsoleLogger(prm Prm) (*Logger, error) {
if err != nil {
return nil, err
}
parentZap := *lZap
lZap = lZap.With(zap.String(zapTagFieldName, tagToString(TagMain)))
l := &Logger{z: lZap, lvl: lvl}
v := atomic.Value{}
v.Store(prm.tl)
l := &Logger{z: lZap, pz: &parentZap, lvl: zap.NewAtomicLevelAt(prm.level), t: TagMain, tl: &v}
return l, nil
}
func newJournaldLogger(prm Prm) (*Logger, error) {
lvl := zap.NewAtomicLevelAt(prm.level)
lvl := zap.NewAtomicLevelAt(zapcore.DebugLevel)
c := zap.NewProductionConfig()
if prm.SamplingHook != nil {
c.Sampling.Hook = prm.SamplingHook
@ -151,26 +171,48 @@ func newJournaldLogger(prm Prm) (*Logger, error) {
samplerOpts...,
)
lZap := zap.New(samplingCore, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)), zap.AddCallerSkip(1))
parentZap := *lZap
lZap = lZap.With(zap.String(zapTagFieldName, tagToString(TagMain)))
l := &Logger{z: lZap, lvl: lvl}
v := atomic.Value{}
v.Store(prm.tl)
l := &Logger{z: lZap, pz: &parentZap, lvl: zap.NewAtomicLevelAt(prm.level), t: TagMain, tl: &v}
return l, nil
}
func (l *Logger) Reload(prm Prm) {
l.lvl.SetLevel(prm.level)
l.tl.Store(prm.tl)
}
func (l *Logger) WithOptions(options ...zap.Option) {
l.z = l.z.WithOptions(options...)
l.pz = l.pz.WithOptions(options...)
}
func (l *Logger) With(fields ...zap.Field) *Logger {
return &Logger{z: l.z.With(fields...)}
c := *l
c.z = l.z.With(fields...)
return &c
}
func (l *Logger) WithTag(tag Tag) *Logger {
c := *l
c.t = tag
c.z = c.pz.With(zap.String(zapTagFieldName, tagToString(tag)))
return &c
}
func NewLoggerWrapper(z *zap.Logger) *Logger {
tl := &atomic.Value{}
tl.Store(make(map[Tag]zapcore.Level))
return &Logger{
z: z.WithOptions(zap.AddCallerSkip(1)),
z: z.WithOptions(zap.AddCallerSkip(1)),
pz: z.WithOptions(zap.AddCallerSkip(1)),
tl: tl,
lvl: zap.NewAtomicLevelAt(zapcore.DebugLevel),
}
}