You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
7.5 KiB
Go
359 lines
7.5 KiB
Go
package log
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/siddontang/go-log/loggers"
|
|
)
|
|
|
|
const (
|
|
timeFormat = "2006/01/02 15:04:05"
|
|
maxBufPoolSize = 16
|
|
)
|
|
|
|
// Logger flag
|
|
const (
|
|
Ltime = 1 << iota // time format "2006/01/02 15:04:05"
|
|
Lfile // file.go:123
|
|
Llevel // [Trace|Debug|Info...]
|
|
)
|
|
|
|
// Level type
|
|
type Level int
|
|
|
|
// Log level, from low to high, more high means more serious
|
|
const (
|
|
LevelTrace Level = iota
|
|
LevelDebug
|
|
LevelInfo
|
|
LevelWarn
|
|
LevelError
|
|
LevelFatal
|
|
)
|
|
|
|
// String returns level String
|
|
func (l Level) String() string {
|
|
switch l {
|
|
case LevelTrace:
|
|
return "trace"
|
|
case LevelDebug:
|
|
return "debug"
|
|
case LevelInfo:
|
|
return "info"
|
|
case LevelWarn:
|
|
return "warn"
|
|
case LevelError:
|
|
return "error"
|
|
case LevelFatal:
|
|
return "fatal"
|
|
}
|
|
// return default info
|
|
return "info"
|
|
}
|
|
|
|
// Logger is the logger to record log
|
|
type Logger struct {
|
|
// TODO: support logger.Contextual
|
|
loggers.Advanced
|
|
|
|
level Level
|
|
flag int
|
|
|
|
hLock sync.Mutex
|
|
handler Handler
|
|
|
|
bufs sync.Pool
|
|
}
|
|
|
|
// New creates a logger with specified handler and flag
|
|
func New(handler Handler, flag int) *Logger {
|
|
var l = new(Logger)
|
|
|
|
l.level = LevelInfo
|
|
l.handler = handler
|
|
|
|
l.flag = flag
|
|
|
|
l.bufs = sync.Pool{
|
|
New: func() interface{} {
|
|
return make([]byte, 0, 1024)
|
|
},
|
|
}
|
|
|
|
return l
|
|
}
|
|
|
|
// NewDefault creates 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
|
|
}
|
|
|
|
// Close closes the logger
|
|
func (l *Logger) Close() {
|
|
l.hLock.Lock()
|
|
defer l.hLock.Unlock()
|
|
l.handler.Close()
|
|
}
|
|
|
|
// SetLevel sets log level, any log level less than it will not log
|
|
func (l *Logger) SetLevel(level Level) {
|
|
l.level = level
|
|
}
|
|
|
|
// SetLevelByName sets log level by name
|
|
func (l *Logger) SetLevelByName(name string) {
|
|
level := LevelInfo
|
|
switch strings.ToLower(name) {
|
|
case "trace":
|
|
level = LevelTrace
|
|
case "debug":
|
|
level = LevelDebug
|
|
case "warn", "warning":
|
|
level = LevelWarn
|
|
case "error":
|
|
level = LevelError
|
|
case "fatal":
|
|
level = LevelFatal
|
|
default:
|
|
level = LevelInfo
|
|
}
|
|
|
|
l.SetLevel(level)
|
|
}
|
|
|
|
// Output records the log with special callstack depth and log level.
|
|
func (l *Logger) Output(callDepth int, level Level, msg string) {
|
|
if l.level > level {
|
|
return
|
|
}
|
|
|
|
buf := l.bufs.Get().([]byte)
|
|
buf = buf[0:0]
|
|
defer l.bufs.Put(buf)
|
|
|
|
if l.flag&Ltime > 0 {
|
|
now := time.Now().Format(timeFormat)
|
|
buf = append(buf, '[')
|
|
buf = append(buf, now...)
|
|
buf = append(buf, "] "...)
|
|
}
|
|
|
|
if l.flag&Llevel > 0 {
|
|
buf = append(buf, '[')
|
|
buf = append(buf, level.String()...)
|
|
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, ' ')
|
|
}
|
|
|
|
buf = append(buf, msg...)
|
|
if len(msg) == 0 || msg[len(msg)-1] != '\n' {
|
|
buf = append(buf, '\n')
|
|
}
|
|
|
|
l.hLock.Lock()
|
|
l.handler.Write(buf)
|
|
l.hLock.Unlock()
|
|
}
|
|
|
|
// Output json format records the log with special callstack depth and log level.
|
|
func (l *Logger) OutputJson(callDepth int, level Level, body interface{}) {
|
|
if l.level > level {
|
|
return
|
|
}
|
|
|
|
buf := l.bufs.Get().([]byte)
|
|
buf = buf[0:0]
|
|
defer l.bufs.Put(buf)
|
|
|
|
type JsonLog struct {
|
|
Time string `json:"log_time"`
|
|
Level string `json:"log_level"`
|
|
File string `json:"log_file"`
|
|
Line string `json:"log_line"`
|
|
Body interface{} `json:"log_body"`
|
|
}
|
|
|
|
var jsonlog JsonLog
|
|
if l.flag&Ltime > 0 {
|
|
now := time.Now().Format(timeFormat)
|
|
jsonlog.Time = now
|
|
}
|
|
|
|
if l.flag&Llevel > 0 {
|
|
jsonlog.Level = level.String()
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
jsonlog.File = file
|
|
jsonlog.Line = string(strconv.AppendInt(buf, int64(line), 10))
|
|
}
|
|
|
|
jsonlog.Body = body
|
|
|
|
msg, _ := json.Marshal(jsonlog)
|
|
msg = append(msg, '\n')
|
|
|
|
l.hLock.Lock()
|
|
l.handler.Write(msg)
|
|
l.hLock.Unlock()
|
|
}
|
|
|
|
// Fatal records the log with fatal level and exits
|
|
func (l *Logger) Fatal(args ...interface{}) {
|
|
l.Output(2, LevelFatal, fmt.Sprint(args...))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Fatalf records the log with fatal level and exits
|
|
func (l *Logger) Fatalf(format string, args ...interface{}) {
|
|
l.Output(2, LevelFatal, fmt.Sprintf(format, args...))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Fatalln records the log with fatal level and exits
|
|
func (l *Logger) Fatalln(args ...interface{}) {
|
|
l.Output(2, LevelFatal, fmt.Sprintln(args...))
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Panic records the log with fatal level and panics
|
|
func (l *Logger) Panic(args ...interface{}) {
|
|
msg := fmt.Sprint(args...)
|
|
l.Output(2, LevelError, msg)
|
|
panic(msg)
|
|
}
|
|
|
|
// Panicf records the log with fatal level and panics
|
|
func (l *Logger) Panicf(format string, args ...interface{}) {
|
|
msg := fmt.Sprintf(format, args...)
|
|
l.Output(2, LevelError, msg)
|
|
panic(msg)
|
|
}
|
|
|
|
// Panicln records the log with fatal level and panics
|
|
func (l *Logger) Panicln(args ...interface{}) {
|
|
msg := fmt.Sprintln(args...)
|
|
l.Output(2, LevelError, msg)
|
|
panic(msg)
|
|
}
|
|
|
|
// Print records the log with trace level
|
|
func (l *Logger) Print(args ...interface{}) {
|
|
l.Output(2, LevelTrace, fmt.Sprint(args...))
|
|
}
|
|
|
|
// Printf records the log with trace level
|
|
func (l *Logger) Printf(format string, args ...interface{}) {
|
|
l.Output(2, LevelTrace, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// Println records the log with trace level
|
|
func (l *Logger) Println(args ...interface{}) {
|
|
l.Output(2, LevelTrace, fmt.Sprintln(args...))
|
|
}
|
|
|
|
// Debug records the log with debug level
|
|
func (l *Logger) Debug(args ...interface{}) {
|
|
l.Output(2, LevelDebug, fmt.Sprint(args...))
|
|
}
|
|
|
|
// Debugf records the log with debug level
|
|
func (l *Logger) Debugf(format string, args ...interface{}) {
|
|
l.Output(2, LevelDebug, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// Debugln records the log with debug level
|
|
func (l *Logger) Debugln(args ...interface{}) {
|
|
l.Output(2, LevelDebug, fmt.Sprintln(args...))
|
|
}
|
|
|
|
// Error records the log with error level
|
|
func (l *Logger) Error(args ...interface{}) {
|
|
l.Output(2, LevelError, fmt.Sprint(args...))
|
|
}
|
|
|
|
// Errorf records the log with error level
|
|
func (l *Logger) Errorf(format string, args ...interface{}) {
|
|
l.Output(2, LevelError, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// Errorln records the log with error level
|
|
func (l *Logger) Errorln(args ...interface{}) {
|
|
l.Output(2, LevelError, fmt.Sprintln(args...))
|
|
}
|
|
|
|
// Info records the log with info level
|
|
func (l *Logger) Info(args ...interface{}) {
|
|
l.Output(2, LevelInfo, fmt.Sprint(args...))
|
|
}
|
|
|
|
// Infof records the log with info level
|
|
func (l *Logger) Infof(format string, args ...interface{}) {
|
|
l.Output(2, LevelInfo, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// Infoln records the log with info level
|
|
func (l *Logger) Infoln(args ...interface{}) {
|
|
l.Output(2, LevelInfo, fmt.Sprintln(args...))
|
|
}
|
|
|
|
// Warn records the log with warn level
|
|
func (l *Logger) Warn(args ...interface{}) {
|
|
l.Output(2, LevelWarn, fmt.Sprint(args...))
|
|
}
|
|
|
|
// Warnf records the log with warn level
|
|
func (l *Logger) Warnf(format string, args ...interface{}) {
|
|
l.Output(2, LevelWarn, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
// Warnln records the log with warn level
|
|
func (l *Logger) Warnln(args ...interface{}) {
|
|
l.Output(2, LevelWarn, fmt.Sprintln(args...))
|
|
}
|