222 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package log
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"path"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
//FileHandler writes log to a file.
 | 
						|
type FileHandler struct {
 | 
						|
	fd *os.File
 | 
						|
}
 | 
						|
 | 
						|
func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
 | 
						|
	dir := path.Dir(fileName)
 | 
						|
	os.Mkdir(dir, 0777)
 | 
						|
 | 
						|
	f, err := os.OpenFile(fileName, flag, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	h := new(FileHandler)
 | 
						|
 | 
						|
	h.fd = f
 | 
						|
 | 
						|
	return h, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *FileHandler) Write(b []byte) (n int, err error) {
 | 
						|
	return h.fd.Write(b)
 | 
						|
}
 | 
						|
 | 
						|
func (h *FileHandler) Close() error {
 | 
						|
	return h.fd.Close()
 | 
						|
}
 | 
						|
 | 
						|
//RotatingFileHandler writes log a file, if file size exceeds maxBytes,
 | 
						|
//it will backup current file and open a new one.
 | 
						|
//
 | 
						|
//max backup file number is set by backupCount, it will delete oldest if backups too many.
 | 
						|
type RotatingFileHandler struct {
 | 
						|
	fd *os.File
 | 
						|
 | 
						|
	fileName    string
 | 
						|
	maxBytes    int
 | 
						|
	curBytes    int
 | 
						|
	backupCount int
 | 
						|
}
 | 
						|
 | 
						|
func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
 | 
						|
	dir := path.Dir(fileName)
 | 
						|
	os.MkdirAll(dir, 0777)
 | 
						|
 | 
						|
	h := new(RotatingFileHandler)
 | 
						|
 | 
						|
	if maxBytes <= 0 {
 | 
						|
		return nil, fmt.Errorf("invalid max bytes")
 | 
						|
	}
 | 
						|
 | 
						|
	h.fileName = fileName
 | 
						|
	h.maxBytes = maxBytes
 | 
						|
	h.backupCount = backupCount
 | 
						|
 | 
						|
	var err error
 | 
						|
	h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := h.fd.Stat()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	h.curBytes = int(f.Size())
 | 
						|
 | 
						|
	return h, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
 | 
						|
	h.doRollover()
 | 
						|
	n, err = h.fd.Write(p)
 | 
						|
	h.curBytes += n
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func (h *RotatingFileHandler) Close() error {
 | 
						|
	if h.fd != nil {
 | 
						|
		return h.fd.Close()
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *RotatingFileHandler) doRollover() {
 | 
						|
 | 
						|
	if h.curBytes < h.maxBytes  {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	f, err := h.fd.Stat()
 | 
						|
	if err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if h.maxBytes <= 0 {
 | 
						|
		return
 | 
						|
	} else if f.Size() < int64(h.maxBytes) {
 | 
						|
		h.curBytes = int(f.Size())
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if h.backupCount > 0 {
 | 
						|
		h.fd.Close()
 | 
						|
 | 
						|
		for i := h.backupCount - 1; i > 0; i-- {
 | 
						|
			sfn := fmt.Sprintf("%s.%d", h.fileName, i)
 | 
						|
			dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
 | 
						|
 | 
						|
			os.Rename(sfn, dfn)
 | 
						|
		}
 | 
						|
 | 
						|
		dfn := fmt.Sprintf("%s.1", h.fileName)
 | 
						|
		os.Rename(h.fileName, dfn)
 | 
						|
 | 
						|
		h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 | 
						|
		h.curBytes = 0
 | 
						|
		f, err := h.fd.Stat()
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		h.curBytes = int(f.Size())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//TimeRotatingFileHandler writes log to a file,
 | 
						|
//it will backup current and open a new one, with a period time you sepecified.
 | 
						|
//
 | 
						|
//refer: http://docs.python.org/2/library/logging.handlers.html.
 | 
						|
//same like python TimedRotatingFileHandler.
 | 
						|
type TimeRotatingFileHandler struct {
 | 
						|
	fd *os.File
 | 
						|
 | 
						|
	baseName   string
 | 
						|
	interval   int64
 | 
						|
	suffix     string
 | 
						|
	rolloverAt int64
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	WhenSecond = iota
 | 
						|
	WhenMinute
 | 
						|
	WhenHour
 | 
						|
	WhenDay
 | 
						|
)
 | 
						|
 | 
						|
func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
 | 
						|
	dir := path.Dir(baseName)
 | 
						|
	os.Mkdir(dir, 0777)
 | 
						|
 | 
						|
	h := new(TimeRotatingFileHandler)
 | 
						|
 | 
						|
	h.baseName = baseName
 | 
						|
 | 
						|
	switch when {
 | 
						|
	case WhenSecond:
 | 
						|
		h.interval = 1
 | 
						|
		h.suffix = "2006-01-02_15-04-05"
 | 
						|
	case WhenMinute:
 | 
						|
		h.interval = 60
 | 
						|
		h.suffix = "2006-01-02_15-04"
 | 
						|
	case WhenHour:
 | 
						|
		h.interval = 3600
 | 
						|
		h.suffix = "2006-01-02_15"
 | 
						|
	case WhenDay:
 | 
						|
		h.interval = 3600 * 24
 | 
						|
		h.suffix = "2006-01-02"
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("invalid when_rotate: %d", when)
 | 
						|
	}
 | 
						|
 | 
						|
	h.interval = h.interval * int64(interval)
 | 
						|
 | 
						|
	var err error
 | 
						|
	h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	fInfo, _ := h.fd.Stat()
 | 
						|
	h.rolloverAt = fInfo.ModTime().Unix() + h.interval
 | 
						|
 | 
						|
	return h, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *TimeRotatingFileHandler) doRollover() {
 | 
						|
	//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
 | 
						|
	now := time.Now()
 | 
						|
 | 
						|
	if h.rolloverAt <= now.Unix() {
 | 
						|
		fName := h.baseName + now.Format(h.suffix)
 | 
						|
		h.fd.Close()
 | 
						|
		e := os.Rename(h.baseName, fName)
 | 
						|
		if e != nil {
 | 
						|
			panic(e)
 | 
						|
		}
 | 
						|
 | 
						|
		h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
 | 
						|
 | 
						|
		h.rolloverAt = time.Now().Unix() + h.interval
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
 | 
						|
	h.doRollover()
 | 
						|
	return h.fd.Write(b)
 | 
						|
}
 | 
						|
 | 
						|
func (h *TimeRotatingFileHandler) Close() error {
 | 
						|
	return h.fd.Close()
 | 
						|
}
 |