From 73d45b150c7b6cccda1d828085f632bfab66ad1e Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 24 Jun 2013 23:24:18 +0800 Subject: [PATCH] log support file & logrotate --- log.go | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 154 insertions(+), 4 deletions(-) diff --git a/log.go b/log.go index 101cb4d3..d69b2e89 100644 --- a/log.go +++ b/log.go @@ -1,13 +1,142 @@ package beego import ( + "fmt" + "io/ioutil" "log" "os" + "path" + "path/filepath" + "strings" + "sync" + "time" ) -//-------------------- -// LOG LEVEL -//-------------------- +type FileLogWriter struct { + *log.Logger + // The opened file + filename string + + maxlines int + maxlines_curlines int + + // Rotate at size + maxsize int + maxsize_cursize int + + // Rotate daily + daily bool + maxday int64 + daily_opendate int + + rotate bool + + startLock sync.Mutex //only one log can writer to the file +} + +func NewFileWriter(fname string, rotate bool) *FileLogWriter { + w := &FileLogWriter{ + filename: fname, + maxlines: 1000000, + maxsize: 1 << 28, //256 MB + daily: true, + maxday: 7, + rotate: rotate, + } + return w +} + +func (w *FileLogWriter) StartLogger() error { + if err := w.DoRotate(false); err != nil { + return err + } + return nil +} + +func (w *FileLogWriter) docheck(size int) { + w.startLock.Lock() + defer w.startLock.Unlock() + if (w.maxlines > 0 && w.maxlines_curlines >= w.maxlines) || + (w.maxsize > 0 && w.maxsize_cursize >= w.maxsize) || + (w.daily && time.Now().Day() != w.daily_opendate) { + if err := w.DoRotate(true); err != nil { + fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err) + return + } + } + w.maxlines_curlines++ + w.maxsize_cursize += size +} + +func (w *FileLogWriter) Printf(format string, v ...interface{}) { + // Perform the write + str := fmt.Sprintf(format, v...) + n := 24 + len(str) // 24 stand for the length "2013/06/23 21:00:22 [T] " + + w.docheck(n) + w.Logger.Printf(format, v...) +} + +func (w *FileLogWriter) DoRotate(rotate bool) error { + if rotate { + _, err := os.Lstat(w.filename) + if err == nil { // file exists + // Find the next available number + num := 1 + fname := "" + for ; err == nil && num <= 999; num++ { + fname = w.filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num) + _, err = os.Lstat(fname) + } + // return error if the last file checked still existed + if err == nil { + return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.filename) + } + + // Rename the file to its newfound home + err = os.Rename(w.filename, fname) + if err != nil { + return fmt.Errorf("Rotate: %s\n", err) + } + go w.deleteOldLog() + } + } + + // Open the log file + fd, err := os.OpenFile(w.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) + if err != nil { + return err + } + w.Logger = log.New(fd, "", log.Ldate|log.Ltime) + finfo, err := fd.Stat() + if err != nil { + return fmt.Errorf("get stat err: %s\n", err) + } + w.maxsize_cursize = int(finfo.Size()) + w.daily_opendate = time.Now().Day() + if finfo.Size() > 0 { + content, err := ioutil.ReadAll(fd) + if err != nil { + //Do something + } + w.maxlines_curlines = len(strings.Split(string(content), "\n")) + + } else { + w.maxlines_curlines = 0 + } + BeeLogger = w + return nil +} + +func (w *FileLogWriter) deleteOldLog() { + dir := path.Dir(w.filename) + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.maxday) { + os.Remove(path) + } + return nil + }) +} // Log levels to control the logging output. const ( @@ -34,8 +163,29 @@ func SetLevel(l int) { level = l } +type IBeeLogger interface { + Fatal(v ...interface{}) + Fatalf(format string, v ...interface{}) + Fatalln(v ...interface{}) + Flags() int + Output(calldepth int, s string) error + Panic(v ...interface{}) + Panicf(format string, v ...interface{}) + Panicln(v ...interface{}) + Prefix() string + Print(v ...interface{}) + Printf(format string, v ...interface{}) + Println(v ...interface{}) + SetFlags(flag int) + SetPrefix(prefix string) +} + // logger references the used application logger. -var BeeLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime) +var BeeLogger IBeeLogger + +func init() { + BeeLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime) +} // SetLogger sets a new logger. func SetLogger(l *log.Logger) {