-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathmain.go
More file actions
171 lines (155 loc) · 4.11 KB
/
main.go
File metadata and controls
171 lines (155 loc) · 4.11 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package logrotate
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"time"
. "m7s.live/engine/v4"
"m7s.live/engine/v4/log"
"m7s.live/engine/v4/util"
. "m7s.live/engine/v4/util"
)
type FileInfo struct {
Name string
Size int64
}
type LogRotateConfig struct {
Path string `default:"./logs" desc:"日志文件存放目录"`
Size int64 `desc:"日志文件大小,单位:字节"`
Days int `default:"1" desc:"日志分割天数"`
MaxDays int `default:"3" desc:"日志文件保留天数"`
Formatter string `default:"2006-01-02T15" desc:"日志文件名格式"`
file *os.File
currentSize int64
createTime time.Time
hours float64
splitFunc func() bool
}
var LogRotatePlugin = InstallPlugin(&LogRotateConfig{})
func (config *LogRotateConfig) OnEvent(event any) {
switch event.(type) {
case FirstConfig:
if config.Size > 0 {
config.splitFunc = config.splitBySize
} else {
if config.Days == 0 {
config.Days = 1
}
config.hours = float64(config.Days) * 24
config.splitFunc = config.splitByTime
}
config.createTime = time.Now()
if config.Formatter == "" {
config.Formatter = "2006-01-02T15"
}
err := os.MkdirAll(config.Path, 0766)
config.file, err = os.OpenFile(filepath.Join(config.Path, fmt.Sprintf("%s.log", config.createTime.Format(config.Formatter))), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
if err == nil {
stat, _ := config.file.Stat()
config.currentSize = stat.Size()
log.AddWriter(config)
} else {
log.Error(err)
}
go func() {
for {
err := DeleteLog(config.Path, config.MaxDays)
if err != nil {
LogRotatePlugin.Error(err.Error())
}
time.Sleep(time.Minute * 30)
}
}()
}
}
func (l *LogRotateConfig) splitBySize() bool {
return l.currentSize >= l.Size
}
func (l *LogRotateConfig) splitByTime() bool {
return time.Since(l.createTime).Hours() > l.hours
}
func (l *LogRotateConfig) Write(data []byte) (n int, err error) {
n, err = l.file.Write(data)
l.currentSize += int64(n)
if err == nil {
if l.splitFunc() {
l.createTime = time.Now()
if file, err := os.OpenFile(filepath.Join(l.Path, fmt.Sprintf("%s.log", l.createTime.Format(l.Formatter))), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666); err == nil {
l.file = file
l.currentSize = 0
}
}
}
return
}
func (l *LogRotateConfig) API_tail(w http.ResponseWriter, r *http.Request) {
writer := NewSSE(w, r.Context())
log.AddWriter(writer)
<-r.Context().Done()
log.DeleteWriter(writer)
}
func (l *LogRotateConfig) API_list(w http.ResponseWriter, r *http.Request) {
dir, err := os.Open(l.Path)
if err == nil {
var files []os.FileInfo
if files, err = dir.Readdir(0); err == nil {
var fileInfos []*FileInfo
for _, info := range files {
fileInfos = append(fileInfos, &FileInfo{
info.Name(), info.Size(),
})
}
err = json.NewEncoder(w).Encode(fileInfos)
}
}
if err != nil {
ReturnError(APIErrorOpen, err.Error(), w, r)
} else {
ReturnOK(w, r)
}
}
func (l *LogRotateConfig) API_download(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Disposition", "attachment; filename="+r.URL.Query().Get("file"))
l.API_open(w, r)
}
func (l *LogRotateConfig) API_open(w http.ResponseWriter, r *http.Request) {
path := filepath.Join(l.Path, r.URL.Query().Get("file"))
if !util.IsSubdir(l.Path, path) {
http.Error(w, "invalid file", http.StatusBadRequest)
return
}
file, err := os.Open(path)
if err == nil {
defer file.Close()
_, err = io.Copy(w, file)
}
if err != nil {
ReturnError(APIErrorOpen, err.Error(), w, r)
} else {
ReturnOK(w, r)
}
}
func DeleteLog(path string, day int) error {
maxAge := time.Duration(day) * 24 * time.Hour
cutOffTime := time.Now().Add(-maxAge)
if path == "" {
LogRotatePlugin.Info("没有获取到日志路径")
return nil
}
return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && info.ModTime().Before(cutOffTime) {
err := os.Remove(path)
if err != nil {
return err
}
LogRotatePlugin.Info(path + "日志文件删除成功")
}
return nil
})
}