This is an automated email from the ASF dual-hosted git repository.
baerwang pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go-pixiu.git
The following commit(s) were added to refs/heads/develop by this push:
new f472c94f fix: fix logger config overwrite problem (#765)
f472c94f is described below
commit f472c94f2044a289aa5e4b6372cd43e1bd5e86f9
Author: Xuetao Li <[email protected]>
AuthorDate: Wed Oct 8 16:46:46 2025 +0800
fix: fix logger config overwrite problem (#765)
* fix: fix logger config overwrite problem
* delete Chinese
* add header
* fix sonar
* import format
* fix ci
* refactor logger: simplify log level handling and remove unused code
* import
* refactor(logger): simplify log level parsing and improve fallback handling
* refactor(logger): simplify log level parsing and improve fallback handling
* fix test
* test(logger): add assertions to validate logger configuration after level
setting
* test(logger): add assertions to validate logger configuration after level
setting
---
pkg/cmd/gateway.go | 23 +---
pkg/configcenter/nacos_load_test.go | 6 +-
pkg/logger/controller.go | 47 ++------
pkg/logger/controller_test.go | 117 ++++++++++++++++++
pkg/logger/logger.go | 84 ++++++++++---
pkg/logger/logger_test.go | 228 ++++++++++++++++++++++++++++--------
6 files changed, 382 insertions(+), 123 deletions(-)
diff --git a/pkg/cmd/gateway.go b/pkg/cmd/gateway.go
index 96bb4ae5..84a7a992 100644
--- a/pkg/cmd/gateway.go
+++ b/pkg/cmd/gateway.go
@@ -39,15 +39,6 @@ import (
)
var (
- flagToLogLevel = map[string]string{
- "trace": "TRACE",
- "debug": "DEBUG",
- "info": "INFO",
- "warning": "WARN",
- "error": "ERROR",
- "critical": "FATAL",
- }
-
configPath string
apiConfigPath string
logConfigPath string
@@ -165,7 +156,7 @@ func initDefaultValue() {
}
}
-// initLog
+// initLog initializes logger according to log config file and log level
func initLog() error {
err := logger.InitLog(logConfigPath)
if err != nil {
@@ -173,13 +164,11 @@ func initLog() error {
return err
}
- if level, ok := flagToLogLevel[logLevel]; ok {
- logger.SetLoggerLevel(level)
- } else {
- logger.SetLoggerLevel(flagToLogLevel[constant.DefaultLogLevel])
- return fmt.Errorf("logLevel is invalid, set log level to
default: %s", constant.DefaultLogLevel)
+ lvl := logger.ParseLogLevel(logLevel)
+ if ok := logger.SetLoggerLevel(lvl); !ok {
+ err = fmt.Errorf("set logLevel failed")
}
- return nil
+ return err
}
func initLogWithConfig(boot *model.Bootstrap) {
@@ -189,7 +178,7 @@ func initLogWithConfig(boot *model.Bootstrap) {
}
// nolint
-// initApiConfig return value of the bool is for the judgment of whether is a
api meta data error, a kind of silly (?)
+// initApiConfig return value of the bool is for the judgment of whether is an
api metadata error or a kind of silly (?)
func initApiConfig() (*model.Bootstrap, error) {
bootstrap := config.Load(configPath)
return bootstrap, nil
diff --git a/pkg/configcenter/nacos_load_test.go
b/pkg/configcenter/nacos_load_test.go
index cadbf94a..1eca5440 100644
--- a/pkg/configcenter/nacos_load_test.go
+++ b/pkg/configcenter/nacos_load_test.go
@@ -28,6 +28,8 @@ import (
import (
. "github.com/smartystreets/goconvey/convey"
+
+ "go.uber.org/zap/zapcore"
)
import (
@@ -97,14 +99,14 @@ func TestNacosConfig_onChange(t *testing.T) {
Convey("Test onChange with empty input", func() {
// Suppress logs during this test.
- logger.SetLoggerLevel("fatal")
+ logger.SetLoggerLevel(zapcore.FatalLevel)
client.remoteConfig = nil
client.onChange(Namespace, Group, DataId, "")
So(client.remoteConfig, ShouldBeNil)
// Restore the logger level.
- logger.SetLoggerLevel("info")
+ logger.SetLoggerLevel(zapcore.InfoLevel)
})
})
}
diff --git a/pkg/logger/controller.go b/pkg/logger/controller.go
index fb2d9708..309442a9 100644
--- a/pkg/logger/controller.go
+++ b/pkg/logger/controller.go
@@ -18,39 +18,32 @@
package logger
import (
- "strings"
"sync"
)
import (
- "go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// logController governs the logging output or configuration changes
throughout the entire project.
type logController struct {
- mu sync.RWMutex
-
- logger *pixiuLogger
+ mu sync.RWMutex
+ logger *PixiuLogger
}
-// setLoggerLevel safely changes the log level in a concurrent manner.
-func (c *logController) setLoggerLevel(level string) bool {
+// setLoggerLevel changes the level at runtime without rebuilding the logger.
+func (c *logController) setLoggerLevel(level zapcore.Level) bool {
c.mu.Lock()
defer c.mu.Unlock()
- lvl := c.parseLevel(level)
- if lvl == nil {
+ if c.logger == nil || c.logger.config == nil {
return false
}
-
- c.logger.config.Level = *lvl
- l, _ := c.logger.config.Build(zap.AddCallerSkip(2))
- c.logger = &pixiuLogger{SugaredLogger: l.Sugar(), config:
c.logger.config}
+ c.logger.config.Level.SetLevel(level)
return true
}
-// updateLogger safely modifies the log object in a concurrent manner.
-func (c *logController) updateLogger(l *pixiuLogger) {
+// updateLogger swaps the underlying logger atomically.
+func (c *logController) updateLogger(l *PixiuLogger) {
c.mu.Lock()
defer c.mu.Unlock()
c.logger = l
@@ -103,27 +96,3 @@ func (c *logController) errorf(fmt string, args ...any) {
defer c.mu.RUnlock()
c.logger.Errorf(fmt, args...)
}
-
-// parseLevel is used to parse the level of the log.
-func (c *logController) parseLevel(level string) *zap.AtomicLevel {
- var lvl zapcore.Level
- switch strings.ToLower(level) {
- case "debug":
- lvl = zapcore.DebugLevel
- case "info":
- lvl = zapcore.InfoLevel
- case "warn":
- lvl = zapcore.WarnLevel
- case "error":
- lvl = zapcore.ErrorLevel
- case "panic":
- lvl = zapcore.PanicLevel
- case "fatal":
- lvl = zapcore.FatalLevel
- default:
- return nil
- }
-
- al := zap.NewAtomicLevelAt(lvl)
- return &al
-}
diff --git a/pkg/logger/controller_test.go b/pkg/logger/controller_test.go
new file mode 100644
index 00000000..eaa4cc25
--- /dev/null
+++ b/pkg/logger/controller_test.go
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package logger
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+
+ "go.uber.org/zap/zapcore"
+)
+
+func TestParseLevelAndSet(t *testing.T) {
+ cfg, _ := newDevConfigToFile(t)
+ InitLogger(cfg)
+
+ tests := []struct {
+ in string
+ ok bool
+ zapLevel zapcore.Level
+ }{
+ {"debug", true, zapcore.DebugLevel},
+ {"INFO", true, zapcore.InfoLevel},
+ {"Warn", true, zapcore.WarnLevel},
+ {"error", true, zapcore.ErrorLevel},
+ {"panic", true, zapcore.PanicLevel},
+ {"dpanic", true, zapcore.DPanicLevel},
+ {"fatal", true, zapcore.FatalLevel},
+ {"critical", true, zapcore.FatalLevel},
+ {"unknown", false, zapcore.InfoLevel}, // parseLevel default
fallback to info
+ {"trace", true, zapcore.DebugLevel},
+ {"Warning", true, zapcore.WarnLevel},
+ }
+
+ for _, tt := range tests {
+ lvl := ParseLogLevel(tt.in)
+ if lvl != tt.zapLevel {
+ t.Fatalf("SetLoggerLevel(%q) want %v", tt.in, tt.ok)
+ }
+ control.setLoggerLevel(lvl)
+
+ // assert the level is set
+ assert.Equal(t, tt.zapLevel,
control.logger.config.Level.Level())
+
+ // assert the cfg is not changed
+ assert.Equal(t, cfg.Development,
control.logger.config.Development)
+ assert.Equal(t, cfg.DisableCaller,
control.logger.config.DisableCaller)
+ assert.Equal(t, cfg.DisableStacktrace,
control.logger.config.DisableStacktrace)
+ assert.Equal(t, cfg.Sampling, control.logger.config.Sampling)
+ assert.Equal(t, cfg.Encoding, control.logger.config.Encoding)
+ assert.Equal(t, cfg.EncoderConfig.MessageKey,
control.logger.config.EncoderConfig.MessageKey)
+ assert.Equal(t, cfg.EncoderConfig.LevelKey,
control.logger.config.EncoderConfig.LevelKey)
+ assert.Equal(t, cfg.EncoderConfig.TimeKey,
control.logger.config.EncoderConfig.TimeKey)
+ assert.Equal(t, cfg.EncoderConfig.NameKey,
control.logger.config.EncoderConfig.NameKey)
+ assert.Equal(t, cfg.EncoderConfig.CallerKey,
control.logger.config.EncoderConfig.CallerKey)
+ assert.Equal(t, cfg.EncoderConfig.FunctionKey,
control.logger.config.EncoderConfig.FunctionKey)
+ assert.Equal(t, cfg.EncoderConfig.StacktraceKey,
control.logger.config.EncoderConfig.StacktraceKey)
+ assert.Equal(t, cfg.EncoderConfig.SkipLineEnding,
control.logger.config.EncoderConfig.SkipLineEnding)
+ assert.Equal(t, cfg.EncoderConfig.LineEnding,
control.logger.config.EncoderConfig.LineEnding)
+ assert.Equal(t, cfg.EncoderConfig.ConsoleSeparator,
control.logger.config.EncoderConfig.ConsoleSeparator)
+ assert.Equal(t, cfg.OutputPaths,
control.logger.config.OutputPaths)
+ assert.Equal(t, cfg.ErrorOutputPaths,
control.logger.config.ErrorOutputPaths)
+ assert.Equal(t, cfg.InitialFields,
control.logger.config.InitialFields)
+ }
+
+ // make sure able to write
+ GetLogger().Info("still alive")
+ _ = GetLogger().Sync()
+}
+
+func TestInitLoggerNil(t *testing.T) {
+ InitLogger(nil)
+ if GetLogger() == nil || GetLogger().SugaredLogger == nil {
+ t.Fatalf("GetLogger returned nil")
+ }
+ // retrigger InitLogger(nil)
+ InitLogger(nil)
+ GetLogger().Debug("dev init ok")
+ _ = GetLogger().Sync()
+}
+
+// HotReload(nil) fallback to dev
+func TestHotReloadNil(t *testing.T) {
+ if err := HotReload(nil); err != nil {
+ t.Fatalf("HotReload(nil) unexpected error: %v", err)
+ }
+ GetLogger().Warn("after hot reload nil")
+ _ = GetLogger().Sync()
+}
+
+func TestLoggerBasicUsage(t *testing.T) {
+ cfg, _ := newDevConfigToFile(t)
+ InitLogger(cfg)
+
+ log := GetLogger()
+ log = &PixiuLogger{SugaredLogger: log.With("k", "v"), config:
log.config}
+ log.Infow("with fields", "a", 1)
+
+ _ = log.Sync()
+}
diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go
index a1fff168..f9a4362f 100644
--- a/pkg/logger/logger.go
+++ b/pkg/logger/logger.go
@@ -37,20 +37,20 @@ import (
var control *logController
-type pixiuLogger struct {
+type PixiuLogger struct {
*zap.SugaredLogger
config *zap.Config
}
func init() {
- // only use in test case, so just load default config
+ // only used in test/bootstrap; keep a sane default
if control == nil {
control = new(logController)
InitLogger(nil)
}
}
-// PaddedCallerEncoder is a custom caller encoder that ensures that all file
paths are displayed at the same length
+// PaddedCallerEncoder aligns caller path to a fixed width for prettier
console output.
func PaddedCallerEncoder(caller zapcore.EntryCaller, enc
zapcore.PrimitiveArrayEncoder) {
callerPath := caller.TrimmedPath()
@@ -65,7 +65,21 @@ func PaddedCallerEncoder(caller zapcore.EntryCaller, enc
zapcore.PrimitiveArrayE
enc.AppendString(callerPath)
}
-// InitLog load from config path
+// helper: build with unified pixiu options.
+// - always AddCaller + AddCallerSkip(2)
+// - AddStacktrace(Error+) only when stacktrace is not disabled in cfg
+func buildWithPixiuOptions(cfg *zap.Config) (*zap.Logger, error) {
+ opts := []zap.Option{
+ zap.AddCaller(),
+ zap.AddCallerSkip(2),
+ }
+ if !cfg.DisableStacktrace {
+ opts = append(opts, zap.AddStacktrace(zapcore.ErrorLevel))
+ }
+ return cfg.Build(opts...)
+}
+
+// InitLog loads from YAML file; falls back to development defaults when file
is absent/invalid.
func InitLog(logConfFile string) error {
if logConfFile == "" {
InitLogger(nil)
@@ -83,8 +97,7 @@ func InitLog(logConfFile string) error {
}
conf := &zap.Config{}
- err = yaml.UnmarshalYML(confFileStream, conf)
- if err != nil {
+ if err := yaml.UnmarshalYML(confFileStream, conf); err != nil {
InitLogger(nil)
return perrors.New(fmt.Sprintf("[Unmarshal]init pixiuLogger
error: %v", err))
}
@@ -94,10 +107,18 @@ func InitLog(logConfFile string) error {
return nil
}
+// InitLogger initializes logger. Default is development-style (console,
debug),
+// but we force stacktrace to Error+ only, and enable caller with our custom
encoder.
+// If a config is supplied, we respect it and only normalize caller encoder
and stacktrace threshold.
func InitLogger(conf *zap.Config) {
- var zapLoggerConfig zap.Config
+ var (
+ cfg zap.Config
+ )
+
if conf == nil {
- zapLoggerConfig = zap.NewDevelopmentConfig()
+ // Default: development style
+ cfg = zap.NewDevelopmentConfig()
+
zapLoggerEncoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
@@ -111,28 +132,57 @@ func InitLogger(conf *zap.Config) {
EncodeCaller: PaddedCallerEncoder,
// EncodeCaller: zapcore.ShortCallerEncoder,
}
- zapLoggerConfig.EncoderConfig = zapLoggerEncoderConfig
+
+ cfg.EncoderConfig = zapLoggerEncoderConfig
} else {
- zapLoggerConfig = *conf
- // Set up a custom encoder directly without checking the
original value
- zapLoggerConfig.EncoderConfig.EncodeCaller = PaddedCallerEncoder
+ cfg = *conf
+ // Unify caller encoder regardless of YAML to keep alignment
style
+ cfg.EncoderConfig.EncodeCaller = PaddedCallerEncoder
}
- zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(2))
- l := &pixiuLogger{zapLogger.Sugar(), &zapLoggerConfig}
+ z, err := buildWithPixiuOptions(&cfg)
+ if err != nil {
+ z = zap.NewNop()
+ }
+ l := &PixiuLogger{z.Sugar(), &cfg}
control.updateLogger(l)
}
-// SetLoggerLevel safely changes the log level in a concurrent manner.
-func SetLoggerLevel(level string) bool {
+// SetLoggerLevel changes the level at runtime without rebuilding logger.
+func SetLoggerLevel(level zapcore.Level) bool {
return control.setLoggerLevel(level)
}
+// HotReload rebuilds from a new zap.Config (e.g., re-read YAML).
func HotReload(conf *zap.Config) error {
InitLogger(conf)
return nil
}
-func GetLogger() *pixiuLogger {
+// GetLogger exposes the current sugared logger.
+func GetLogger() *PixiuLogger {
return control.logger
}
+
+// ParseLogLevel parses textual level to zapcore.Level.
+func ParseLogLevel(level string) zapcore.Level {
+ switch strings.ToLower(strings.TrimSpace(level)) {
+ case "debug", "trace":
+ return zapcore.DebugLevel
+ case "info":
+ return zapcore.InfoLevel
+ case "warn", "warning":
+ return zapcore.WarnLevel
+ case "error":
+ return zapcore.ErrorLevel
+ case "dpanic":
+ return zapcore.DPanicLevel
+ case "panic":
+ return zapcore.PanicLevel
+ case "fatal", "critical":
+ return zapcore.FatalLevel
+ default:
+ Warnf("unknown log level %q, defaulting to info", level)
+ return zapcore.InfoLevel
+ }
+}
diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go
index 561cc4d7..ce7fb21e 100644
--- a/pkg/logger/logger_test.go
+++ b/pkg/logger/logger_test.go
@@ -18,66 +18,198 @@
package logger
import (
- "fmt"
+ "os"
"path/filepath"
- "runtime"
+ "strings"
"testing"
+ "time"
)
import (
- "github.com/stretchr/testify/assert"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
)
-func TestInitLog(t *testing.T) {
- var (
- err error
- path string
+func newDevConfigToFile(t *testing.T) (*zap.Config, string) {
+ t.Helper()
+ dir := t.TempDir()
+ out := filepath.Join(dir, "zap.log")
+
+ cfg := zap.NewDevelopmentConfig()
+ // output to a temp file
+ cfg.OutputPaths = []string{out}
+ cfg.ErrorOutputPaths = []string{out}
+ cfg.EncoderConfig.StacktraceKey = "stacktrace"
+ cfg.EncoderConfig.CallerKey = "caller"
+
+ return &cfg, out
+}
+
+func readAll(t *testing.T, path string) string {
+ t.Helper()
+ b, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("read %s failed: %v", path, err)
+ }
+ return string(b)
+}
+
+func TestDisableStacktraceTrueNoStackEvenOnError(t *testing.T) {
+ cfg, out := newDevConfigToFile(t)
+ cfg.DisableStacktrace = true // YAML equivalent: disableStacktrace: true
+ InitLogger(cfg)
+
+ log := GetLogger()
+ log.Error("boom")
+ _ = log.Sync()
+
+ got := readAll(t, out)
+ line := ""
+ for _, l := range strings.Split(got, "\n") {
+ if strings.Contains(l, "boom") {
+ line = l
+ break
+ }
+ }
+ if line == "" {
+ t.Fatalf("error line not found")
+ }
+ if strings.Contains(strings.ToLower(line), "stacktrace") {
+ t.Fatalf("disableStacktrace=true: must NOT output stacktrace,
got:\n%s", line)
+ }
+}
+
+func TestSetLoggerLevelDoesNotRebuildAndTakesEffect(t *testing.T) {
+ cfg, out := newDevConfigToFile(t)
+ InitLogger(cfg)
+
+ before := GetLogger().SugaredLogger
+
+ // dynamic set to error
+ ok := SetLoggerLevel(zapcore.ErrorLevel)
+ if !ok {
+ t.Fatalf("SetLoggerLevel returned false")
+ }
+
+ after := GetLogger().SugaredLogger
+ if before != after {
+ t.Fatalf("SetLoggerLevel should NOT rebuild logger; pointer
changed: %p -> %p", before, after)
+ }
+
+ // write new: info should not appear, error should appear
+ log := GetLogger()
+ log.Info("info should be filtered")
+ log.Error("error should appear")
+ _ = log.Sync()
+
+ got := readAll(t, out)
+ if strings.Contains(got, "info should be filtered") {
+ t.Fatalf("info should NOT appear after level set to
error:\n%s", got)
+ }
+ if !strings.Contains(got, "error should appear") {
+ t.Fatalf("error should appear but not found:\n%s", got)
+ }
+}
+
+func TestHotReloadRebuildsAndSwitchesSink(t *testing.T) {
+ // cfg1 -> out1
+ cfg1, out1 := newDevConfigToFile(t)
+ InitLogger(cfg1)
+ l1 := GetLogger().SugaredLogger
+
+ const (
+ H1 = "hello-1"
+ H2 = "hello-2"
)
- err = InitLog("")
- assert.EqualError(t, err, "log configure file name is nil")
-
- path, err = filepath.Abs("./log.xml")
- assert.NoError(t, err)
- err = InitLog(path)
- assert.EqualError(t, err, "log configure file name "+path+" suffix must
be .yml")
-
- path, err = filepath.Abs("./logger.yml")
- assert.NoError(t, err)
- err = InitLog(path)
- var errMsg string
- if runtime.GOOS == "windows" {
- errMsg = fmt.Sprintf("open %s: The system cannot find the file
specified.", path)
- } else {
- errMsg = fmt.Sprintf("open %s: no such file or directory", path)
+ GetLogger().Info(H1)
+ _ = GetLogger().Sync()
+
+ // cfg2 -> out2(new sink)
+ cfg2, out2 := newDevConfigToFile(t)
+ // to split it, set level to info
+ HotReload(cfg2)
+ l2 := GetLogger().SugaredLogger
+
+ if l1 == l2 {
+ t.Fatalf("HotReload should rebuild logger; got same pointer
%p", l1)
+ }
+
+ GetLogger().Info(H2)
+ _ = GetLogger().Sync()
+
+ got1 := readAll(t, out1)
+ got2 := readAll(t, out2)
+
+ if !strings.Contains(got1, H1) {
+ t.Fatalf("out1 should contain hello-1 but not found:\n%s", got1)
+ }
+ if strings.Contains(got1, H2) {
+ t.Fatalf("out1 should NOT contain hello-2 after reload:\n%s",
got1)
+ }
+ if !strings.Contains(got2, H2) {
+ t.Fatalf("out2 should contain hello-2 but not found:\n%s", got2)
}
- assert.EqualError(t, err, fmt.Sprintf("os.ReadFile file:%s, error:%s",
path, errMsg))
-
- err = InitLog("./log.yml")
- assert.NoError(t, err)
-
- Debug("debug")
- Info("info")
- Warn("warn")
- Error("error")
- Debugf("%s", "debug")
- Infof("%s", "info")
- Warnf("%s", "warn")
- Errorf("%s", "error")
}
-func TestSetLoggerLevel(t *testing.T) {
- assert.NotNil(t, control, "control should not be nil")
+func TestPaddedCallerEncoderFixedWidthAtLeast30(t *testing.T) {
+ caller := zapcore.EntryCaller{
+ Defined: true,
+ File: "a/b/c.go",
+ Line: 7,
+ }
+ collector := &stringCollector{}
+ PaddedCallerEncoder(caller, collector)
+
+ if len(collector.items) == 0 {
+ t.Fatalf("collector got no items")
+ }
+ got := collector.items[0]
+ if len(got) < 30 {
+ t.Fatalf("caller not padded to >=30, got len=%d val=%q",
len(got), got)
+ }
+}
- assert.True(t, SetLoggerLevel("info"), "when pass info to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("debug"), "when pass debug to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("error"), "when pass error to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("panic"), "when pass panic to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("INFO"), "when pass INFO to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("DEbug"), "when pass DEbug to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("ErRor"), "when pass ErRor to
SetLoggerLevel, result should be true")
- assert.True(t, SetLoggerLevel("WaRN"), "when pass WaRN to
SetLoggerLevel, result should be true")
+// -------------------------- helpers --------------------------
- assert.False(t, SetLoggerLevel("i"), "when pass i to SetLoggerLevel,
result should be false")
- assert.False(t, SetLoggerLevel(""), "when pass nothing to
SetLoggerLevel, result should be false")
+type stringCollector struct {
+ items []string
}
+
+// mock zapcore.PrimitiveArrayEncoder
+func (s *stringCollector) AppendString(v string) { s.items = append(s.items,
v) }
+
+func (s *stringCollector) AppendBool(bool) { /*mock*/ }
+func (s *stringCollector) AppendByteString([]byte) { /*mock*/ }
+func (s *stringCollector) AppendComplex128(complex128) { /*mock*/ }
+func (s *stringCollector) AppendComplex64(complex64) { /*mock*/ }
+func (s *stringCollector) AppendDuration(time.Duration) { /*mock*/ }
+func (s *stringCollector) AppendFloat64(float64) { /*mock*/ }
+func (s *stringCollector) AppendFloat32(float32) { /*mock*/ }
+func (s *stringCollector) AppendInt(int) { /*mock*/ }
+func (s *stringCollector) AppendInt64(int64) { /*mock*/ }
+func (s *stringCollector) AppendInt32(int32) { /*mock*/ }
+func (s *stringCollector) AppendInt16(int16) { /*mock*/ }
+func (s *stringCollector) AppendInt8(int8) { /*mock*/ }
+func (s *stringCollector) AppendTime(time.Time) { /*mock*/ }
+func (s *stringCollector) AppendUint(uint) { /*mock*/ }
+func (s *stringCollector) AppendUint64(uint64) { /*mock*/ }
+func (s *stringCollector) AppendUint32(uint32) { /*mock*/ }
+func (s *stringCollector) AppendUint16(uint16) { /*mock*/ }
+func (s *stringCollector) AppendUint8(uint8) { /*mock*/ }
+func (s *stringCollector) AppendUintptr(uintptr) { /*mock*/ }
+func (s *stringCollector) AppendReflected(any) { /*mock*/ }
+func (s *stringCollector) AppendArray(zapcore.ArrayMarshaler) { /*mock*/ }
+func (s *stringCollector) AppendObject(zapcore.ObjectMarshaler) { /*mock*/ }
+func (s *stringCollector) AppendBinary([]byte) { /*mock*/ }
+func (s *stringCollector) AppendComplex(complex128) { /*mock*/ }
+func (s *stringCollector) AppendDurationRef(time.Duration) { /*mock*/ }
+func (s *stringCollector) AppendTimeLayout(time.Time, string) { /*mock*/ }
+func (s *stringCollector) AppendIP(ip any) { /*mock*/ }
+func (s *stringCollector) AppendIPNet(net any) { /*mock*/ }
+func (s *stringCollector) AppendMAC(mac any) { /*mock*/ }
+func (s *stringCollector) AppendHex(any) { /*mock*/ }
+func (s *stringCollector) AppendFloat(any) { /*mock*/ }
+func (s *stringCollector) Cap() int { return 0 }
+func (s *stringCollector) Len() int { return
len(s.items) }
+func (s *stringCollector) Truncate(int) { /*mock*/ }