blob: fd59e0779eae0c3219834c2d9958afc485b2cbd1 [file] [log] [blame]
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
}