-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathsize_rotator.go
97 lines (85 loc) · 2.2 KB
/
size_rotator.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
package rotator
import (
"errors"
"os"
"strconv"
"sync"
)
const (
defaultRotationSize = 1024 * 1024 * 10
defaultMaxRotation = 999
)
// SizeRotator is file writer which rotates files by size
type SizeRotator struct {
path string // base file path
totalSize int64 // current file size
file *os.File // current file
mutex sync.Mutex // lock
RotationSize int64 // size threshold of the rotation
MaxRotation int // maximum count of the rotation
}
// Write bytes to the file. If binaries exceeds rotation threshold,
// it will automatically rotate the file.
func (r *SizeRotator) Write(bytes []byte) (n int, err error) {
r.mutex.Lock()
defer r.mutex.Unlock()
if r.file == nil {
// Check file existence
stat, _ := os.Lstat(r.path)
if stat != nil {
// Update initial size by file size
r.totalSize = stat.Size()
}
}
// Do rotate when size exceeded
if r.totalSize+int64(len(bytes)) > r.RotationSize {
// Get available file name to be rotated
for i := 1; i <= r.MaxRotation; i++ {
renamedPath := r.path + "." + strconv.Itoa(i)
stat, _ := os.Lstat(renamedPath)
if stat == nil {
err := os.Rename(r.path, renamedPath)
if err != nil {
return 0, err
}
if r.file != nil {
// reset file reference
r.file.Close()
r.file = nil
}
break
}
if i == r.MaxRotation {
return 0, errors.New("rotation count has been exceeded")
}
}
}
if r.file == nil {
r.file, err = os.OpenFile(r.path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return 0, err
}
// Switch current date
r.totalSize = 0
}
n, err = r.file.Write(bytes)
r.totalSize += int64(n)
return n, err
}
// WriteString writes strings to the file. If binaries exceeds rotation threshold,
// it will automatically rotate the file.
func (r *SizeRotator) WriteString(str string) (n int, err error) {
return r.Write([]byte(str))
}
// Close the file
func (r *SizeRotator) Close() error {
return r.file.Close()
}
// NewSizeRotator creates new writer of the file
func NewSizeRotator(path string) *SizeRotator {
return &SizeRotator{
path: path,
RotationSize: defaultRotationSize,
MaxRotation: defaultMaxRotation,
}
}