This is an automated email from the ASF dual-hosted git repository.
hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks-controller.git
The following commit(s) were added to refs/heads/unstable by this push:
new 817a884 Allow to send logs to the file with the rotation (#270)
817a884 is described below
commit 817a884ca679f1a8f0e6c73fbfc5f474ecf25480
Author: Raphael <[email protected]>
AuthorDate: Sun Mar 2 22:55:15 2025 +0800
Allow to send logs to the file with the rotation (#270)
---
cmd/server/main.go | 11 ++++++++
config/config-consul.yaml | 11 +++++++-
config/config-raft.yaml | 9 ++++++
config/config-zk.yaml | 11 +++++++-
config/config.go | 10 +++++++
config/config.yaml | 11 +++++++-
go.mod | 3 ++
go.sum | 4 +++
logger/logger.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 137 insertions(+), 3 deletions(-)
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 614f184..080aae4 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -65,6 +65,8 @@ func handleSignals(sig os.Signal) (exitNow bool) {
}
func main() {
+ defer logger.Sync()
+
ctx, cancelFn := context.WithCancel(context.Background())
// os signal handler
shutdownCh := make(chan struct{})
@@ -92,6 +94,15 @@ func main() {
logger.Get().With(zap.Error(err)).Error("Failed to validate the
config file")
return
}
+
+ if cfg.Log != nil && cfg.Log.Filename != "" {
+ logger.Get().Info("Logs will be saved to " + cfg.Log.Filename)
+ if err := logger.InitLoggerRotate(cfg.Log.Level,
cfg.Log.Filename, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.MaxSize,
cfg.Log.Compress); err != nil {
+ logger.Get().With(zap.Error(err)).Error("Failed to init
the log rotate")
+ return
+ }
+ }
+
srv, err := server.NewServer(cfg)
if err != nil {
logger.Get().With(zap.Error(err)).Error("Failed to create the
server")
diff --git a/config/config-consul.yaml b/config/config-consul.yaml
index 3315721..b457cc5 100644
--- a/config/config-consul.yaml
+++ b/config/config-consul.yaml
@@ -39,4 +39,13 @@ consul:
controller:
failover:
ping_interval_seconds: 3
- min_alive_size: 5
\ No newline at end of file
+ min_alive_size: 5
+
+# Uncomment this part to save logs to filename instead of stdout
+#log:
+# level: info
+# filename: /data/logs/kvctl.log
+# max_backups: 10
+# max_age: 7
+# max_size: 100
+# compress: false
\ No newline at end of file
diff --git a/config/config-raft.yaml b/config/config-raft.yaml
index 0ba300f..3f1bb34 100644
--- a/config/config-raft.yaml
+++ b/config/config-raft.yaml
@@ -42,3 +42,12 @@ controller:
failover:
ping_interval_seconds: 3
min_alive_size: 5
+
+# Uncomment this part to save logs to filename instead of stdout
+#log:
+# level: info
+# filename: /data/logs/kvctl.log
+# max_backups: 10
+# max_age: 7
+# max_size: 100
+# compress: false
\ No newline at end of file
diff --git a/config/config-zk.yaml b/config/config-zk.yaml
index ee54655..1870b23 100644
--- a/config/config-zk.yaml
+++ b/config/config-zk.yaml
@@ -36,4 +36,13 @@ zookeeper:
controller:
failover:
ping_interval_seconds: 3
- min_alive_size: 5
\ No newline at end of file
+ min_alive_size: 5
+
+# Uncomment this part to save logs to filename instead of stdout
+#log:
+# level: info
+# filename: /data/logs/kvctl.log
+# max_backups: 10
+# max_age: 7
+# max_size: 100
+# compress: false
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
index 6c80312..69558fb 100644
--- a/config/config.go
+++ b/config/config.go
@@ -49,6 +49,15 @@ type ControllerConfig struct {
FailOver *FailOverConfig `yaml:"failover"`
}
+type LogConfig struct {
+ Level string `yaml:"level"`
+ Filename string `yaml:"filename"`
+ MaxBackups int `yaml:"max_backups"`
+ MaxAge int `yaml:"max_age"`
+ MaxSize int `yaml:"max_size"`
+ Compress bool `yaml:"compress"`
+}
+
const defaultPort = 9379
type Config struct {
@@ -60,6 +69,7 @@ type Config struct {
Consul *consul.Config `yaml:"consul"`
Admin AdminConfig `yaml:"admin"`
Controller *ControllerConfig `yaml:"controller"`
+ Log *LogConfig `yaml:"log"`
}
func DefaultFailOverConfig() *FailOverConfig {
diff --git a/config/config.yaml b/config/config.yaml
index 3877ecf..c3cfb0b 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -41,4 +41,13 @@ etcd:
controller:
failover:
ping_interval_seconds: 3
- min_alive_size: 5
\ No newline at end of file
+ min_alive_size: 5
+
+# Uncomment this part to save logs to filename instead of stdout
+#log:
+# level: info
+# filename: /data/logs/kvctl.log
+# max_backups: 10
+# max_age: 7
+# max_size: 100
+# compress: false
\ No newline at end of file
diff --git a/go.mod b/go.mod
index fb5d32c..b45115f 100644
--- a/go.mod
+++ b/go.mod
@@ -22,9 +22,12 @@ require (
go.etcd.io/etcd/raft/v3 v3.5.18
go.etcd.io/etcd/server/v3 v3.5.18
go.uber.org/zap v1.27.0
+ gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
)
+require github.com/BurntSushi/toml v1.4.0 // indirect
+
require (
github.com/armon/go-metrics v0.4.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
diff --git a/go.sum b/go.sum
index add17ec..6023ada 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,6 @@
cloud.google.com/go v0.34.0/go.mod
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v1.4.0
h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod
h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod
h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod
h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -423,6 +425,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod
h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
diff --git a/logger/logger.go b/logger/logger.go
index 9bd844f..437dfa6 100644
--- a/logger/logger.go
+++ b/logger/logger.go
@@ -20,8 +20,11 @@
package logger
import (
+ "fmt"
+
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
+ "gopkg.in/natefinch/lumberjack.v2"
)
var zapLogger *zap.Logger
@@ -36,3 +39,70 @@ func init() {
zapConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
zapLogger, _ = zapConfig.Build()
}
+
+func getEncoder() zapcore.Encoder {
+ encoderConfig := zap.NewProductionEncoderConfig()
+ encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
+ encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
+ encoderConfig.TimeKey = "time"
+
+ return zapcore.NewJSONEncoder(encoderConfig)
+}
+
+func getWriteSyncer(filename string, maxBackups, maxAge, maxSize int, compress
bool) (zapcore.WriteSyncer, error) {
+ lumberJackLogger := &lumberjack.Logger{
+ Filename: filename,
+ MaxBackups: maxBackups,
+ MaxSize: maxSize,
+ MaxAge: maxAge,
+ Compress: compress,
+ }
+
+ if _, err := lumberJackLogger.Write([]byte("test logfile
writable\r\n")); err != nil {
+ return nil, fmt.Errorf("test writing to log file %s failed",
filename)
+ }
+
+ return zapcore.AddSync(lumberJackLogger), nil
+}
+
+func InitLoggerRotate(level, filename string, maxBackups, maxAge, maxSize int,
compress bool) error {
+ // if file path is empty, use default zapLogger, print in console
+ if len(filename) == 0 {
+ return nil
+ }
+ if level != "info" && level != "warn" && level != "error" {
+ return fmt.Errorf("log level must be one of info,warn,error")
+ }
+ if maxBackups > 100 || maxBackups < 10 {
+ return fmt.Errorf("log max_backups must be between 10 and 100")
+ }
+ if maxAge > 30 || maxAge < 1 {
+ return fmt.Errorf("log max_age must be between 1 and 30")
+ }
+ if maxSize > 500 || maxSize < 100 {
+ return fmt.Errorf("log max_size must be between 100 and 500")
+ }
+
+ var l = new(zapcore.Level)
+ if err := l.UnmarshalText([]byte(level)); err != nil {
+ return err
+ }
+ encoder := getEncoder()
+ writeSync, err := getWriteSyncer(filename, maxBackups, maxAge, maxSize,
compress)
+ if err != nil {
+ return err
+ }
+ core := zapcore.NewCore(encoder, writeSync, l)
+ rotateLogger := zap.New(core, zap.AddCaller())
+ zapLogger = rotateLogger
+
+ return nil
+}
+
+func Sync() {
+ if zapLogger != nil {
+ if err := zapLogger.Sync(); err != nil {
+ return
+ }
+ }
+}