diff --git a/vendor/github.com/siddontang/go/log/doc.go b/vendor/github.com/siddontang/go/log/doc.go new file mode 100644 index 0000000..81a60ee --- /dev/null +++ b/vendor/github.com/siddontang/go/log/doc.go @@ -0,0 +1,21 @@ +// log package supplies more advanced features than go orign log package. +// +// It supports log different level: trace, debug, info, warn, error, fatal. +// +// It also supports different log handlers which you can log to stdout, file, socket, etc... +// +// Use +// +// import "github.com/siddontang/go/log" +// +// //log with different level +// log.Info("hello world") +// log.Error("hello world") +// +// //create a logger with specified handler +// h := NewStreamHandler(os.Stdout) +// l := log.NewDefault(h) +// l.Info("hello world") +// l.Infof("%s %d", "hello", 123) +// +package log diff --git a/vendor/github.com/siddontang/go/log/filehandler.go b/vendor/github.com/siddontang/go/log/filehandler.go new file mode 100644 index 0000000..308896a --- /dev/null +++ b/vendor/github.com/siddontang/go/log/filehandler.go @@ -0,0 +1,200 @@ +package log + +import ( + "fmt" + "os" + "path" + "time" +) + +//FileHandler writes log to a file. +type FileHandler struct { + fd *os.File +} + +func NewFileHandler(fileName string, flag int) (*FileHandler, error) { + dir := path.Dir(fileName) + os.Mkdir(dir, 0777) + + f, err := os.OpenFile(fileName, flag, 0) + if err != nil { + return nil, err + } + + h := new(FileHandler) + + h.fd = f + + return h, nil +} + +func (h *FileHandler) Write(b []byte) (n int, err error) { + return h.fd.Write(b) +} + +func (h *FileHandler) Close() error { + return h.fd.Close() +} + +//RotatingFileHandler writes log a file, if file size exceeds maxBytes, +//it will backup current file and open a new one. +// +//max backup file number is set by backupCount, it will delete oldest if backups too many. +type RotatingFileHandler struct { + fd *os.File + + fileName string + maxBytes int + backupCount int +} + +func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) { + dir := path.Dir(fileName) + os.Mkdir(dir, 0777) + + h := new(RotatingFileHandler) + + if maxBytes <= 0 { + return nil, fmt.Errorf("invalid max bytes") + } + + h.fileName = fileName + h.maxBytes = maxBytes + h.backupCount = backupCount + + var err error + h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + return nil, err + } + + return h, nil +} + +func (h *RotatingFileHandler) Write(p []byte) (n int, err error) { + h.doRollover() + return h.fd.Write(p) +} + +func (h *RotatingFileHandler) Close() error { + if h.fd != nil { + return h.fd.Close() + } + return nil +} + +func (h *RotatingFileHandler) doRollover() { + f, err := h.fd.Stat() + if err != nil { + return + } + + if h.maxBytes <= 0 { + return + } else if f.Size() < int64(h.maxBytes) { + return + } + + if h.backupCount > 0 { + h.fd.Close() + + for i := h.backupCount - 1; i > 0; i-- { + sfn := fmt.Sprintf("%s.%d", h.fileName, i) + dfn := fmt.Sprintf("%s.%d", h.fileName, i+1) + + os.Rename(sfn, dfn) + } + + dfn := fmt.Sprintf("%s.1", h.fileName) + os.Rename(h.fileName, dfn) + + h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + } +} + +//TimeRotatingFileHandler writes log to a file, +//it will backup current and open a new one, with a period time you sepecified. +// +//refer: http://docs.python.org/2/library/logging.handlers.html. +//same like python TimedRotatingFileHandler. +type TimeRotatingFileHandler struct { + 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) (*TimeRotatingFileHandler, error) { + dir := path.Dir(baseName) + os.Mkdir(dir, 0777) + + 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: + return nil, fmt.Errorf("invalid when_rotate: %d", when) + } + + 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 { + return nil, err + } + + fInfo, _ := h.fd.Stat() + h.rolloverAt = fInfo.ModTime().Unix() + h.interval + + return h, nil +} + +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) Write(b []byte) (n int, err error) { + h.doRollover() + return h.fd.Write(b) +} + +func (h *TimeRotatingFileHandler) Close() error { + return h.fd.Close() +} diff --git a/vendor/github.com/siddontang/go/log/handler.go b/vendor/github.com/siddontang/go/log/handler.go new file mode 100644 index 0000000..4dc086f --- /dev/null +++ b/vendor/github.com/siddontang/go/log/handler.go @@ -0,0 +1,48 @@ +package log + +import ( + "io" +) + +//Handler writes logs to somewhere +type Handler interface { + Write(p []byte) (n int, err error) + Close() error +} + +//StreamHandler writes logs to a specified io Writer, maybe stdout, stderr, etc... +type StreamHandler struct { + w io.Writer +} + +func NewStreamHandler(w io.Writer) (*StreamHandler, error) { + h := new(StreamHandler) + + h.w = w + + return h, nil +} + +func (h *StreamHandler) Write(b []byte) (n int, err error) { + return h.w.Write(b) +} + +func (h *StreamHandler) Close() error { + return nil +} + +//NullHandler does nothing, it discards anything. +type NullHandler struct { +} + +func NewNullHandler() (*NullHandler, error) { + return new(NullHandler), nil +} + +func (h *NullHandler) Write(b []byte) (n int, err error) { + return len(b), nil +} + +func (h *NullHandler) Close() { + +} diff --git a/vendor/github.com/siddontang/go/log/log.go b/vendor/github.com/siddontang/go/log/log.go new file mode 100644 index 0000000..f2e5ef2 --- /dev/null +++ b/vendor/github.com/siddontang/go/log/log.go @@ -0,0 +1,366 @@ +package log + +import ( + "fmt" + "os" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "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 + +type atomicInt32 int32 + +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 + + hMutex sync.Mutex + handler Handler + + quit chan struct{} + msg chan []byte + + bufMutex sync.Mutex + bufs [][]byte + + wg sync.WaitGroup + + closed atomicInt32 +} + +//new a logger with specified handler and flag +func New(handler Handler, flag int) *Logger { + var l = new(Logger) + + l.level.Set(LevelInfo) + l.handler = handler + + l.flag = flag + + l.quit = make(chan struct{}) + l.closed.Set(0) + + l.msg = make(chan []byte, 1024) + + l.bufs = make([][]byte, 0, 16) + + l.wg.Add(1) + 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() { + defer l.wg.Done() + for { + select { + case msg := <-l.msg: + l.hMutex.Lock() + l.handler.Write(msg) + l.hMutex.Unlock() + l.putBuf(msg) + case <-l.quit: + //we must log all msg + if len(l.msg) == 0 { + return + } + } + } +} + +func (l *Logger) popBuf() []byte { + l.bufMutex.Lock() + 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] + } + l.bufMutex.Unlock() + + return buf +} + +func (l *Logger) putBuf(buf []byte) { + l.bufMutex.Lock() + if len(l.bufs) < maxBufPoolSize { + buf = buf[0:0] + l.bufs = append(l.bufs, buf) + } + l.bufMutex.Unlock() +} + +func (l *Logger) Close() { + if l.closed.Get() == 1 { + return + } + l.closed.Set(1) + + close(l.quit) + + l.wg.Wait() + + l.quit = nil + + l.handler.Close() +} + +//set log level, any log level less than it will not log +func (l *Logger) SetLevel(level int) { + l.level.Set(level) +} + +// 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) + } +} + +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() +} + +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 + } + + 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...)) +} + +//log with Debug level +func (l *Logger) Debug(v ...interface{}) { + l.Output(2, LevelDebug, fmt.Sprint(v...)) +} + +//log with info level +func (l *Logger) Info(v ...interface{}) { + l.Output(2, LevelInfo, fmt.Sprint(v...)) +} + +//log with warn level +func (l *Logger) Warn(v ...interface{}) { + l.Output(2, LevelWarn, fmt.Sprint(v...)) +} + +//log with error level +func (l *Logger) Error(v ...interface{}) { + l.Output(2, LevelError, fmt.Sprint(v...)) +} + +//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...)) +} + +func SetLevel(level int) { + std.SetLevel(level) +} + +// name can be in ["trace", "debug", "info", "warn", "error", "fatal"] +func SetLevelByName(name string) { + std.SetLevelByName(name) +} + +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...)) +} + +func Debugf(format string, v ...interface{}) { + std.Output(2, LevelDebug, fmt.Sprintf(format, v...)) +} + +func Infof(format string, v ...interface{}) { + std.Output(2, LevelInfo, fmt.Sprintf(format, v...)) +} + +func Warnf(format string, v ...interface{}) { + std.Output(2, LevelWarn, fmt.Sprintf(format, v...)) +} + +func Errorf(format string, v ...interface{}) { + std.Output(2, LevelError, fmt.Sprintf(format, v...)) +} + +func Fatalf(format string, v ...interface{}) { + std.Output(2, LevelFatal, fmt.Sprintf(format, v...)) +} diff --git a/vendor/github.com/siddontang/go/log/sockethandler.go b/vendor/github.com/siddontang/go/log/sockethandler.go new file mode 100644 index 0000000..3e7494d --- /dev/null +++ b/vendor/github.com/siddontang/go/log/sockethandler.go @@ -0,0 +1,65 @@ +package log + +import ( + "encoding/binary" + "net" + "time" +) + +//SocketHandler writes log to a connectionl. +//Network protocol is simple: log length + log | log length + log. log length is uint32, bigendian. +//you must implement your own log server, maybe you can use logd instead simply. +type SocketHandler struct { + c net.Conn + protocol string + addr string +} + +func NewSocketHandler(protocol string, addr string) (*SocketHandler, error) { + s := new(SocketHandler) + + s.protocol = protocol + s.addr = addr + + return s, nil +} + +func (h *SocketHandler) Write(p []byte) (n int, err error) { + if err = h.connect(); err != nil { + return + } + + buf := make([]byte, len(p)+4) + + binary.BigEndian.PutUint32(buf, uint32(len(p))) + + copy(buf[4:], p) + + n, err = h.c.Write(buf) + if err != nil { + h.c.Close() + h.c = nil + } + return +} + +func (h *SocketHandler) Close() error { + if h.c != nil { + h.c.Close() + } + return nil +} + +func (h *SocketHandler) connect() error { + if h.c != nil { + return nil + } + + var err error + h.c, err = net.DialTimeout(h.protocol, h.addr, 20*time.Second) + if err != nil { + return err + } + + return nil +}