add an ability to set levels separately for named loggers
with glob support
This commit is contained in:
parent
bc7a1754ad
commit
d4c19f790d
@ -1,11 +1,17 @@
|
||||
package logger
|
||||
|
||||
import "go.uber.org/zap"
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/anytypeio/any-sync/util/slice"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Production bool `yaml:"production"`
|
||||
DefaultLevel string `yaml:"defaultLevel"`
|
||||
NamedLevels map[string]string `yaml:"namedLevels"`
|
||||
Production bool `yaml:"production"`
|
||||
DefaultLevel string `yaml:"defaultLevel"`
|
||||
NamedLevels map[string]string `yaml:"namedLevels"`
|
||||
AddOutputPaths []string
|
||||
DisableStdErr bool
|
||||
}
|
||||
|
||||
func (l Config) ApplyGlobal() {
|
||||
@ -15,19 +21,33 @@ func (l Config) ApplyGlobal() {
|
||||
} else {
|
||||
conf = zap.NewDevelopmentConfig()
|
||||
}
|
||||
if len(l.AddOutputPaths) > 0 {
|
||||
conf.OutputPaths = append(conf.OutputPaths, l.AddOutputPaths...)
|
||||
}
|
||||
if l.DisableStdErr {
|
||||
conf.OutputPaths = slice.Filter(conf.OutputPaths, func(path string) bool {
|
||||
return path != "stderr"
|
||||
})
|
||||
}
|
||||
|
||||
var err error
|
||||
if defaultLevel, err := zap.ParseAtomicLevel(l.DefaultLevel); err == nil {
|
||||
conf.Level = defaultLevel
|
||||
}
|
||||
var levels = make(map[string]zap.AtomicLevel)
|
||||
var lvl = make(map[string]zap.AtomicLevel)
|
||||
for k, v := range l.NamedLevels {
|
||||
if lev, err := zap.ParseAtomicLevel(v); err != nil {
|
||||
levels[k] = lev
|
||||
if lev, err := zap.ParseAtomicLevel(v); err == nil {
|
||||
lvl[k] = lev
|
||||
// we need to have a minimum level of all named loggers for the main logger
|
||||
if lev.Level() < conf.Level.Level() {
|
||||
conf.Level.SetLevel(lev.Level())
|
||||
}
|
||||
}
|
||||
}
|
||||
defaultLogger, err := conf.Build()
|
||||
lg, err := conf.Build()
|
||||
if err != nil {
|
||||
Default().Fatal("can't build logger", zap.Error(err))
|
||||
}
|
||||
SetDefault(defaultLogger)
|
||||
SetNamedLevels(levels)
|
||||
SetDefault(lg)
|
||||
SetNamedLevels(lvl)
|
||||
}
|
||||
|
||||
@ -1,51 +1,110 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
defaultLogger *zap.Logger
|
||||
levels = make(map[string]zap.AtomicLevel)
|
||||
loggers = make(map[string]CtxLogger)
|
||||
mu sync.Mutex
|
||||
logger *zap.Logger
|
||||
loggerConfig zap.Config
|
||||
namedLevels = make(map[string]zap.AtomicLevel)
|
||||
namedGlobs = make(map[string]glob.Glob)
|
||||
namedLoggers = make(map[string]CtxLogger)
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultLogger, _ = zap.NewDevelopment()
|
||||
zap.NewProduction()
|
||||
loggerConfig = zap.NewDevelopmentConfig()
|
||||
logger, _ = loggerConfig.Build()
|
||||
}
|
||||
|
||||
// SetDefault replaces the default logger
|
||||
// you need to call SetNamedLevels after in case you have named loggers,
|
||||
// otherwise they will use the old logger
|
||||
func SetDefault(l *zap.Logger) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
*defaultLogger = *l
|
||||
for name, l := range loggers {
|
||||
*l.Logger = *defaultLogger.Named(name)
|
||||
}
|
||||
*logger = *l
|
||||
}
|
||||
|
||||
// SetNamedLevels sets the namedLevels for named loggers
|
||||
// it also supports glob patterns for names, like "app*"
|
||||
// can be racy in case there are existing named loggers
|
||||
// so consider to call only once at the beginning
|
||||
func SetNamedLevels(l map[string]zap.AtomicLevel) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
levels = l
|
||||
namedLevels = l
|
||||
|
||||
var minLevel = logger.Level()
|
||||
for k, l := range namedLevels {
|
||||
g, err := glob.Compile(k)
|
||||
if err == nil {
|
||||
namedGlobs[k] = g
|
||||
}
|
||||
namedLevels[k] = l
|
||||
if l.Level() < minLevel {
|
||||
minLevel = l.Level()
|
||||
}
|
||||
}
|
||||
|
||||
if minLevel < logger.Level() {
|
||||
// recreate logger if the min level is lower than the current min one
|
||||
loggerConfig.Level = zap.NewAtomicLevelAt(minLevel)
|
||||
logger, _ = loggerConfig.Build()
|
||||
}
|
||||
|
||||
for name, lg := range namedLoggers {
|
||||
level := getLevel(name)
|
||||
// this can be racy, but
|
||||
lg.Logger = zap.New(logger.Core()).WithOptions(
|
||||
zap.IncreaseLevel(level),
|
||||
).Named(name)
|
||||
}
|
||||
}
|
||||
|
||||
func Default() *zap.Logger {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return defaultLogger
|
||||
return logger
|
||||
}
|
||||
|
||||
func getLevel(name string) zap.AtomicLevel {
|
||||
level, ok := namedLevels[name]
|
||||
if !ok {
|
||||
var found bool
|
||||
for globName, glob := range namedGlobs {
|
||||
if glob.Match(name) {
|
||||
found = true
|
||||
level, _ = namedLevels[globName]
|
||||
// no need to check ok, because we know that globName exists
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
level = loggerConfig.Level
|
||||
}
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func NewNamed(name string, fields ...zap.Field) CtxLogger {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
l := defaultLogger.Named(name)
|
||||
if len(fields) > 0 {
|
||||
l = l.With(fields...)
|
||||
|
||||
if l, nameExists := namedLoggers[name]; nameExists {
|
||||
return l
|
||||
}
|
||||
|
||||
level := getLevel(name)
|
||||
l := zap.New(logger.Core()).WithOptions(
|
||||
zap.IncreaseLevel(level),
|
||||
).Named(name)
|
||||
|
||||
ctxL := CtxLogger{l}
|
||||
loggers[name] = ctxL
|
||||
namedLoggers[name] = ctxL
|
||||
return ctxL
|
||||
}
|
||||
|
||||
3
go.mod
3
go.mod
@ -7,6 +7,7 @@ require (
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cheggaaa/mb/v3 v3.0.1
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/goccy/go-graphviz v0.1.0
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/mock v1.6.0
|
||||
@ -22,6 +23,7 @@ require (
|
||||
github.com/ipfs/go-unixfs v0.4.4
|
||||
github.com/libp2p/go-libp2p v0.24.1
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/multiformats/go-multibase v0.1.1
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
@ -74,7 +76,6 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.8.0 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@ -106,6 +106,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-graphviz v0.1.0 h1:6OqQoQ5PeAiHYe/YcusyeulqBrOkUb16HQ4ctRdyVUU=
|
||||
github.com/goccy/go-graphviz v0.1.0/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user