-
Notifications
You must be signed in to change notification settings - Fork 0
/
rotate_file.go
104 lines (85 loc) · 1.86 KB
/
rotate_file.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
package logh
import (
"fmt"
"os"
"time"
)
type RotateFile struct {
filepath string
file *os.File
rotateSize int
rotateInterval time.Duration
checkEveryN int
written int
lastRotate time.Time
count int
}
func NewRotateFile(directory string, basename string, rotateSize int, opts ...Option) (*RotateFile, error) {
err := os.MkdirAll(directory, 0o755)
if err != nil {
return nil, err
}
rf := &RotateFile{
filepath: directory + "/" + basename,
rotateSize: rotateSize,
rotateInterval: time.Hour * 24,
checkEveryN: 1024,
}
for _, opt := range opts {
if opt != nil {
opt(rf)
}
}
rf.rotate()
return rf, nil
}
func (r *RotateFile) Write(p []byte) (int, error) {
n, err := r.file.Write(p)
r.written += n
if r.written > r.rotateSize {
r.rotate()
} else {
r.count++
if r.count >= r.checkEveryN {
r.count = 0
if time.Now().After(r.lastRotate.Add(r.rotateInterval)) {
r.rotate()
}
}
}
return n, err
}
func (r *RotateFile) logFileName() (string, time.Time) {
hostname, err := os.Hostname()
if err != nil {
hostname = "unknownhost"
}
now := time.Now()
return r.filepath + "." + now.Format("20060102-150405.000000000") + "." + hostname + "." + fmt.Sprint(os.Getpid()) + ".log", now
}
func (r *RotateFile) rotate() {
filename, now := r.logFileName()
if now.After(r.lastRotate) {
file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
if err != nil {
panic(fmt.Sprintf("Failed to open log file %s: %s", filename, err))
}
if r.file != nil {
// TODO: error handling?
r.file.Close()
}
r.file = file
r.lastRotate = now
}
}
type Option func(*RotateFile)
func WithCheckEveryN(n int) Option {
return func(r *RotateFile) {
r.checkEveryN = n
}
}
func WithRotateInterval(d time.Duration) Option {
return func(r *RotateFile) {
r.rotateInterval = d
}
}