Skip to content

Commit 817a884

Browse files
authored
Allow to send logs to the file with the rotation (#270)
1 parent 0032e54 commit 817a884

File tree

9 files changed

+137
-3
lines changed

9 files changed

+137
-3
lines changed

cmd/server/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ func handleSignals(sig os.Signal) (exitNow bool) {
6565
}
6666

6767
func main() {
68+
defer logger.Sync()
69+
6870
ctx, cancelFn := context.WithCancel(context.Background())
6971
// os signal handler
7072
shutdownCh := make(chan struct{})
@@ -92,6 +94,15 @@ func main() {
9294
logger.Get().With(zap.Error(err)).Error("Failed to validate the config file")
9395
return
9496
}
97+
98+
if cfg.Log != nil && cfg.Log.Filename != "" {
99+
logger.Get().Info("Logs will be saved to " + cfg.Log.Filename)
100+
if err := logger.InitLoggerRotate(cfg.Log.Level, cfg.Log.Filename, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.MaxSize, cfg.Log.Compress); err != nil {
101+
logger.Get().With(zap.Error(err)).Error("Failed to init the log rotate")
102+
return
103+
}
104+
}
105+
95106
srv, err := server.NewServer(cfg)
96107
if err != nil {
97108
logger.Get().With(zap.Error(err)).Error("Failed to create the server")

config/config-consul.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,13 @@ consul:
3939
controller:
4040
failover:
4141
ping_interval_seconds: 3
42-
min_alive_size: 5
42+
min_alive_size: 5
43+
44+
# Uncomment this part to save logs to filename instead of stdout
45+
#log:
46+
# level: info
47+
# filename: /data/logs/kvctl.log
48+
# max_backups: 10
49+
# max_age: 7
50+
# max_size: 100
51+
# compress: false

config/config-raft.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,12 @@ controller:
4242
failover:
4343
ping_interval_seconds: 3
4444
min_alive_size: 5
45+
46+
# Uncomment this part to save logs to filename instead of stdout
47+
#log:
48+
# level: info
49+
# filename: /data/logs/kvctl.log
50+
# max_backups: 10
51+
# max_age: 7
52+
# max_size: 100
53+
# compress: false

config/config-zk.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,13 @@ zookeeper:
3636
controller:
3737
failover:
3838
ping_interval_seconds: 3
39-
min_alive_size: 5
39+
min_alive_size: 5
40+
41+
# Uncomment this part to save logs to filename instead of stdout
42+
#log:
43+
# level: info
44+
# filename: /data/logs/kvctl.log
45+
# max_backups: 10
46+
# max_age: 7
47+
# max_size: 100
48+
# compress: false

config/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ type ControllerConfig struct {
4949
FailOver *FailOverConfig `yaml:"failover"`
5050
}
5151

52+
type LogConfig struct {
53+
Level string `yaml:"level"`
54+
Filename string `yaml:"filename"`
55+
MaxBackups int `yaml:"max_backups"`
56+
MaxAge int `yaml:"max_age"`
57+
MaxSize int `yaml:"max_size"`
58+
Compress bool `yaml:"compress"`
59+
}
60+
5261
const defaultPort = 9379
5362

5463
type Config struct {
@@ -60,6 +69,7 @@ type Config struct {
6069
Consul *consul.Config `yaml:"consul"`
6170
Admin AdminConfig `yaml:"admin"`
6271
Controller *ControllerConfig `yaml:"controller"`
72+
Log *LogConfig `yaml:"log"`
6373
}
6474

6575
func DefaultFailOverConfig() *FailOverConfig {

config/config.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,13 @@ etcd:
4141
controller:
4242
failover:
4343
ping_interval_seconds: 3
44-
min_alive_size: 5
44+
min_alive_size: 5
45+
46+
# Uncomment this part to save logs to filename instead of stdout
47+
#log:
48+
# level: info
49+
# filename: /data/logs/kvctl.log
50+
# max_backups: 10
51+
# max_age: 7
52+
# max_size: 100
53+
# compress: false

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ require (
2222
go.etcd.io/etcd/raft/v3 v3.5.18
2323
go.etcd.io/etcd/server/v3 v3.5.18
2424
go.uber.org/zap v1.27.0
25+
gopkg.in/natefinch/lumberjack.v2 v2.0.0
2526
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
2627
)
2728

29+
require github.com/BurntSushi/toml v1.4.0 // indirect
30+
2831
require (
2932
github.com/armon/go-metrics v0.4.1 // indirect
3033
github.com/beorn7/perks v1.0.1 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2+
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
3+
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
24
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
35
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
46
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
423425
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
424426
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
425427
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
428+
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
429+
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
426430
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
427431
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
428432
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=

logger/logger.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
package logger
2121

2222
import (
23+
"fmt"
24+
2325
"go.uber.org/zap"
2426
"go.uber.org/zap/zapcore"
27+
"gopkg.in/natefinch/lumberjack.v2"
2528
)
2629

2730
var zapLogger *zap.Logger
@@ -36,3 +39,70 @@ func init() {
3639
zapConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
3740
zapLogger, _ = zapConfig.Build()
3841
}
42+
43+
func getEncoder() zapcore.Encoder {
44+
encoderConfig := zap.NewProductionEncoderConfig()
45+
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
46+
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
47+
encoderConfig.TimeKey = "time"
48+
49+
return zapcore.NewJSONEncoder(encoderConfig)
50+
}
51+
52+
func getWriteSyncer(filename string, maxBackups, maxAge, maxSize int, compress bool) (zapcore.WriteSyncer, error) {
53+
lumberJackLogger := &lumberjack.Logger{
54+
Filename: filename,
55+
MaxBackups: maxBackups,
56+
MaxSize: maxSize,
57+
MaxAge: maxAge,
58+
Compress: compress,
59+
}
60+
61+
if _, err := lumberJackLogger.Write([]byte("test logfile writable\r\n")); err != nil {
62+
return nil, fmt.Errorf("test writing to log file %s failed", filename)
63+
}
64+
65+
return zapcore.AddSync(lumberJackLogger), nil
66+
}
67+
68+
func InitLoggerRotate(level, filename string, maxBackups, maxAge, maxSize int, compress bool) error {
69+
// if file path is empty, use default zapLogger, print in console
70+
if len(filename) == 0 {
71+
return nil
72+
}
73+
if level != "info" && level != "warn" && level != "error" {
74+
return fmt.Errorf("log level must be one of info,warn,error")
75+
}
76+
if maxBackups > 100 || maxBackups < 10 {
77+
return fmt.Errorf("log max_backups must be between 10 and 100")
78+
}
79+
if maxAge > 30 || maxAge < 1 {
80+
return fmt.Errorf("log max_age must be between 1 and 30")
81+
}
82+
if maxSize > 500 || maxSize < 100 {
83+
return fmt.Errorf("log max_size must be between 100 and 500")
84+
}
85+
86+
var l = new(zapcore.Level)
87+
if err := l.UnmarshalText([]byte(level)); err != nil {
88+
return err
89+
}
90+
encoder := getEncoder()
91+
writeSync, err := getWriteSyncer(filename, maxBackups, maxAge, maxSize, compress)
92+
if err != nil {
93+
return err
94+
}
95+
core := zapcore.NewCore(encoder, writeSync, l)
96+
rotateLogger := zap.New(core, zap.AddCaller())
97+
zapLogger = rotateLogger
98+
99+
return nil
100+
}
101+
102+
func Sync() {
103+
if zapLogger != nil {
104+
if err := zapLogger.Sync(); err != nil {
105+
return
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)