forked from lestrrat-go/file-rotatelogs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rotatelogs.go
134 lines (126 loc) · 3.33 KB
/
rotatelogs.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
package rotatelogs
import (
"io"
"os"
"regexp"
"strings"
"sync"
"time"
"github.com/lestrrat-go/strftime"
)
// Rotate represents a log file that gets
// automatically rotated as you write to it.
type Rotate struct {
clock Clock // 时间
out *os.File // 文件句柄
business *os.File // 文件句柄
mutex *sync.RWMutex // 读写锁
maxAge time.Duration // 最大保存时间
pattern *strftime.Strftime // 时间格式
rotationTime time.Duration // 旋转时间
}
// New creates a new Rotate object. A log filename pattern
// must be passed. Optional `Option` parameters may be passed
func New(p string, options ...Option) (*Rotate, error) {
pattern, err := strftime.New(p)
if err != nil {
return nil, err
}
rotate := &Rotate{
clock: Local,
mutex: new(sync.RWMutex),
pattern: pattern,
rotationTime: 24 * time.Hour,
}
for i := 0; i < len(options); i++ {
options[i](rotate)
}
return rotate, nil
}
// Write satisfies the io.Writer interface. It writes to the
// appropriate file handle that is currently being used.
// If we have reached rotation time, the target file gets
// automatically rotated, and also purged if necessary.
func (r *Rotate) Write(bytes []byte) (n int, err error) {
r.mutex.Lock() // Guard against concurrent writes
defer func() {
r.mutex.Unlock()
r.Close()
}()
var out io.Writer
if strings.Contains(string(bytes), "business") {
var compile *regexp.Regexp
compile, err = regexp.Compile(`{"business": "([^,]+)"}`)
if err != nil {
return 0, err
}
if compile.Match(bytes) {
finds := compile.FindSubmatch(bytes)
business := string(finds[len(finds)-1])
bytes = compile.ReplaceAll(bytes, []byte(""))
out, err = r.getBusinessWriter(business)
if err != nil {
return 0, err
}
return out.Write(bytes)
}
compile, err = regexp.Compile(`"business": "([^,]+)"`)
if err != nil {
return 0, err
}
if compile.Match(bytes) {
finds := compile.FindSubmatch(bytes)
business := string(finds[len(finds)-1])
bytes = compile.ReplaceAll(bytes, []byte(""))
out, err = r.getBusinessWriter(business)
if err != nil {
return 0, err
}
return out.Write(bytes)
}
}
out, err = r.getWriter()
if err != nil {
return 0, err
}
return out.Write(bytes)
}
// getBusinessWriter 获取 business io.Writer
func (r *Rotate) getBusinessWriter(business string) (io.Writer, error) {
var pattern *strftime.Strftime
slice := strings.Split(r.pattern.Pattern(), "/")
if slice[len(slice)-2] != business {
slice = append(slice[:len(slice)-1], business, slice[len(slice)-1])
pattern, _ = strftime.New(strings.Join(slice, "/"))
}
filename := GenerateFile(pattern, r.clock, r.rotationTime)
out, err := CreateFile(filename)
if err != nil {
return nil, err
}
r.business = out
return out, nil
}
// getWriter 获取 io.Writer
func (r *Rotate) getWriter() (io.Writer, error) {
filename := GenerateFile(r.pattern, r.clock, r.rotationTime)
out, err := CreateFile(filename)
if err != nil {
return nil, err
}
_ = r.out.Close()
r.out = out
return out, nil
}
func (r *Rotate) Close() {
r.mutex.Lock() // Guard against concurrent writes
defer r.mutex.Unlock()
if r.out != nil {
_ = r.out.Close()
r.out = nil
}
if r.business != nil {
_ = r.business.Close()
r.business = nil
}
}