mirror of https://github.com/siddontang/go.git
refactor log
This commit is contained in:
parent
e009b5fbd8
commit
ec6187efd9
110
log/handler.go
110
log/handler.go
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
132
log/log.go
132
log/log.go
|
@ -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...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue