171 lines
3.3 KiB
Go
171 lines
3.3 KiB
Go
package logger
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
type Level int8
|
|
|
|
type Fields map[string]interface{}
|
|
|
|
const (
|
|
LevelDebug Level = iota
|
|
LevelInfo
|
|
LevelWarn
|
|
LevelError
|
|
LevelFatal
|
|
LevelPanic
|
|
)
|
|
|
|
func (l Level) String() string {
|
|
switch l {
|
|
case LevelDebug:
|
|
return "debug"
|
|
case LevelInfo:
|
|
return "info"
|
|
case LevelWarn:
|
|
return "warn"
|
|
case LevelError:
|
|
return "error"
|
|
case LevelFatal:
|
|
return "fatal"
|
|
case LevelPanic:
|
|
return "panic"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
type Logger struct {
|
|
newLogger *log.Logger
|
|
ctx context.Context
|
|
fields Fields
|
|
callers []string
|
|
}
|
|
|
|
func NewLogger(w io.Writer, prefix string, flag int) *Logger {
|
|
l := log.New(w, prefix, flag)
|
|
return &Logger{newLogger: l}
|
|
}
|
|
|
|
func (l *Logger) clone() *Logger {
|
|
nl := *l
|
|
return &nl
|
|
}
|
|
|
|
func (l *Logger) WithFields(f Fields) *Logger {
|
|
ll := l.clone()
|
|
if ll.fields == nil {
|
|
ll.fields = make(Fields)
|
|
}
|
|
for k, v := range f {
|
|
ll.fields[k] = v
|
|
}
|
|
return ll
|
|
}
|
|
|
|
func (l *Logger) WithContext(ctx context.Context) *Logger {
|
|
ll := l.clone()
|
|
ll.ctx = ctx
|
|
return ll
|
|
}
|
|
|
|
func (l *Logger) WithCaller(skip int) *Logger {
|
|
ll := l.clone()
|
|
pc, file, line, ok := runtime.Caller(skip)
|
|
if ok {
|
|
f := runtime.FuncForPC(pc)
|
|
ll.callers = []string{fmt.Sprintf("%s: %d %s", file, line, f.Name())}
|
|
}
|
|
|
|
return ll
|
|
}
|
|
|
|
func (l *Logger) WithCallersFrames() *Logger {
|
|
maxCallerDepth := 25
|
|
minCallerDepth := 1
|
|
callers := []string{}
|
|
pcs := make([]uintptr, maxCallerDepth)
|
|
depth := runtime.Callers(minCallerDepth, pcs)
|
|
frames := runtime.CallersFrames(pcs[:depth])
|
|
for frame, more := frames.Next(); more; frame, more = frames.Next() {
|
|
callers = append(callers, fmt.Sprintf("%s: %d %s", frame.File, frame.Line, frame.Function))
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
ll := l.clone()
|
|
ll.callers = callers
|
|
return ll
|
|
}
|
|
|
|
func (l *Logger) JSONFormat(level Level, message string) map[string]interface{} {
|
|
data := make(Fields, len(l.fields)+4)
|
|
data["level"] = level.String()
|
|
data["time"] = time.Now().Local().UnixNano()
|
|
data["message"] = message
|
|
data["callers"] = l.callers
|
|
if len(l.fields) > 0 {
|
|
for k, v := range l.fields {
|
|
if _, ok := data[k]; !ok {
|
|
data[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
func (l *Logger) Output(level Level, message string) {
|
|
body, _ := json.Marshal(l.JSONFormat(level, message))
|
|
content := string(body)
|
|
switch level {
|
|
case LevelDebug:
|
|
l.newLogger.Print(content)
|
|
case LevelInfo:
|
|
l.newLogger.Print(content)
|
|
case LevelWarn:
|
|
l.newLogger.Print(content)
|
|
case LevelError:
|
|
l.newLogger.Print(content)
|
|
case LevelFatal:
|
|
l.newLogger.Fatal(content)
|
|
case LevelPanic:
|
|
l.newLogger.Panic(content)
|
|
}
|
|
}
|
|
|
|
func (l *Logger) Info(v ...interface{}) {
|
|
l.Output(LevelInfo, fmt.Sprint(v...))
|
|
}
|
|
|
|
func (l *Logger) Infof(format string, v ...interface{}) {
|
|
l.Output(LevelInfo, fmt.Sprintf(format, v...))
|
|
}
|
|
|
|
func (l *Logger) Fatal(v ...interface{}) {
|
|
l.Output(LevelFatal, fmt.Sprint(v...))
|
|
}
|
|
|
|
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
|
l.Output(LevelFatal, fmt.Sprintf(format, v...))
|
|
}
|
|
|
|
func (l *Logger) Error(v ...interface{}) {
|
|
l.Output(LevelError, fmt.Sprint(v...))
|
|
}
|
|
|
|
func (l *Logger) Errorf(format string, v ...interface{}) {
|
|
l.Output(LevelError, fmt.Sprintf(format, v...))
|
|
}
|
|
|
|
func (l *Logger) Panicf(format string, v ...interface{}) {
|
|
l.Output(LevelPanic, fmt.Sprintf(format, v...))
|
|
|
|
}
|