blob: fd59e0779eae0c3219834c2d9958afc485b2cbd1 [file] [log] [blame]
Tang Cheng998c4342016-05-11 16:33:24 +08001package golog
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "os"
8 "path/filepath"
9 "time"
10
11 log "github.com/go-playground/log"
12)
13
14var logLevelsArray = []log.Level{log.DebugLevel,
15 log.TraceLevel,
16 log.InfoLevel,
17 log.NoticeLevel,
18 log.WarnLevel,
19 log.ErrorLevel,
20 log.PanicLevel,
21 log.AlertLevel,
22 log.FatalLevel}
23
24func getLogLevels(l log.Level) []log.Level {
25 levels := make([]log.Level, 0)
26 offset := int(l)
27 levels = append(levels, logLevelsArray[offset:]...)
28 return levels
29}
30
31func RegisterHandler(handler log.Handler, l log.Level) {
32 log.RegisterHandler(handler, getLogLevels(l)...)
33}
34
35type BaseLogHandler struct {
36}
37
38func (l *BaseLogHandler) FormatMessage(e *log.Entry, w io.Writer) {
39 now := e.Timestamp.In(time.Local)
40 fmt.Fprintf(w, "[%s] %s - %s", e.Level,
41 now.Format(l.getDefaultTimeLayout()), e.Message)
42 for _, f := range e.Fields {
43 fmt.Fprintf(w, " %s=%v", f.Key, f.Value)
44 }
45 w.Write([]byte("\n"))
46}
47
48func (l *BaseLogHandler) getDefaultTimeLayout() string {
49 return "2006-01-02 15:04:05.000"
50}
51
52type FileLogHandler struct {
53 *BaseLogHandler
54 logFilePath string
55 logHandler *os.File
56}
57
58func checkAndCreateDir(path string) error {
59 if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
60 if err = os.MkdirAll(path, os.ModeDir|os.ModePerm); err != nil {
61 return err
62 }
63 }
64 return nil
65}
66
67func NewFileLogHandler(logPath string) *FileLogHandler {
68 res := new(FileLogHandler)
69 res.logFilePath = logPath
70 return res
71}
72
73func (h *FileLogHandler) openLogFile() error {
74 dir := filepath.Dir(h.logFilePath)
75 var err error
76 if err = checkAndCreateDir(dir); err != nil {
77 return err
78 }
79 if h.logHandler, err = os.OpenFile(h.logFilePath,
80 os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
81 return err
82 }
83 return nil
84}
85
86func (h *FileLogHandler) Run() chan<- *log.Entry {
87 if err := h.openLogFile(); err != nil {
88 panic(fmt.Sprintf("Can't open log file, Err=%v\n", err))
89 }
90 ch := make(chan *log.Entry, 5)
91 go func(entries <-chan *log.Entry) {
92 var e *log.Entry
93 b := new(bytes.Buffer)
94 defer h.logHandler.Close()
95 for e = range entries {
96
97 b.Reset()
98 h.FormatMessage(e, b)
99 io.Copy(h.logHandler, b)
100 h.logHandler.Sync()
101 e.Consumed()
102 }
103 }(ch)
104 return ch
105}
106
107type RotateFileLogHandler struct {
108 *BaseLogHandler
109 logFilePath string
110 maxLogSize int64
111 maxLogFileCount int
112 logCurrentSize int64
113 logHandler *os.File
114}
115
116// NewRotateFileLogHandler
117// maxSize in MB
118func NewRotateFileLogHandler(logPath string, maxSize int, maxCount int) *RotateFileLogHandler {
119 res := new(RotateFileLogHandler)
120 res.logFilePath = logPath
121 if maxSize < 1 || maxSize > 2000 {
122 maxSize = 50
123 }
124 res.maxLogFileCount = maxCount
125 res.maxLogSize = int64(maxSize) * 1024 * 1024
126 return res
127}
128
129func (h *RotateFileLogHandler) checkFile() error {
130 var err error
131 dir := filepath.Dir(h.logFilePath)
132 if err = checkAndCreateDir(dir); err != nil {
133 return err
134 }
135 if h.logHandler, err = os.OpenFile(h.logFilePath,
136 os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
137 return err
138 }
139 h.logHandler.Seek(0, os.SEEK_SET)
140 n, _ := h.logHandler.Seek(0, os.SEEK_END)
141 h.logCurrentSize = n
142 return nil
143}
144
145func (h *RotateFileLogHandler) rotate() error {
146 var backupFilePath string
147 minModTime := time.Now()
148 backupExists := true
149 for i := 0; i < h.maxLogFileCount; i++ {
150 fullPath := fmt.Sprintf("%v.%d", h.logFilePath, i+1)
151 if stat, err := os.Stat(fullPath); err != nil {
152 if os.IsNotExist(err) {
153 backupFilePath = fullPath
154 backupExists = false
155 break
156 } else {
157 return err
158 }
159 } else {
160 if stat.ModTime().Before(minModTime) {
161 minModTime = stat.ModTime()
162 backupFilePath = fullPath
163 }
164 }
165 }
166 if backupExists && len(backupFilePath) > 0 {
167 os.Remove(backupFilePath)
168 }
169 if len(backupFilePath) > 0 {
170 var err error
171 h.logHandler.Close()
172 h.logHandler = nil
173 err = os.Rename(h.logFilePath, backupFilePath)
174 if err != nil {
175 fmt.Printf("Rename file Error=%v\n", err)
176 }
177 // if stat, err := os.Stat(backupFilePath); err == nil {
178 // fmt.Printf("Backup file size:<%v>%v\n", backupFilePath, stat.Size())
179 // }
180 h.logHandler, err = os.OpenFile(h.logFilePath,
181 os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0660)
182 if err != nil {
183 return err
184 }
185 h.logCurrentSize = 0
186 }
187 return nil
188}
189
190func (h *RotateFileLogHandler) Run() chan<- *log.Entry {
191 if err := h.checkFile(); err != nil {
192 panic(fmt.Sprintf("Can't create file, Err=%v", err))
193 }
194 ch := make(chan *log.Entry, 5)
195 go func(entries <-chan *log.Entry) {
196 var e *log.Entry
197 b := new(bytes.Buffer)
198 defer h.logHandler.Close()
199 for e = range entries {
200
201 b.Reset()
202 h.FormatMessage(e, b)
203 h.logCurrentSize += int64(b.Len())
204 if h.logHandler != nil {
205 io.Copy(h.logHandler, b)
206 // h.logHandler.Sync()
207 if h.logCurrentSize >= h.maxLogSize {
208 //fmt.Printf("Current Size=%v, old=%v\n", h.logCurrentSize, h.maxLogSize)
209 h.rotate()
210 }
211 }
212 e.Consumed()
213 }
214 }(ch)
215 return ch
216}