refactor log

This commit is contained in:
siddontang 2014-04-06 22:09:23 +08:00
parent e009b5fbd8
commit ec6187efd9
3 changed files with 117 additions and 127 deletions

View File

@ -9,67 +9,34 @@ import (
type Handler interface { type Handler interface {
Write(p []byte) (n int, err error) Write(p []byte) (n int, err error)
Close() Close() error
}
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
} }
type StreamHandler struct { type StreamHandler struct {
base
w io.Writer w io.Writer
} }
func NewStreamHandler(w io.Writer, msgNum int) (*StreamHandler, error) { func NewStreamHandler(w io.Writer) (*StreamHandler, error) {
h := new(StreamHandler) h := new(StreamHandler)
h.w = w h.w = w
h.msg = make(chan []byte, msgNum)
h.quit = make(chan bool, 1)
go h.run()
return h, nil return h, nil
} }
func NewDefaultStreamHandler(w io.Writer) (*StreamHandler, error) { func (h *StreamHandler) Write(b []byte) (n int, err error) {
return NewStreamHandler(w, 1024) return h.w.Write(b)
} }
func (h *StreamHandler) run() { func (h *StreamHandler) Close() error {
for { return nil
select {
case m := <-h.msg:
h.w.Write(m)
case <-h.quit:
return
}
}
} }
type FileHandler struct { type FileHandler struct {
base
fd *os.File 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) f, err := os.OpenFile(fileName, flag, 0)
if err != nil { if err != nil {
return nil, err return nil, err
@ -79,36 +46,21 @@ func NewFileHandler(fileName string, flag int, msgNum int) (*FileHandler, error)
h.fd = f h.fd = f
h.msg = make(chan []byte, msgNum)
h.quit = make(chan bool, 1)
go h.run()
return h, nil return h, nil
} }
func NewDefaultFileHandler(fileName string, flag int) (*FileHandler, error) { func (h *FileHandler) Write(b []byte) (n int, err error) {
return NewFileHandler(fileName, flag, 1024) return h.fd.Write(b)
} }
func (h *FileHandler) run() { func (h *FileHandler) Close() error {
for { return h.fd.Close()
select {
case m := <-h.msg:
h.fd.Write(m)
case <-h.quit:
h.fd.Close()
return
}
}
} }
//refer: http://docs.python.org/2/library/logging.handlers.html //refer: http://docs.python.org/2/library/logging.handlers.html
//same like python TimedRotatingFileHandler //same like python TimedRotatingFileHandler
type TimeRotatingFileHandler struct { type TimeRotatingFileHandler struct {
base
fd *os.File fd *os.File
baseName string baseName string
@ -124,7 +76,7 @@ const (
WhenDay 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 := new(TimeRotatingFileHandler)
h.baseName = baseName h.baseName = baseName
@ -143,8 +95,7 @@ func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum
h.interval = 3600 * 24 h.interval = 3600 * 24
h.suffix = "2006-01-02" h.suffix = "2006-01-02"
default: default:
e := fmt.Errorf("invalid when_rotate: %d", when) return nil, fmt.Errorf("invalid when_rotate: %d", when)
panic(e)
} }
h.interval = h.interval * int64(interval) h.interval = h.interval * int64(interval)
@ -152,23 +103,15 @@ func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum
var err error var err error
h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { if err != nil {
panic(err) return nil, err
} }
fInfo, _ := h.fd.Stat() fInfo, _ := h.fd.Stat()
h.rolloverAt = fInfo.ModTime().Unix() + h.interval 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 return h, nil
} }
func NewDefaultTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
return NewTimeRotatingFileHandler(baseName, when, interval, 1024)
}
func (h *TimeRotatingFileHandler) doRollover() { func (h *TimeRotatingFileHandler) doRollover() {
//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py //refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
now := time.Now() now := time.Now()
@ -187,22 +130,11 @@ func (h *TimeRotatingFileHandler) doRollover() {
} }
} }
func (h *TimeRotatingFileHandler) run() { func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
for { h.doRollover()
select { return h.fd.Write(b)
case m := <-h.msg: }
h.doRollover()
if h.fd != nil { func (h *TimeRotatingFileHandler) Close() error {
_, e := h.fd.Write(m) return h.fd.Close()
if e != nil {
panic(e)
}
}
case <-h.quit:
if h.fd != nil {
h.fd.Close()
}
return
}
}
} }

View File

@ -2,8 +2,9 @@ package log
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"runtime"
"time"
) )
const ( const (
@ -15,45 +16,72 @@ const (
LevelFatal 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"} var LevelName [6]string = [6]string{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"}
type Logger struct { const TimeFormat = "2006/01/02 15:04:05"
logger *log.Logger
level int
handler Handler
}
const ( type Logger struct {
Ldate = log.Ldate level int
Ltime = log.Ltime flag int
Lmicroseconds = log.Lmicroseconds
Llongfile = log.Llongfile handler Handler
Lshortfile = log.Lshortfile
LstdFlags = Ldate | Ltime quit chan struct{}
) msg chan []byte
}
func New(handler Handler, flag int) *Logger { func New(handler Handler, flag int) *Logger {
var l = new(Logger) var l = new(Logger)
l.logger = log.New(handler, "", flag) //log.LstdFlags|log.Lshortfile)
l.level = LevelInfo l.level = LevelInfo
l.handler = handler l.handler = handler
l.flag = flag
l.quit = make(chan struct{})
l.msg = make(chan []byte, 1024)
go l.run()
return l return l
} }
func NewDefault(handler Handler) *Logger { func NewDefault(handler Handler) *Logger {
return New(handler, log.LstdFlags|log.Lshortfile) return New(handler, Ltime|Lfile|Llevel)
} }
func newStdHandler() *StreamHandler { func newStdHandler() *StreamHandler {
h, _ := NewDefaultStreamHandler(os.Stdout) h, _ := NewStreamHandler(os.Stdout)
return h return h
} }
var std = NewDefault(newStdHandler()) 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() { func (l *Logger) Close() {
l.handler.Close() if l.quit == nil {
return
}
close(l.quit)
l.quit = nil
} }
func (l *Logger) SetLevel(level int) { 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{}) { func (l *Logger) Output(callDepth int, level int, format string, v ...interface{}) {
if l.level <= level { if l.level > level {
f := fmt.Sprintf("[%s] %s", LevelName[level], format) return
s := fmt.Sprintf(f, v...)
l.logger.Output(callDepth, s)
} }
}
func (l *Logger) Write(s string) { buf := make([]byte, 0, 1024)
l.logger.Output(3, s)
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{}) { 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{}) { 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{}) { 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{}) { 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{}) { 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{}) { func (l *Logger) Fatal(format string, v ...interface{}) {
l.Output(3, LevelFatal, format, v...) l.Output(2, LevelFatal, format, v...)
} }
func SetLevel(level int) { func SetLevel(level int) {
@ -101,25 +159,25 @@ func SetLevel(level int) {
} }
func Trace(format string, v ...interface{}) { func Trace(format string, v ...interface{}) {
std.Output(3, LevelTrace, format, v...) std.Output(2, LevelTrace, format, v...)
} }
func Debug(format string, v ...interface{}) { func Debug(format string, v ...interface{}) {
std.Output(3, LevelDebug, format, v...) std.Output(2, LevelDebug, format, v...)
} }
func Info(format string, v ...interface{}) { func Info(format string, v ...interface{}) {
std.Output(3, LevelInfo, format, v...) std.Output(2, LevelInfo, format, v...)
} }
func Warn(format string, v ...interface{}) { func Warn(format string, v ...interface{}) {
std.Output(3, LevelWarn, format, v...) std.Output(2, LevelWarn, format, v...)
} }
func Error(format string, v ...interface{}) { func Error(format string, v ...interface{}) {
std.Output(3, LevelError, format, v...) std.Output(2, LevelError, format, v...)
} }
func Fatal(format string, v ...interface{}) { func Fatal(format string, v ...interface{}) {
std.Output(3, LevelFatal, format, v...) std.Output(2, LevelFatal, format, v...)
} }

View File

@ -6,7 +6,7 @@ import (
) )
func TestStdStreamLog(t *testing.T) { func TestStdStreamLog(t *testing.T) {
h, _ := NewDefaultStreamHandler(os.Stdout) h, _ := NewStreamHandler(os.Stdout)
s := NewDefault(h) s := NewDefault(h)
s.Info("hello world") s.Info("hello world")