-
Notifications
You must be signed in to change notification settings - Fork 0
/
outer.go
140 lines (116 loc) · 2.35 KB
/
outer.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
package ylog
import (
"io"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"sync"
"time"
)
type (
Outer interface {
Write(r Record) error
}
// 标准输出
StdOut struct {
o io.Writer
mu sync.Mutex
}
// 空输出,测试时使用
EmptyOut struct {
StdOut
}
// 文件输出
RotateFileOut struct {
path string
nameFormat string
num int
mu sync.Mutex
openName string
openFd *os.File
}
)
func NewStdout() Outer {
return &StdOut{o: os.Stdout}
}
func NewEmptyOut() Outer {
e := &EmptyOut{}
e.o = io.Discard
return e
}
func NewRotateFile(path string, nameformat string, num int) Outer {
return &RotateFileOut{
path: path,
nameFormat: nameformat,
num: num,
}
}
func (s *StdOut) Write(r Record) error {
s.mu.Lock()
defer s.mu.Unlock()
_, err := s.o.Write([]byte(r.Fmsg))
return err
}
func (ro *RotateFileOut) Write(r Record) error {
ro.mu.Lock()
defer ro.mu.Unlock()
fpath := ro.fileNameByTime(r.Time)
if fpath != ro.openName {
if ro.openFd != nil {
ro.openFd.Close()
ro.openFd = nil
}
// 创建目录
ro.createDir()
// 打开日志文件
fd, err := os.OpenFile(fpath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return err
}
ro.openName = fpath
ro.openFd = fd
// 检查文件数量, 删除多余的文件
ro.delFiles()
}
// 写文件
_, err := ro.openFd.WriteString(r.Fmsg)
if err != nil {
ro.openName = ""
return err
}
return nil
}
// 根据时间获取文件名
func (ro *RotateFileOut) fileNameByTime(t time.Time) string {
fname := t.Format(ro.nameFormat)
fullpath := strings.TrimRight(ro.path, "/") + "/" + fname
return fullpath
}
func (ro *RotateFileOut) createDir() error {
if _, err := os.Stat(ro.path); err != nil {
return os.MkdirAll(ro.path, 0755)
}
return nil
}
// 匹配路径下的所有文件
func (ro *RotateFileOut) globFiles() []string {
re, _ := regexp.Compile("[0-9]+")
namePattern := re.ReplaceAllString(ro.nameFormat, "*")
pathPattern := strings.TrimRight(ro.path, "/") + "/" + namePattern
files, _ := filepath.Glob(pathPattern)
return files
}
// 删除多的文件
func (ro *RotateFileOut) delFiles() error {
files := ro.globFiles()
if len(files) > ro.num {
sort.Strings(files)
delFiles := files[0 : len(files)-ro.num]
for _, f := range delFiles {
os.Remove(f)
}
}
return nil
}