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

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...))
}