go/log/log.go

367 lines
6.7 KiB
Go
Raw Normal View History

2014-09-24 05:38:19 +04:00
package log
import (
"fmt"
"os"
"runtime"
"strconv"
2015-12-27 07:49:29 +03:00
"strings"
2014-09-24 05:38:19 +04:00
"sync"
2015-02-08 04:30:54 +03:00
"sync/atomic"
2014-09-24 05:38:19 +04:00
"time"
)
//log level, from low to high, more high means more serious
const (
LevelTrace = iota
LevelDebug
LevelInfo
LevelWarn
LevelError
LevelFatal
)
const (
Ltime = 1 << iota //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"}
const TimeFormat = "2006/01/02 15:04:05"
const maxBufPoolSize = 16
2015-02-08 04:30:54 +03:00
type atomicInt32 int32
func (i *atomicInt32) Set(n int) {
atomic.StoreInt32((*int32)(i), int32(n))
}
2014-09-24 05:38:19 +04:00
2015-02-08 04:30:54 +03:00
func (i *atomicInt32) Get() int {
return int(atomic.LoadInt32((*int32)(i)))
}
type Logger struct {
level atomicInt32
2014-09-24 05:38:19 +04:00
flag int
2015-02-08 04:30:54 +03:00
hMutex sync.Mutex
2014-09-24 05:38:19 +04:00
handler Handler
quit chan struct{}
msg chan []byte
2015-02-08 04:30:54 +03:00
bufMutex sync.Mutex
bufs [][]byte
2014-10-27 10:24:58 +03:00
wg sync.WaitGroup
2015-02-08 04:30:54 +03:00
closed atomicInt32
2014-09-24 05:38:19 +04:00
}
//new a logger with specified handler and flag
func New(handler Handler, flag int) *Logger {
var l = new(Logger)
2015-02-08 04:30:54 +03:00
l.level.Set(LevelInfo)
2014-09-24 05:38:19 +04:00
l.handler = handler
l.flag = flag
l.quit = make(chan struct{})
2015-02-08 04:30:54 +03:00
l.closed.Set(0)
2014-09-24 05:38:19 +04:00
l.msg = make(chan []byte, 1024)
l.bufs = make([][]byte, 0, 16)
2014-10-27 10:24:58 +03:00
l.wg.Add(1)
2014-09-24 05:38:19 +04:00
go l.run()
return l
}
//new a default logger with specified handler and flag: Ltime|Lfile|Llevel
func NewDefault(handler Handler) *Logger {
return New(handler, Ltime|Lfile|Llevel)
}
func newStdHandler() *StreamHandler {
h, _ := NewStreamHandler(os.Stdout)
return h
}
var std = NewDefault(newStdHandler())
func (l *Logger) run() {
2014-10-27 10:24:58 +03:00
defer l.wg.Done()
2014-09-24 05:38:19 +04:00
for {
select {
case msg := <-l.msg:
2015-02-08 04:30:54 +03:00
l.hMutex.Lock()
2014-09-24 05:38:19 +04:00
l.handler.Write(msg)
2015-02-08 04:30:54 +03:00
l.hMutex.Unlock()
2014-09-24 05:38:19 +04:00
l.putBuf(msg)
case <-l.quit:
2014-10-27 10:24:58 +03:00
//we must log all msg
if len(l.msg) == 0 {
return
}
2014-09-24 05:38:19 +04:00
}
}
}
func (l *Logger) popBuf() []byte {
2015-02-08 04:30:54 +03:00
l.bufMutex.Lock()
2014-09-24 05:38:19 +04:00
var buf []byte
if len(l.bufs) == 0 {
buf = make([]byte, 0, 1024)
} else {
buf = l.bufs[len(l.bufs)-1]
l.bufs = l.bufs[0 : len(l.bufs)-1]
}
2015-02-08 04:30:54 +03:00
l.bufMutex.Unlock()
2014-09-24 05:38:19 +04:00
return buf
}
func (l *Logger) putBuf(buf []byte) {
2015-02-08 04:30:54 +03:00
l.bufMutex.Lock()
2014-09-24 05:38:19 +04:00
if len(l.bufs) < maxBufPoolSize {
buf = buf[0:0]
l.bufs = append(l.bufs, buf)
}
2015-02-08 04:30:54 +03:00
l.bufMutex.Unlock()
2014-09-24 05:38:19 +04:00
}
func (l *Logger) Close() {
2015-02-08 04:30:54 +03:00
if l.closed.Get() == 1 {
2014-09-24 05:38:19 +04:00
return
}
2015-02-08 04:30:54 +03:00
l.closed.Set(1)
2014-09-24 05:38:19 +04:00
close(l.quit)
2014-10-27 10:24:58 +03:00
l.wg.Wait()
2014-09-24 05:38:19 +04:00
l.quit = nil
2014-10-27 10:24:58 +03:00
l.handler.Close()
2014-09-24 05:38:19 +04:00
}
//set log level, any log level less than it will not log
func (l *Logger) SetLevel(level int) {
2015-02-08 04:30:54 +03:00
l.level.Set(level)
}
2015-12-27 07:49:29 +03:00
// name can be in ["trace", "debug", "info", "warn", "error", "fatal"]
func (l *Logger) SetLevelByName(name string) {
name = strings.ToLower(name)
switch name {
case "trace":
l.SetLevel(LevelTrace)
case "debug":
l.SetLevel(LevelDebug)
case "info":
l.SetLevel(LevelInfo)
case "warn":
l.SetLevel(LevelWarn)
case "error":
l.SetLevel(LevelError)
case "fatal":
l.SetLevel(LevelFatal)
}
}
2015-02-08 04:30:54 +03:00
func (l *Logger) SetHandler(h Handler) {
if l.closed.Get() == 1 {
return
}
l.hMutex.Lock()
if l.handler != nil {
l.handler.Close()
}
l.handler = h
l.hMutex.Unlock()
2014-09-24 05:38:19 +04:00
}
func (l *Logger) Output(callDepth int, level int, s string) {
2015-02-08 04:30:54 +03:00
if l.closed.Get() == 1 {
// closed
2014-10-27 10:24:58 +03:00
return
}
2015-02-08 04:30:54 +03:00
if l.level.Get() > level {
// higher level can be logged
2014-09-24 05:38:19 +04:00
return
}
buf := l.popBuf()
if l.flag&Ltime > 0 {
now := time.Now().Format(TimeFormat)
buf = append(buf, '[')
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, file...)
buf = append(buf, ':')
buf = strconv.AppendInt(buf, int64(line), 10)
buf = append(buf, ' ')
}
if l.flag&Llevel > 0 {
buf = append(buf, '[')
buf = append(buf, LevelName[level]...)
buf = append(buf, "] "...)
}
buf = append(buf, s...)
if s[len(s)-1] != '\n' {
buf = append(buf, '\n')
}
l.msg <- buf
}
//log with Trace level
func (l *Logger) Trace(v ...interface{}) {
l.Output(2, LevelTrace, fmt.Sprint(v...))
2014-09-24 05:38:19 +04:00
}
//log with Debug level
func (l *Logger) Debug(v ...interface{}) {
l.Output(2, LevelDebug, fmt.Sprint(v...))
2014-09-24 05:38:19 +04:00
}
//log with info level
func (l *Logger) Info(v ...interface{}) {
l.Output(2, LevelInfo, fmt.Sprint(v...))
2014-09-24 05:38:19 +04:00
}
//log with warn level
func (l *Logger) Warn(v ...interface{}) {
l.Output(2, LevelWarn, fmt.Sprint(v...))
2014-09-24 05:38:19 +04:00
}
//log with error level
func (l *Logger) Error(v ...interface{}) {
l.Output(2, LevelError, fmt.Sprint(v...))
2014-09-24 05:38:19 +04:00
}
//log with fatal level
func (l *Logger) Fatal(v ...interface{}) {
l.Output(2, LevelFatal, fmt.Sprint(v...))
}
//log with Trace level
func (l *Logger) Tracef(format string, v ...interface{}) {
l.Output(2, LevelTrace, fmt.Sprintf(format, v...))
}
//log with Debug level
func (l *Logger) Debugf(format string, v ...interface{}) {
l.Output(2, LevelDebug, fmt.Sprintf(format, v...))
}
//log with info level
func (l *Logger) Infof(format string, v ...interface{}) {
l.Output(2, LevelInfo, fmt.Sprintf(format, v...))
}
//log with warn level
func (l *Logger) Warnf(format string, v ...interface{}) {
l.Output(2, LevelWarn, fmt.Sprintf(format, v...))
}
//log with error level
func (l *Logger) Errorf(format string, v ...interface{}) {
l.Output(2, LevelError, fmt.Sprintf(format, v...))
}
//log with fatal level
func (l *Logger) Fatalf(format string, v ...interface{}) {
l.Output(2, LevelFatal, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func SetLevel(level int) {
std.SetLevel(level)
}
2015-12-27 07:49:29 +03:00
// name can be in ["trace", "debug", "info", "warn", "error", "fatal"]
func SetLevelByName(name string) {
std.SetLevelByName(name)
}
2015-02-08 04:30:54 +03:00
func SetHandler(h Handler) {
std.SetHandler(h)
}
func Trace(v ...interface{}) {
std.Output(2, LevelTrace, fmt.Sprint(v...))
}
func Debug(v ...interface{}) {
std.Output(2, LevelDebug, fmt.Sprint(v...))
}
func Info(v ...interface{}) {
std.Output(2, LevelInfo, fmt.Sprint(v...))
}
func Warn(v ...interface{}) {
std.Output(2, LevelWarn, fmt.Sprint(v...))
}
func Error(v ...interface{}) {
std.Output(2, LevelError, fmt.Sprint(v...))
}
func Fatal(v ...interface{}) {
std.Output(2, LevelFatal, fmt.Sprint(v...))
}
func Tracef(format string, v ...interface{}) {
std.Output(2, LevelTrace, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func Debugf(format string, v ...interface{}) {
std.Output(2, LevelDebug, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func Infof(format string, v ...interface{}) {
std.Output(2, LevelInfo, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func Warnf(format string, v ...interface{}) {
std.Output(2, LevelWarn, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func Errorf(format string, v ...interface{}) {
std.Output(2, LevelError, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}
func Fatalf(format string, v ...interface{}) {
std.Output(2, LevelFatal, fmt.Sprintf(format, v...))
2014-09-24 05:38:19 +04:00
}