/
rotate_log_hook.go
125 lines (104 loc) · 3.74 KB
/
rotate_log_hook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package xlogrus
import (
"github.com/ah-forklib/rotatelogs"
"github.com/ah-forklib/strftime"
"github.com/sirupsen/logrus"
"io"
"time"
)
// RotateLogConfig represents RotateLogHook's config.
type RotateLogConfig struct {
// Filename represents the log filename without time part and extension, required.
Filename string
// FilenameTimePart represents time part after filename, defaults to ".%Y%m%d.log". See strftime.New.
FilenameTimePart string
// LinkFileName represents the symbolic link filename, defaults to "", no link will be written.
LinkFileName string
// Level represents the lowest log level, defaults to logrus.PanicLevel.
Level logrus.Level
// Formatter represents the logger formatter, defaults to logrus.JSONFormatter.
Formatter logrus.Formatter
// MaxAge represents the max duration of the file, defaults to one week.
MaxAge time.Duration
// MaxSize represents the max size in MB of the file, defaults to no limit.
MaxSize int
// RotationTime represents the rotation duration of the file, defaults to one day.
RotationTime time.Duration
// LocalTime represents the switcher for local or UTC time, defaults to use UTC time.
LocalTime bool
// ForceNewFile represents the switcher for forcing to save to new file, defaults to false.
ForceNewFile bool
}
// RotateLogHook represents a logrus hook for writing logs into files splitting by time.
type RotateLogHook struct {
// config is the rotate config.
config *RotateLogConfig
// writer is the io.Writer for log file rotation.
writer io.Writer
}
const (
panicInvalidTimePattern = "xlogrus: invalid time pattern for filename"
)
// NewRotateLogHook creates a RotateLogHook as logrus.Hook with RotateLogConfig.
// Example:
// hook := NewRotateLogHook(&RotateLogConfig{
// Filename: "console",
// FilenameTimePart: ".%Y%m%d.log",
// LinkFileName: "console.curr.log",
// Level: logrus.WarnLevel,
// Formatter: &logrus.JSONFormatter{TimestampFormat: time.RFC3339},
// MaxAge: time.Hour * 24 * 30,
// MaxSize: 100,
// RotationTime: time.Hour * 24,
// LocalTime: false,
// ForceNewFile: false,
// })
// logger.AddHook(hook)
func NewRotateLogHook(config *RotateLogConfig) logrus.Hook {
if config == nil {
panic(panicNilConfig)
}
if config.Filename == "" {
panic(panicEmptyFilename)
}
if config.Level < logrus.PanicLevel || config.Level > logrus.TraceLevel {
panic(panicInvalidLevel)
}
if config.Formatter == nil {
config.Formatter = &logrus.JSONFormatter{TimestampFormat: time.RFC3339}
}
timePartName := ".%Y%m%d.log" // default time part name
if config.FilenameTimePart != "" {
timePartName = config.FilenameTimePart
}
_, err := strftime.New(timePartName)
if err != nil {
panic(panicInvalidTimePattern)
}
options := []rotatelogs.Option{
rotatelogs.WithLinkName(config.LinkFileName),
rotatelogs.WithMaxAge(config.MaxAge),
rotatelogs.WithRotationSize(int64(float64(config.MaxSize) * 1024 * 1024)), // MB -> B
rotatelogs.WithRotationTime(config.RotationTime),
}
if config.LocalTime {
options = append(options, rotatelogs.WithClock(rotatelogs.Local))
} else {
options = append(options, rotatelogs.WithClock(rotatelogs.UTC))
}
if config.ForceNewFile {
options = append(options, rotatelogs.ForceNewFile())
}
filename := config.Filename + timePartName
writer, _ := rotatelogs.New(filename, options...) // no error
return &RotateLogHook{config: config, writer: writer}
}
func (r *RotateLogHook) Levels() []logrus.Level {
return logrus.AllLevels[:r.config.Level+1]
}
// Fire writes logrus.Entry data to io.Writer, this implements logrus.Hook.
func (r *RotateLogHook) Fire(entry *logrus.Entry) error {
b, _ := r.config.Formatter.Format(entry) // ignore error
_, _ = r.writer.Write(b)
return nil
}