add log
This commit is contained in:
parent
108b73122d
commit
eead8cb809
|
@ -0,0 +1,208 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type StreamHandler struct {
|
||||
base
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func NewStreamHandler(w io.Writer, msgNum int) (*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) run() {
|
||||
for {
|
||||
select {
|
||||
case m := <-h.msg:
|
||||
h.w.Write(m)
|
||||
case <-h.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type FileHandler struct {
|
||||
base
|
||||
fd *os.File
|
||||
}
|
||||
|
||||
func NewFileHandler(fileName string, flag int, msgNum int) (*FileHandler, error) {
|
||||
f, err := os.OpenFile(fileName, flag, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := new(FileHandler)
|
||||
|
||||
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) run() {
|
||||
for {
|
||||
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
|
||||
//same like python TimedRotatingFileHandler
|
||||
|
||||
type TimeRotatingFileHandler struct {
|
||||
base
|
||||
|
||||
fd *os.File
|
||||
|
||||
baseName string
|
||||
interval int64
|
||||
suffix string
|
||||
rolloverAt int64
|
||||
}
|
||||
|
||||
const (
|
||||
WhenSecond = iota
|
||||
WhenMinute
|
||||
WhenHour
|
||||
WhenDay
|
||||
)
|
||||
|
||||
func NewTimeRotatingFileHandler(baseName string, when int8, interval int, msgNum int) (*TimeRotatingFileHandler, error) {
|
||||
h := new(TimeRotatingFileHandler)
|
||||
|
||||
h.baseName = baseName
|
||||
|
||||
switch when {
|
||||
case WhenSecond:
|
||||
h.interval = 1
|
||||
h.suffix = "2006-01-02_15-04-05"
|
||||
case WhenMinute:
|
||||
h.interval = 60
|
||||
h.suffix = "2006-01-02_15-04"
|
||||
case WhenHour:
|
||||
h.interval = 3600
|
||||
h.suffix = "2006-01-02_15"
|
||||
case WhenDay:
|
||||
h.interval = 3600 * 24
|
||||
h.suffix = "2006-01-02"
|
||||
default:
|
||||
e := fmt.Errorf("invalid when_rotate: %d", when)
|
||||
panic(e)
|
||||
}
|
||||
|
||||
h.interval = h.interval * int64(interval)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
if h.rolloverAt <= now.Unix() {
|
||||
fName := h.baseName + now.Format(h.suffix)
|
||||
h.fd.Close()
|
||||
e := os.Rename(h.baseName, fName)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
|
||||
h.rolloverAt = time.Now().Unix() + h.interval
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
LevelTrace = iota
|
||||
LevelDebug
|
||||
LevelInfo
|
||||
LevelWarn
|
||||
LevelError
|
||||
LevelFatal
|
||||
)
|
||||
|
||||
var LevelName [6]string = [6]string{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"}
|
||||
|
||||
type QLogger struct {
|
||||
logger *log.Logger
|
||||
level int
|
||||
handler Handler
|
||||
}
|
||||
|
||||
func New(handler Handler, flag int) *QLogger {
|
||||
var l = new(QLogger)
|
||||
l.logger = log.New(handler, "", flag) //log.LstdFlags|log.Lshortfile)
|
||||
l.level = LevelInfo
|
||||
l.handler = handler
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func NewDefault(handler Handler) *QLogger {
|
||||
return New(handler, log.LstdFlags|log.Lshortfile)
|
||||
}
|
||||
|
||||
func newStdHandler() *StreamHandler {
|
||||
h, _ := NewDefaultStreamHandler(os.Stdout)
|
||||
return h
|
||||
}
|
||||
|
||||
var std = NewDefault(newStdHandler())
|
||||
|
||||
func (l *QLogger) Close() {
|
||||
l.handler.Close()
|
||||
}
|
||||
|
||||
func (l *QLogger) SetLevel(level int) {
|
||||
l.level = level
|
||||
}
|
||||
|
||||
func (l *QLogger) 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)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *QLogger) Write(s string) {
|
||||
l.logger.Output(3, s)
|
||||
}
|
||||
|
||||
func (l *QLogger) Trace(format string, v ...interface{}) {
|
||||
l.Output(3, LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
func (l *QLogger) Debug(format string, v ...interface{}) {
|
||||
l.Output(3, LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
func (l *QLogger) Info(format string, v ...interface{}) {
|
||||
l.Output(3, LevelInfo, format, v...)
|
||||
}
|
||||
|
||||
func (l *QLogger) Warn(format string, v ...interface{}) {
|
||||
l.Output(3, LevelWarn, format, v...)
|
||||
}
|
||||
|
||||
func (l *QLogger) Error(format string, v ...interface{}) {
|
||||
l.Output(3, LevelError, format, v...)
|
||||
}
|
||||
|
||||
func (l *QLogger) Fatal(format string, v ...interface{}) {
|
||||
l.Output(3, LevelFatal, format, v...)
|
||||
}
|
||||
|
||||
func SetLevel(level int) {
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
func Trace(format string, v ...interface{}) {
|
||||
std.Output(3, LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
func Debug(format string, v ...interface{}) {
|
||||
std.Output(3, LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
func Info(format string, v ...interface{}) {
|
||||
std.Output(3, LevelInfo, format, v...)
|
||||
}
|
||||
|
||||
func Warn(format string, v ...interface{}) {
|
||||
std.Output(3, LevelWarn, format, v...)
|
||||
}
|
||||
|
||||
func Error(format string, v ...interface{}) {
|
||||
std.Output(3, LevelError, format, v...)
|
||||
}
|
||||
|
||||
func Fatal(format string, v ...interface{}) {
|
||||
std.Output(3, LevelFatal, format, v...)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStdStreamLog(t *testing.T) {
|
||||
h, _ := NewDefaultStreamHandler(os.Stdout)
|
||||
s := NewDefault(h)
|
||||
s.Info("hello world")
|
||||
|
||||
s.Close()
|
||||
|
||||
Info("hello world")
|
||||
}
|
Loading…
Reference in New Issue