diff --git a/common/logger/file_log.yml b/common/logger/file_log.yml new file mode 100644 index 0000000000..75cc32c7ea --- /dev/null +++ b/common/logger/file_log.yml @@ -0,0 +1,36 @@ +lumberjackConfig: + filename: "logs.log" + maxSize: 1 + maxAge: 3 + maxBackups: 5 + localTime: true + compress: false + +zapConfig: + level: "debug" + development: false + disableCaller: false + disableStacktrace: false + sampling: + encoding: "console" + + # encoder + encoderConfig: + messageKey: "message" + levelKey: "level" + timeKey: "time" + nameKey: "logger" + callerKey: "caller" + stacktraceKey: "stacktrace" + lineEnding: "" + levelEncoder: "capitalColor" + timeEncoder: "iso8601" + durationEncoder: "seconds" + callerEncoder: "short" + nameEncoder: "" + + outputPaths: + - "stderr" + errorOutputPaths: + - "stderr" + initialFields: diff --git a/common/logger/logger.go b/common/logger/logger.go index 0aa741050b..140f56fc3f 100644 --- a/common/logger/logger.go +++ b/common/logger/logger.go @@ -26,6 +26,7 @@ import ( import ( "github.com/apache/dubbo-getty" + "github.com/natefinch/lumberjack" perrors "github.com/pkg/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -44,6 +45,11 @@ type DubboLogger struct { dynamicLevel zap.AtomicLevel } +type Config struct { + LumberjackConfig *lumberjack.Logger `yaml:"lumberjackConfig"` + ZapConfig *zap.Config `yaml:"zapConfig"` +} + // Logger is the interface for Logger types type Logger interface { Info(args ...interface{}) @@ -95,7 +101,7 @@ func InitLog(logConfFile string) error { return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", logConfFile, err) } - conf := &zap.Config{} + conf := &Config{} err = yaml.Unmarshal(confFileStream, conf) if err != nil { InitLogger(nil) @@ -108,9 +114,12 @@ func InitLog(logConfFile string) error { } // InitLogger use for init logger by @conf -func InitLogger(conf *zap.Config) { - var zapLoggerConfig zap.Config - if conf == nil { +func InitLogger(conf *Config) { + var ( + zapLogger *zap.Logger + config = &Config{} + ) + if conf == nil || conf.ZapConfig == nil { zapLoggerEncoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", @@ -123,7 +132,7 @@ func InitLogger(conf *zap.Config) { EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } - zapLoggerConfig = zap.Config{ + config.ZapConfig = &zap.Config{ Level: zap.NewAtomicLevelAt(zap.DebugLevel), Development: false, Encoding: "console", @@ -132,10 +141,17 @@ func InitLogger(conf *zap.Config) { ErrorOutputPaths: []string{"stderr"}, } } else { - zapLoggerConfig = *conf + config.ZapConfig = conf.ZapConfig + } + + if conf == nil || conf.LumberjackConfig == nil { + zapLogger, _ = config.ZapConfig.Build(zap.AddCallerSkip(1)) + } else { + config.LumberjackConfig = conf.LumberjackConfig + zapLogger = initZapLoggerWithSyncer(config) } - zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(1)) - logger = &DubboLogger{Logger: zapLogger.Sugar(), dynamicLevel: zapLoggerConfig.Level} + + logger = &DubboLogger{Logger: zapLogger.Sugar(), dynamicLevel: config.ZapConfig.Level} // set getty log getty.SetLogger(logger) @@ -174,3 +190,29 @@ func (dl *DubboLogger) SetLoggerLevel(level string) { dl.dynamicLevel.SetLevel(*l) } } + +// initZapLoggerWithSyncer init zap Logger with syncer +func initZapLoggerWithSyncer(conf *Config) *zap.Logger { + core := zapcore.NewCore( + conf.getEncoder(), + conf.getLogWriter(), + zap.NewAtomicLevelAt(zap.DebugLevel), + ) + + return zap.New(core, zap.AddCallerSkip(1)) +} + +// getEncoder get encoder by config, zapcore support json and console encoder +func (c *Config) getEncoder() zapcore.Encoder { + if c.ZapConfig.Encoding == "json" { + return zapcore.NewJSONEncoder(c.ZapConfig.EncoderConfig) + } else if c.ZapConfig.Encoding == "console" { + return zapcore.NewConsoleEncoder(c.ZapConfig.EncoderConfig) + } + return nil +} + +// getLogWriter get Lumberjack writer by LumberjackConfig +func (c *Config) getLogWriter() zapcore.WriteSyncer { + return zapcore.AddSync(c.LumberjackConfig) +} diff --git a/common/logger/logger_test.go b/common/logger/logger_test.go index 6081f71aec..12d1ab8d29 100644 --- a/common/logger/logger_test.go +++ b/common/logger/logger_test.go @@ -81,3 +81,57 @@ func TestSetLevel(t *testing.T) { Debug("debug") Info("info") } + +func TestInitLogWidthFile(t *testing.T) { + var ( + err error + path string + ) + + err = InitLog("") + assert.EqualError(t, err, "log configure file name is nil") + + path, err = filepath.Abs("./file_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) + } + assert.EqualError(t, err, fmt.Sprintf("ioutil.ReadFile(file:%s) = error:%s", path, errMsg)) + + err = InitLog("./file_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 TestSetLevelWidthFile(t *testing.T) { + err := InitLog("./file_log.yml") + assert.NoError(t, err) + Debug("debug") + Info("info") + + assert.True(t, SetLoggerLevel("info")) + Debug("debug") + Info("info") + + SetLogger(GetLogger().(*DubboLogger).Logger) + assert.False(t, SetLoggerLevel("debug")) + Debug("debug") + Info("info") +} diff --git a/go.mod b/go.mod index 853ffe9279..df90a91994 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/nacos-group/nacos-sdk-go v1.0.8 + github.com/natefinch/lumberjack v2.0.0+incompatible github.com/opentracing/opentracing-go v1.2.0 github.com/pierrec/lz4 v2.2.6+incompatible // indirect github.com/pkg/errors v0.9.1 @@ -48,4 +49,5 @@ require ( k8s.io/apimachinery v0.16.9 k8s.io/client-go v0.16.9 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect ) diff --git a/go.sum b/go.sum index b1202a9666..f5b52ba73e 100644 --- a/go.sum +++ b/go.sum @@ -435,6 +435,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nacos-group/nacos-sdk-go v1.0.8 h1:8pEm05Cdav9sQgJSv5kyvlgfz0SzFUUGI3pWX6SiSnM= github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= @@ -912,6 +914,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=