| package golog |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "os" |
| "path/filepath" |
| "time" |
| |
| log "github.com/go-playground/log" |
| ) |
| |
| var logLevelsArray = []log.Level{log.DebugLevel, |
| log.TraceLevel, |
| log.InfoLevel, |
| log.NoticeLevel, |
| log.WarnLevel, |
| log.ErrorLevel, |
| log.PanicLevel, |
| log.AlertLevel, |
| log.FatalLevel} |
| |
| func getLogLevels(l log.Level) []log.Level { |
| levels := make([]log.Level, 0) |
| offset := int(l) |
| levels = append(levels, logLevelsArray[offset:]...) |
| return levels |
| } |
| |
| func RegisterHandler(handler log.Handler, l log.Level) { |
| log.RegisterHandler(handler, getLogLevels(l)...) |
| } |
| |
| type BaseLogHandler struct { |
| } |
| |
| func (l *BaseLogHandler) FormatMessage(e *log.Entry, w io.Writer) { |
| now := e.Timestamp.In(time.Local) |
| fmt.Fprintf(w, "[%s] %s - %s", e.Level, |
| now.Format(l.getDefaultTimeLayout()), e.Message) |
| for _, f := range e.Fields { |
| fmt.Fprintf(w, " %s=%v", f.Key, f.Value) |
| } |
| w.Write([]byte("\n")) |
| } |
| |
| func (l *BaseLogHandler) getDefaultTimeLayout() string { |
| return "2006-01-02 15:04:05.000" |
| } |
| |
| type FileLogHandler struct { |
| *BaseLogHandler |
| logFilePath string |
| logHandler *os.File |
| } |
| |
| func checkAndCreateDir(path string) error { |
| if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { |
| if err = os.MkdirAll(path, os.ModeDir|os.ModePerm); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func NewFileLogHandler(logPath string) *FileLogHandler { |
| res := new(FileLogHandler) |
| res.logFilePath = logPath |
| return res |
| } |
| |
| func (h *FileLogHandler) openLogFile() error { |
| dir := filepath.Dir(h.logFilePath) |
| var err error |
| if err = checkAndCreateDir(dir); err != nil { |
| return err |
| } |
| if h.logHandler, err = os.OpenFile(h.logFilePath, |
| os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil { |
| return err |
| } |
| return nil |
| } |
| |
| func (h *FileLogHandler) Run() chan<- *log.Entry { |
| if err := h.openLogFile(); err != nil { |
| panic(fmt.Sprintf("Can't open log file, Err=%v\n", err)) |
| } |
| ch := make(chan *log.Entry, 5) |
| go func(entries <-chan *log.Entry) { |
| var e *log.Entry |
| b := new(bytes.Buffer) |
| defer h.logHandler.Close() |
| for e = range entries { |
| |
| b.Reset() |
| h.FormatMessage(e, b) |
| io.Copy(h.logHandler, b) |
| h.logHandler.Sync() |
| e.Consumed() |
| } |
| }(ch) |
| return ch |
| } |
| |
| type RotateFileLogHandler struct { |
| *BaseLogHandler |
| logFilePath string |
| maxLogSize int64 |
| maxLogFileCount int |
| logCurrentSize int64 |
| logHandler *os.File |
| } |
| |
| // NewRotateFileLogHandler |
| // maxSize in MB |
| func NewRotateFileLogHandler(logPath string, maxSize int, maxCount int) *RotateFileLogHandler { |
| res := new(RotateFileLogHandler) |
| res.logFilePath = logPath |
| if maxSize < 1 || maxSize > 2000 { |
| maxSize = 50 |
| } |
| res.maxLogFileCount = maxCount |
| res.maxLogSize = int64(maxSize) * 1024 * 1024 |
| return res |
| } |
| |
| func (h *RotateFileLogHandler) checkFile() error { |
| var err error |
| dir := filepath.Dir(h.logFilePath) |
| if err = checkAndCreateDir(dir); err != nil { |
| return err |
| } |
| if h.logHandler, err = os.OpenFile(h.logFilePath, |
| os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil { |
| return err |
| } |
| h.logHandler.Seek(0, os.SEEK_SET) |
| n, _ := h.logHandler.Seek(0, os.SEEK_END) |
| h.logCurrentSize = n |
| return nil |
| } |
| |
| func (h *RotateFileLogHandler) rotate() error { |
| var backupFilePath string |
| minModTime := time.Now() |
| backupExists := true |
| for i := 0; i < h.maxLogFileCount; i++ { |
| fullPath := fmt.Sprintf("%v.%d", h.logFilePath, i+1) |
| if stat, err := os.Stat(fullPath); err != nil { |
| if os.IsNotExist(err) { |
| backupFilePath = fullPath |
| backupExists = false |
| break |
| } else { |
| return err |
| } |
| } else { |
| if stat.ModTime().Before(minModTime) { |
| minModTime = stat.ModTime() |
| backupFilePath = fullPath |
| } |
| } |
| } |
| if backupExists && len(backupFilePath) > 0 { |
| os.Remove(backupFilePath) |
| } |
| if len(backupFilePath) > 0 { |
| var err error |
| h.logHandler.Close() |
| h.logHandler = nil |
| err = os.Rename(h.logFilePath, backupFilePath) |
| if err != nil { |
| fmt.Printf("Rename file Error=%v\n", err) |
| } |
| // if stat, err := os.Stat(backupFilePath); err == nil { |
| // fmt.Printf("Backup file size:<%v>%v\n", backupFilePath, stat.Size()) |
| // } |
| h.logHandler, err = os.OpenFile(h.logFilePath, |
| os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0660) |
| if err != nil { |
| return err |
| } |
| h.logCurrentSize = 0 |
| } |
| return nil |
| } |
| |
| func (h *RotateFileLogHandler) Run() chan<- *log.Entry { |
| if err := h.checkFile(); err != nil { |
| panic(fmt.Sprintf("Can't create file, Err=%v", err)) |
| } |
| ch := make(chan *log.Entry, 5) |
| go func(entries <-chan *log.Entry) { |
| var e *log.Entry |
| b := new(bytes.Buffer) |
| defer h.logHandler.Close() |
| for e = range entries { |
| |
| b.Reset() |
| h.FormatMessage(e, b) |
| h.logCurrentSize += int64(b.Len()) |
| if h.logHandler != nil { |
| io.Copy(h.logHandler, b) |
| // h.logHandler.Sync() |
| if h.logCurrentSize >= h.maxLogSize { |
| //fmt.Printf("Current Size=%v, old=%v\n", h.logCurrentSize, h.maxLogSize) |
| h.rotate() |
| } |
| } |
| e.Consumed() |
| } |
| }(ch) |
| return ch |
| } |