xlog/logger.go
2021-03-05 15:55:26 +08:00

219 lines
4.9 KiB
Go

package log
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/mattn/go-colorable"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Logger represents a logger
type Logger struct {
log *zap.SugaredLogger
f *os.File
Flags int `json:"flags"`
Filename string `json:"filename"`
Rotate bool `json:"rotate"`
Daily bool `json:"Daily"`
Maxdays int `json:"maxdays"`
StacktraceLevel string `json:"stacktraceLevel"`
Level string `json:"level"`
}
// NewLogger creates a new logger
func NewLogger(name, provider string, configJSON string) error {
logger, err := newLogger(name, provider, configJSON)
if err != nil {
return err
}
Default.loggers[name] = logger
return nil
}
// GetLogger returns the logger
func GetLogger(name string) *Logger {
return Default.loggers[name]
}
// DelLogger delete a log
func DelLogger(name string) {
delete(Default.loggers, name)
}
func convertLevel(lvl string) zapcore.Level {
switch lvl {
case "debug", "trace":
return zap.DebugLevel
case "warn":
return zap.WarnLevel
case "error":
return zap.ErrorLevel
case "critical":
return zap.PanicLevel
case "fatal":
return zap.FatalLevel
case "info":
fallthrough
default:
return zap.InfoLevel
}
}
func MyPath(ec zapcore.EntryCaller) string {
if !ec.Defined {
return "undefined"
}
idx := strings.LastIndexByte(ec.File, '/')
if idx == -1 {
return ec.FullPath()
}
// Find the penultimate separator.
idx = strings.LastIndexByte(ec.File[:idx], '/')
if idx == -1 {
return ec.FullPath()
}
var buf strings.Builder
// Keep everything after the penultimate separator.
buf.WriteString(ec.File[idx+1:])
buf.WriteByte(':')
buf.WriteString(fmt.Sprintf("%d", ec.Line))
return buf.String()
}
func MyCallerEncoder(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(MyPath(caller))
}
func newLogger(name, provider string, configJSON string) (*Logger, error) {
var l Logger
if configJSON != "" {
err := json.Unmarshal([]byte(configJSON), &l)
if err != nil {
return nil, err
}
}
encoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000"),
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: MyCallerEncoder, // 全路径编码器
ConsoleSeparator: " ",
}
var writeSyncers []zapcore.WriteSyncer
if provider == "console" {
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
writeSyncers = append(writeSyncers, zapcore.AddSync(colorable.NewColorableStdout()))
} else if provider == "file" {
if l.Filename == "" {
l.Filename = "xlog.log"
}
if l.Rotate {
if l.Maxdays == 0 {
l.Maxdays = 7
}
lumberJackLogger := &lumberjack.Logger{
Filename: l.Filename,
MaxBackups: l.Maxdays,
MaxAge: l.Maxdays,
Compress: false,
}
writeSyncers = append(writeSyncers, zapcore.AddSync(lumberJackLogger))
} else {
var err error
l.f, err = os.Create(l.Filename)
if err != nil {
return nil, err
}
writeSyncers = append(writeSyncers, zapcore.AddSync(l.f))
}
}
atomicLevel := zap.NewAtomicLevel()
atomicLevel.SetLevel(convertLevel(l.Level))
core := zapcore.NewCore(
zapcore.NewConsoleEncoder(encoderConfig),
zapcore.NewMultiWriteSyncer(writeSyncers...),
atomicLevel,
)
if l.StacktraceLevel == "" {
l.StacktraceLevel = "critical"
}
l.log = zap.New(core,
zap.AddCaller(),
zap.AddCallerSkip(3),
zap.AddStacktrace(convertLevel(l.StacktraceLevel)),
).Sugar()
return &l, nil
}
// GetLevel return the log level
func (l *Logger) GetLevel() string {
return l.Level
}
// Debug record debug log
func (l *Logger) Debug(format string, args ...interface{}) {
l.log.Debugf(format, args...)
}
// Trace record trace log
func (l *Logger) Trace(format string, args ...interface{}) {
l.log.Debugf(format, args...)
}
// Info record info log
func (l *Logger) Info(format string, args ...interface{}) {
l.log.Infof(format, args...)
}
// Warn record warn log
func (l *Logger) Warn(format string, args ...interface{}) {
l.log.Warnf(format, args...)
}
// Error record error log
func (l *Logger) Error(format string, args ...interface{}) {
l.log.Errorf(format, args...)
}
// Critical record critical error log
func (l *Logger) Critical(format string, args ...interface{}) {
l.log.Panicf(format, args...)
}
// Fatal record fatal log
func (l *Logger) Fatal(format string, args ...interface{}) {
l.log.Fatalf(format, args...)
}
// Close should be invoked before exit the program
func (l *Logger) Close() {
if l.log != nil {
l.log.Sync()
}
if l.f != nil {
l.f.Close()
}
}