package log import ( "fmt" "io" "os" "time" ) type Handler interface { Write(p []byte) (n int, err error) Close() error } type StreamHandler struct { w io.Writer } func NewStreamHandler(w io.Writer) (*StreamHandler, error) { h := new(StreamHandler) h.w = w return h, nil } func (h *StreamHandler) Write(b []byte) (n int, err error) { return h.w.Write(b) } func (h *StreamHandler) Close() error { return nil } type FileHandler struct { fd *os.File } func NewFileHandler(fileName string, flag int) (*FileHandler, error) { 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() } //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) { 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() }