Skip to content

Commit

Permalink
[#1770] logger: Support runtime level reloading
Browse files Browse the repository at this point in the history
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
  • Loading branch information
carpawell committed Oct 12, 2022
1 parent f037022 commit d7c7022
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 14 deletions.
2 changes: 1 addition & 1 deletion cmd/neofs-node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ func initCfg(appCfg *config.Config) *cfg {
)
fatalOnErr(err)

log, err := logger.NewLogger(logPrm)
log, err := logger.NewLogger(&logPrm)
fatalOnErr(err)

var netAddr network.AddressGroup
Expand Down
71 changes: 58 additions & 13 deletions pkg/util/logger/logger.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package logger

import (
"errors"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
Expand All @@ -15,44 +13,91 @@ type Logger struct {
}

// 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 {
// link to the created Logger
// instance; used for a runtime
// reconfiguration
_log *Logger

// support runtime rereading
level zapcore.Level
}

// ErrNilLogger is returned by functions that
// expect a non-nil Logger but received nil.
var ErrNilLogger = errors.New("logger is nil")
// do not support runtime rereading
}

// SetLevelString sets the minimum logging level.
// SetLevelString sets the minimum logging level. Default is
// "info".
//
// Returns an error if s is not a string representation of a
// supporting logging level.
//
// Returns error of s is not a string representation of zap.Level
// value (see zapcore.Level docs).
// Supports runtime rereading.
func (p *Prm) SetLevelString(s string) error {
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:
// - parameterized level;
// - console encoding;
// - ISO8601 time encoding.
//
// 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)

c := zap.NewProductionConfig()
c.Level = lvl
c.Encoding = "console"
c.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder

l, err := c.Build(
lZap, err := c.Build(
zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)),
)
if err != nil {
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
}

0 comments on commit d7c7022

Please sign in to comment.