-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathu_rotate_file.go
143 lines (128 loc) · 3.94 KB
/
u_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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package kerbalwzygo
import (
"fmt"
"io/ioutil"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
// Custom rotate file writer.
type RotateFileWriter struct {
fileName string // The file name, but the finally file name would be `<obj.fileName>.<timestamp>`.
dirPath string // The dir path for saving the files.
count int // The count of existed files.
size int64 // The size of the file which is used now.
maxCount int // The max value of the <obj.count>, meaning how much file can be saved totally.
maxSize int64 // Meaning how much bytes data one file can saving.
fp *os.File // The current file object that for writing data
wt sync.Mutex // The lock for operate the 'count'
once sync.Once // Keep initial just one times
}
// Check the target dir if existed which for saving files.
// When the result is false, will create the dir, if error happened there, panic.
func (obj *RotateFileWriter) checkDir() {
info, err := os.Stat(obj.dirPath)
if nil != err || !info.IsDir() {
err := os.Mkdir(obj.dirPath, os.ModePerm)
if nil != err {
panic(err)
}
}
}
// Search the files under the target dir, which matching the target file format.
func (obj *RotateFileWriter) searchExistedFiles() map[int64]string {
fileNameRe := regexp.MustCompile(fmt.Sprintf(`^%s.\d+$`, obj.fileName))
exitedFiles := make(map[int64]string)
files, _ := ioutil.ReadDir(obj.dirPath)
for _, file := range files {
if !file.IsDir() && fileNameRe.MatchString(file.Name()) {
splitSlice := strings.Split(file.Name(), ".")
timestampStr := splitSlice[len(splitSlice)-1]
if timestamp, err := strconv.ParseInt(timestampStr, 10, 64); nil == err {
exitedFiles[timestamp] = file.Name()
}
}
}
return exitedFiles
}
// Initial method, check whether the log dir existed and have history log files
func (obj *RotateFileWriter) Init() {
obj.once.Do(func() {
obj.checkDir()
exitedFiles := obj.searchExistedFiles()
exitedFilesCount := len(exitedFiles)
// check weather have tag files here
if exitedFilesCount > 0 {
// if haven, find the newest one and use it
var newEstLogFile int64
for K := range exitedFiles {
if K > newEstLogFile {
newEstLogFile = K
}
}
fileName := exitedFiles[newEstLogFile]
fp, err := os.OpenFile(obj.dirPath+"/"+fileName, os.O_APPEND|os.O_WRONLY, 0666)
if nil != err {
panic(err)
}
fileInfo, err := fp.Stat()
if nil != err {
panic(err)
}
obj.fp = fp
obj.count = exitedFilesCount
obj.size = fileInfo.Size()
} else {
// if not haven, create one new log file
obj.createNewFile()
}
})
}
func (obj *RotateFileWriter) createNewFile() {
obj.wt.Lock()
defer obj.wt.Unlock()
obj.count++
if obj.count > obj.maxCount {
// if the count is large than maxCount, remove the oldest log file
fileDateNums := make([]int64, 0)
existedFiles := obj.searchExistedFiles()
for k := range existedFiles {
fileDateNums = append(fileDateNums, k)
}
oldEstFile := fileDateNums[0]
for _, item := range fileDateNums {
if item < oldEstFile {
oldEstFile = item
}
}
_ = os.Remove(obj.dirPath + "/" + existedFiles[oldEstFile])
obj.count--
}
timeStamp := time.Now().Unix()
fileName := fmt.Sprintf("%s.%d", obj.fileName, timeStamp)
fp, _ := os.OpenFile(obj.dirPath+"/"+fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
obj.fp = fp
obj.size = 0
}
func (obj *RotateFileWriter) Write(p []byte) (n int, err error) {
addSize := int64(len(p))
newSize := obj.size + addSize
if newSize > obj.maxSize {
obj.createNewFile()
}
obj.size += addSize
return obj.fp.Write(p)
}
// 循环文件写入器: fileName基本文件名, dirPath文件夹路径, maxCount最大文件数量, maxSize最大文件体积
func NewRotateFileWriter(fileName, dirPath string, maxCount int, maxSize int64) *RotateFileWriter {
writer := &RotateFileWriter{
fileName: fileName,
dirPath: dirPath,
maxCount: maxCount,
maxSize: maxSize}
writer.Init()
return writer
}