[#1770] logger: Support runtime level reloading

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2022-09-28 10:59:23 +03:00 committed by Pavel Karpy
parent f037022a7a
commit d7c7022bbd
2 changed files with 59 additions and 14 deletions

View file

@ -492,7 +492,7 @@ func initCfg(appCfg *config.Config) *cfg {
) )
fatalOnErr(err) fatalOnErr(err)
log, err := logger.NewLogger(logPrm) log, err := logger.NewLogger(&logPrm)
fatalOnErr(err) fatalOnErr(err)
var netAddr network.AddressGroup var netAddr network.AddressGroup

View file

@ -1,8 +1,6 @@
package logger package logger
import ( import (
"errors"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
) )
@ -15,23 +13,58 @@ type Logger struct {
} }
// Prm groups Logger's parameters. // Prm groups Logger's parameters.
// Successful passing non-nil parameters to the NewLogger (if returned
// error is nil) connects the parameters with the returned Logger.
// Parameters that have been connected to the Logger support its
// configuration changing.
//
// Passing Prm after a successful connection via the NewLogger, connects
// the Prm to a new instance of the Logger.
//
// See also Reload, SetLevelString.
type Prm struct { type Prm struct {
// link to the created Logger
// instance; used for a runtime
// reconfiguration
_log *Logger
// support runtime rereading
level zapcore.Level level zapcore.Level
// do not support runtime rereading
} }
// ErrNilLogger is returned by functions that // SetLevelString sets the minimum logging level. Default is
// expect a non-nil Logger but received nil. // "info".
var ErrNilLogger = errors.New("logger is nil")
// SetLevelString sets the minimum logging level.
// //
// Returns error of s is not a string representation of zap.Level // Returns an error if s is not a string representation of a
// value (see zapcore.Level docs). // supporting logging level.
//
// Supports runtime rereading.
func (p *Prm) SetLevelString(s string) error { func (p *Prm) SetLevelString(s string) error {
return p.level.UnmarshalText([]byte(s)) return p.level.UnmarshalText([]byte(s))
} }
// NewLogger constructs a new zap logger instance. // Reload reloads configuration of a connected instance of the Logger.
// Returns ErrLoggerNotConnected if no connection has been performed.
// Returns any reconfiguration error from the Logger directly.
func (p Prm) Reload() error {
if p._log == nil {
// incorrect logger usage
panic("parameters are not connected to any Logger")
}
return p._log.reload(p)
}
func defaultPrm() *Prm {
return new(Prm)
}
// 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
// runtime reconfiguration.
// //
// Logger is built from production logging configuration with: // Logger is built from production logging configuration with:
// - parameterized level; // - parameterized level;
@ -39,7 +72,11 @@ func (p *Prm) SetLevelString(s string) error {
// - ISO8601 time encoding. // - ISO8601 time encoding.
// //
// Logger records a stack trace for all messages at or above fatal level. // Logger records a stack trace for all messages at or above fatal level.
func NewLogger(prm Prm) (*Logger, error) { func NewLogger(prm *Prm) (*Logger, error) {
if prm == nil {
prm = defaultPrm()
}
lvl := zap.NewAtomicLevelAt(prm.level) lvl := zap.NewAtomicLevelAt(prm.level)
c := zap.NewProductionConfig() c := zap.NewProductionConfig()
@ -47,12 +84,20 @@ func NewLogger(prm Prm) (*Logger, error) {
c.Encoding = "console" c.Encoding = "console"
c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
l, err := c.Build( lZap, err := c.Build(
zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)), zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)),
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Logger{Logger: l, lvl: lvl}, nil l := &Logger{Logger: lZap, lvl: lvl}
prm._log = l
return l, nil
}
func (l *Logger) reload(prm Prm) error {
l.lvl.SetLevel(prm.level)
return nil
} }