diff --git a/log/handler.go b/log/handler.go index 2a05098..87b835a 100644 --- a/log/handler.go +++ b/log/handler.go @@ -9,67 +9,34 @@ import ( type Handler interface { Write(p []byte) (n int, err error) - Close() -} - -type base struct { - msg chan []byte - quit chan bool -} - -func (h *base) Write(p []byte) (n int, err error) { - m := make([]byte, len(p)) - - copy(m, p) - - h.msg <- m - - return len(p), nil -} - -func (h *base) Close() { - h.quit <- true + Close() error } type StreamHandler struct { - base w io.Writer } -func NewStreamHandler(w io.Writer, msgNum int) (*StreamHandler, error) { +func NewStreamHandler(w io.Writer) (*StreamHandler, error) { h := new(StreamHandler) h.w = w - h.msg = make(chan []byte, msgNum) - h.quit = make(chan bool, 1) - - go h.run() - return h, nil } -func NewDefaultStreamHandler(w io.Writer) (*StreamHandler, error) { - return NewStreamHandler(w, 1024) +func (h *StreamHandler) Write(b []byte) (n int, err error) { + return h.w.Write(b) } -func (h *StreamHandler) run() { - for { - select { - case m := <-h.msg: - h.w.Write(m) - case <-h.quit: - return - } - } +func (h *StreamHandler) Close() error { + return nil } type FileHandler struct { - base fd *os.File } -func NewFileHandler(fileName string, flag int, msgNum int) (*FileHandler, error) { +func NewFileHandler(fileName string, flag int) (*FileHandler, error) { f, err := os.OpenFile(fileName, flag, 0) if err != nil { return nil, err @@ -79,36 +46,21 @@ func NewFileHandler(fileName string, flag int, msgNum int) (*FileHandler, error) h.fd = f - h.msg = make(chan []byte, msgNum) - h.quit = make(chan bool, 1) - - go h.run() - return h, nil } -func NewDefaultFileHandler(fileName string, flag int) (*FileHandler, error) { - return NewFileHandler(fileName, flag, 1024) +func (h *FileHandler) Write(b []byte) (n int, err error) { + return h.fd.Write(b) } -func (h *FileHandler) run() { - for { - select { - case m := <-h.msg: - h.fd.Write(m) - case <-h.quit: - h.fd.Close() - return - } - } +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 { - base - fd *os.File baseName string @@ -124,7 +76,7 @@ const ( WhenDay ) -func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum int) (*TimeRotatingFileHandler, error) { +func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) { h := new(TimeRotatingFileHandler) h.baseName = baseName @@ -143,8 +95,7 @@ func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum h.interval = 3600 * 24 h.suffix = "2006-01-02" default: - e := fmt.Errorf("invalid when_rotate: %d", when) - panic(e) + return nil, fmt.Errorf("invalid when_rotate: %d", when) } h.interval = h.interval * int64(interval) @@ -152,23 +103,15 @@ func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum var err error h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { - panic(err) + return nil, err } fInfo, _ := h.fd.Stat() h.rolloverAt = fInfo.ModTime().Unix() + h.interval - h.msg = make(chan []byte, msgNum) - h.quit = make(chan bool, 1) - - go h.run() return h, nil } -func NewDefaultTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) { - return NewTimeRotatingFileHandler(baseName, when, interval, 1024) -} - func (h *TimeRotatingFileHandler) doRollover() { //refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py now := time.Now() @@ -187,22 +130,11 @@ func (h *TimeRotatingFileHandler) doRollover() { } } -func (h *TimeRotatingFileHandler) run() { - for { - select { - case m := <-h.msg: - h.doRollover() - if h.fd != nil { - _, e := h.fd.Write(m) - if e != nil { - panic(e) - } - } - case <-h.quit: - if h.fd != nil { - h.fd.Close() - } - return - } - } +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() } diff --git a/log/log.go b/log/log.go index 80af33f..e1c8440 100644 --- a/log/log.go +++ b/log/log.go @@ -2,8 +2,9 @@ package log import ( "fmt" - "log" "os" + "runtime" + "time" ) const ( @@ -15,45 +16,72 @@ const ( LevelFatal ) +const ( + Ltime = iota << 1 //time format "2006/01/02 15:04:05" + Lfile //file.go:123 + Llevel //[Trace|Debug|Info...] +) + var LevelName [6]string = [6]string{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"} -type Logger struct { - logger *log.Logger - level int - handler Handler -} +const TimeFormat = "2006/01/02 15:04:05" -const ( - Ldate = log.Ldate - Ltime = log.Ltime - Lmicroseconds = log.Lmicroseconds - Llongfile = log.Llongfile - Lshortfile = log.Lshortfile - LstdFlags = Ldate | Ltime -) +type Logger struct { + level int + flag int + + handler Handler + + quit chan struct{} + msg chan []byte +} func New(handler Handler, flag int) *Logger { var l = new(Logger) - l.logger = log.New(handler, "", flag) //log.LstdFlags|log.Lshortfile) + l.level = LevelInfo l.handler = handler + l.flag = flag + + l.quit = make(chan struct{}) + + l.msg = make(chan []byte, 1024) + + go l.run() + return l } func NewDefault(handler Handler) *Logger { - return New(handler, log.LstdFlags|log.Lshortfile) + return New(handler, Ltime|Lfile|Llevel) } func newStdHandler() *StreamHandler { - h, _ := NewDefaultStreamHandler(os.Stdout) + h, _ := NewStreamHandler(os.Stdout) return h } var std = NewDefault(newStdHandler()) +func (l *Logger) run() { + for { + select { + case msg := <-l.msg: + l.handler.Write(msg) + case <-l.quit: + l.handler.Close() + } + } +} + func (l *Logger) Close() { - l.handler.Close() + if l.quit == nil { + return + } + + close(l.quit) + l.quit = nil } func (l *Logger) SetLevel(level int) { @@ -61,39 +89,69 @@ func (l *Logger) SetLevel(level int) { } func (l *Logger) Output(callDepth int, level int, format string, v ...interface{}) { - if l.level <= level { - f := fmt.Sprintf("[%s] %s", LevelName[level], format) - s := fmt.Sprintf(f, v...) - l.logger.Output(callDepth, s) + if l.level > level { + return } -} -func (l *Logger) Write(s string) { - l.logger.Output(3, s) + buf := make([]byte, 0, 1024) + + if l.flag&Ltime > 0 { + now := time.Now().Format(TimeFormat) + buf = append(buf, now...) + buf = append(buf, " "...) + } + + if l.flag&Lfile > 0 { + _, file, line, ok := runtime.Caller(callDepth) + if !ok { + file = "???" + line = 0 + } else { + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + file = file[i+1:] + break + } + } + } + + buf = append(buf, fmt.Sprintf("%s:%d ", file, line)...) + } + + if l.flag&Llevel > 0 { + buf = append(buf, fmt.Sprintf("[%s] ", LevelName[level])...) + } + + s := fmt.Sprintf(format, v...) + + buf = append(buf, s...) + buf = append(buf, "\n"...) + + l.msg <- buf } func (l *Logger) Trace(format string, v ...interface{}) { - l.Output(3, LevelTrace, format, v...) + l.Output(2, LevelTrace, format, v...) } func (l *Logger) Debug(format string, v ...interface{}) { - l.Output(3, LevelDebug, format, v...) + l.Output(2, LevelDebug, format, v...) } func (l *Logger) Info(format string, v ...interface{}) { - l.Output(3, LevelInfo, format, v...) + l.Output(2, LevelInfo, format, v...) } func (l *Logger) Warn(format string, v ...interface{}) { - l.Output(3, LevelWarn, format, v...) + l.Output(2, LevelWarn, format, v...) } func (l *Logger) Error(format string, v ...interface{}) { - l.Output(3, LevelError, format, v...) + l.Output(2, LevelError, format, v...) } func (l *Logger) Fatal(format string, v ...interface{}) { - l.Output(3, LevelFatal, format, v...) + l.Output(2, LevelFatal, format, v...) } func SetLevel(level int) { @@ -101,25 +159,25 @@ func SetLevel(level int) { } func Trace(format string, v ...interface{}) { - std.Output(3, LevelTrace, format, v...) + std.Output(2, LevelTrace, format, v...) } func Debug(format string, v ...interface{}) { - std.Output(3, LevelDebug, format, v...) + std.Output(2, LevelDebug, format, v...) } func Info(format string, v ...interface{}) { - std.Output(3, LevelInfo, format, v...) + std.Output(2, LevelInfo, format, v...) } func Warn(format string, v ...interface{}) { - std.Output(3, LevelWarn, format, v...) + std.Output(2, LevelWarn, format, v...) } func Error(format string, v ...interface{}) { - std.Output(3, LevelError, format, v...) + std.Output(2, LevelError, format, v...) } func Fatal(format string, v ...interface{}) { - std.Output(3, LevelFatal, format, v...) + std.Output(2, LevelFatal, format, v...) } diff --git a/log/log_test.go b/log/log_test.go index 6d70f06..e5e022b 100644 --- a/log/log_test.go +++ b/log/log_test.go @@ -6,7 +6,7 @@ import ( ) func TestStdStreamLog(t *testing.T) { - h, _ := NewDefaultStreamHandler(os.Stdout) + h, _ := NewStreamHandler(os.Stdout) s := NewDefault(h) s.Info("hello world")