mirror of https://github.com/siddontang/go.git
add SetHandler, enhance threadsafe
This commit is contained in:
parent
c2b3327130
commit
dfa1fad4a1
65
log/log.go
65
log/log.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,35 +32,45 @@ const TimeFormat = "2006/01/02 15:04:05"
|
||||||
|
|
||||||
const maxBufPoolSize = 16
|
const maxBufPoolSize = 16
|
||||||
|
|
||||||
type Logger struct {
|
type atomicInt32 int32
|
||||||
sync.Mutex
|
|
||||||
|
|
||||||
level int
|
func (i *atomicInt32) Set(n int) {
|
||||||
|
atomic.StoreInt32((*int32)(i), int32(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *atomicInt32) Get() int {
|
||||||
|
return int(atomic.LoadInt32((*int32)(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
level atomicInt32
|
||||||
flag int
|
flag int
|
||||||
|
|
||||||
|
hMutex sync.Mutex
|
||||||
handler Handler
|
handler Handler
|
||||||
|
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
msg chan []byte
|
msg chan []byte
|
||||||
|
|
||||||
|
bufMutex sync.Mutex
|
||||||
bufs [][]byte
|
bufs [][]byte
|
||||||
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
|
||||||
closed bool
|
closed atomicInt32
|
||||||
}
|
}
|
||||||
|
|
||||||
//new a logger with specified handler and flag
|
//new a logger with specified handler and flag
|
||||||
func New(handler Handler, flag int) *Logger {
|
func New(handler Handler, flag int) *Logger {
|
||||||
var l = new(Logger)
|
var l = new(Logger)
|
||||||
|
|
||||||
l.level = LevelInfo
|
l.level.Set(LevelInfo)
|
||||||
l.handler = handler
|
l.handler = handler
|
||||||
|
|
||||||
l.flag = flag
|
l.flag = flag
|
||||||
|
|
||||||
l.quit = make(chan struct{})
|
l.quit = make(chan struct{})
|
||||||
l.closed = false
|
l.closed.Set(0)
|
||||||
|
|
||||||
l.msg = make(chan []byte, 1024)
|
l.msg = make(chan []byte, 1024)
|
||||||
|
|
||||||
|
@ -88,7 +99,9 @@ func (l *Logger) run() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg := <-l.msg:
|
case msg := <-l.msg:
|
||||||
|
l.hMutex.Lock()
|
||||||
l.handler.Write(msg)
|
l.handler.Write(msg)
|
||||||
|
l.hMutex.Unlock()
|
||||||
l.putBuf(msg)
|
l.putBuf(msg)
|
||||||
case <-l.quit:
|
case <-l.quit:
|
||||||
//we must log all msg
|
//we must log all msg
|
||||||
|
@ -100,7 +113,7 @@ func (l *Logger) run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) popBuf() []byte {
|
func (l *Logger) popBuf() []byte {
|
||||||
l.Lock()
|
l.bufMutex.Lock()
|
||||||
var buf []byte
|
var buf []byte
|
||||||
if len(l.bufs) == 0 {
|
if len(l.bufs) == 0 {
|
||||||
buf = make([]byte, 0, 1024)
|
buf = make([]byte, 0, 1024)
|
||||||
|
@ -108,25 +121,25 @@ func (l *Logger) popBuf() []byte {
|
||||||
buf = l.bufs[len(l.bufs)-1]
|
buf = l.bufs[len(l.bufs)-1]
|
||||||
l.bufs = l.bufs[0 : len(l.bufs)-1]
|
l.bufs = l.bufs[0 : len(l.bufs)-1]
|
||||||
}
|
}
|
||||||
l.Unlock()
|
l.bufMutex.Unlock()
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) putBuf(buf []byte) {
|
func (l *Logger) putBuf(buf []byte) {
|
||||||
l.Lock()
|
l.bufMutex.Lock()
|
||||||
if len(l.bufs) < maxBufPoolSize {
|
if len(l.bufs) < maxBufPoolSize {
|
||||||
buf = buf[0:0]
|
buf = buf[0:0]
|
||||||
l.bufs = append(l.bufs, buf)
|
l.bufs = append(l.bufs, buf)
|
||||||
}
|
}
|
||||||
l.Unlock()
|
l.bufMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Close() {
|
func (l *Logger) Close() {
|
||||||
if l.closed {
|
if l.closed.Get() == 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.closed = true
|
l.closed.Set(1)
|
||||||
|
|
||||||
close(l.quit)
|
close(l.quit)
|
||||||
|
|
||||||
|
@ -139,16 +152,30 @@ func (l *Logger) Close() {
|
||||||
|
|
||||||
//set log level, any log level less than it will not log
|
//set log level, any log level less than it will not log
|
||||||
func (l *Logger) SetLevel(level int) {
|
func (l *Logger) SetLevel(level int) {
|
||||||
l.level = level
|
l.level.Set(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) Output(callDepth int, level int, s string) {
|
func (l *Logger) SetHandler(h Handler) {
|
||||||
if l.closed {
|
if l.closed.Get() == 1 {
|
||||||
//closed
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.level > level {
|
l.hMutex.Lock()
|
||||||
|
if l.handler != nil {
|
||||||
|
l.handler.Close()
|
||||||
|
}
|
||||||
|
l.handler = h
|
||||||
|
l.hMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Output(callDepth int, level int, s string) {
|
||||||
|
if l.closed.Get() == 1 {
|
||||||
|
// closed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.level.Get() > level {
|
||||||
|
// higher level can be logged
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,6 +288,10 @@ func SetLevel(level int) {
|
||||||
std.SetLevel(level)
|
std.SetLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetHandler(h Handler) {
|
||||||
|
std.SetHandler(h)
|
||||||
|
}
|
||||||
|
|
||||||
func Trace(v ...interface{}) {
|
func Trace(v ...interface{}) {
|
||||||
std.Output(2, LevelTrace, fmt.Sprint(v...))
|
std.Output(2, LevelTrace, fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,14 @@ func TestStdStreamLog(t *testing.T) {
|
||||||
|
|
||||||
Info("hello world")
|
Info("hello world")
|
||||||
|
|
||||||
|
SetHandler(os.Stderr)
|
||||||
|
|
||||||
Infof("%s %d", "Hello", 123)
|
Infof("%s %d", "Hello", 123)
|
||||||
|
|
||||||
|
SetLevel(LevelError)
|
||||||
|
|
||||||
|
Infof("%s %d", "Hello", 123)
|
||||||
|
Fatalf("%s %d", "Hello", 123)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRotatingFileLog(t *testing.T) {
|
func TestRotatingFileLog(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue