admin / modules /logger /logger.go
AZLABS's picture
Upload folder using huggingface_hub
530729e verified
// Copyright 2019 GoAdmin Core Team. All rights reserved.
// Use of this source code is governed by a Apache-2.0 style
// license that can be found in the LICENSE file.
package logger
import (
"fmt"
"os"
"path/filepath"
"strconv"
"github.com/GoAdminGroup/go-admin/context"
"github.com/GoAdminGroup/go-admin/modules/trace"
"github.com/GoAdminGroup/go-admin/modules/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
var (
defaultEncoderCfg = EncoderCfg{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
Level: "capitalColor",
Time: "ISO8601",
Duration: "seconds",
Caller: "short",
Encoding: "console",
}
defaultRotateCfg = RotateCfg{
MaxSize: 10,
MaxBackups: 5,
MaxAge: 30,
Compress: false,
}
logger = &Logger{
rotate: defaultRotateCfg,
encoder: defaultEncoderCfg,
Level: zapcore.InfoLevel,
}
infoLevelEnabler = zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.InfoLevel
})
errorLevelEnabler = zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.ErrorLevel
})
accessLevelEnabler = zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.WarnLevel
})
)
func init() {
logger.Init()
}
type Logger struct {
logger *zap.Logger
sugaredLogger *zap.SugaredLogger
infoLogOff bool
errorLogOff bool
accessLogOff bool
accessAssetsLogOff bool
debug bool
sqlLogOpen bool
infoLogPath string
errorLogPath string
accessLogPath string
rotate RotateCfg
encoder EncoderCfg
Level zapcore.Level
}
type EncoderCfg struct {
TimeKey string
LevelKey string
NameKey string
CallerKey string
MessageKey string
StacktraceKey string
Level string
Time string
Duration string
Caller string
Encoding string
}
type RotateCfg struct {
MaxSize int
MaxBackups int
MaxAge int
Compress bool
}
func (l *Logger) Init() {
zapLogger := zap.New(zapcore.NewTee(
zapcore.NewCore(l.getEncoder(l.encoder.LevelKey), l.getLogWriter(l.infoLogPath), infoLevelEnabler),
zapcore.NewCore(l.getEncoder(l.encoder.LevelKey), l.getLogWriter(l.errorLogPath), errorLevelEnabler),
zapcore.NewCore(l.getEncoder(""), l.getLogWriter(l.accessLogPath), accessLevelEnabler),
), zap.AddCaller(), zap.AddCallerSkip(1), zap.AddStacktrace(errorLevelEnabler))
l.sugaredLogger = zapLogger.Sugar()
l.logger = zapLogger
}
func (l *Logger) getEncoder(levelKey string) zapcore.Encoder {
var (
timeEncoder = new(zapcore.TimeEncoder)
durationEncoder = new(zapcore.DurationEncoder)
callerEncoder = new(zapcore.CallerEncoder)
nameEncoder = new(zapcore.NameEncoder)
levelEncoder = new(zapcore.LevelEncoder)
)
_ = timeEncoder.UnmarshalText([]byte(l.encoder.Time))
_ = durationEncoder.UnmarshalText([]byte(l.encoder.Duration))
_ = callerEncoder.UnmarshalText([]byte(l.encoder.Caller))
_ = nameEncoder.UnmarshalText([]byte("full"))
_ = levelEncoder.UnmarshalText([]byte(l.encoder.Level))
encoderConfig := zapcore.EncoderConfig{
TimeKey: l.encoder.TimeKey,
LevelKey: levelKey,
NameKey: l.encoder.NameKey,
CallerKey: l.encoder.CallerKey,
MessageKey: l.encoder.MessageKey,
StacktraceKey: l.encoder.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: *levelEncoder,
EncodeTime: *timeEncoder,
EncodeDuration: *durationEncoder,
EncodeCaller: *callerEncoder,
EncodeName: *nameEncoder,
}
return filterZapEncoder(l.encoder.Encoding, encoderConfig)
}
func (l *Logger) getLogWriter(path string) zapcore.WriteSyncer {
if path != "" {
lumberJackLogger := &lumberjack.Logger{
Filename: path,
MaxSize: l.rotate.MaxSize,
MaxBackups: l.rotate.MaxBackups,
MaxAge: l.rotate.MaxAge,
Compress: l.rotate.Compress,
}
if l.debug {
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
}
return zapcore.AddSync(lumberJackLogger)
}
return zapcore.AddSync(os.Stdout)
}
func (l *Logger) SetRotate(cfg RotateCfg) {
if cfg.MaxSize != 0 && cfg.MaxAge != 0 && cfg.MaxBackups != 0 {
l.rotate = cfg
}
}
func (l *Logger) SetEncoder(cfg EncoderCfg) {
cfg.TimeKey = utils.SetDefault(cfg.TimeKey, "", defaultEncoderCfg.TimeKey)
cfg.LevelKey = utils.SetDefault(cfg.LevelKey, "", defaultEncoderCfg.LevelKey)
cfg.NameKey = utils.SetDefault(cfg.NameKey, "", defaultEncoderCfg.NameKey)
cfg.CallerKey = utils.SetDefault(cfg.CallerKey, "", defaultEncoderCfg.CallerKey)
cfg.MessageKey = utils.SetDefault(cfg.MessageKey, "", defaultEncoderCfg.MessageKey)
cfg.StacktraceKey = utils.SetDefault(cfg.StacktraceKey, "", defaultEncoderCfg.StacktraceKey)
cfg.Level = utils.SetDefault(cfg.Level, "", defaultEncoderCfg.Level)
cfg.Time = utils.SetDefault(cfg.Time, "", defaultEncoderCfg.Time)
cfg.Duration = utils.SetDefault(cfg.Duration, "", defaultEncoderCfg.Duration)
cfg.Caller = utils.SetDefault(cfg.Caller, "", defaultEncoderCfg.Caller)
cfg.Encoding = utils.SetDefault(cfg.Encoding, "", defaultEncoderCfg.Encoding)
l.encoder = cfg
}
type Config struct {
InfoLogOff bool
ErrorLogOff bool
AccessLogOff bool
SqlLogOpen bool
InfoLogPath string
ErrorLogPath string
AccessLogPath string
AccessAssetsLogOff bool
Rotate RotateCfg
Encode EncoderCfg
Level int8
Debug bool
}
func InitWithConfig(cfg Config) {
logger.infoLogPath = cfg.InfoLogPath
logger.infoLogOff = cfg.InfoLogOff
logger.errorLogPath = cfg.ErrorLogPath
logger.errorLogOff = cfg.ErrorLogOff
logger.accessLogPath = cfg.AccessLogPath
logger.accessLogOff = cfg.AccessLogOff
logger.sqlLogOpen = cfg.SqlLogOpen
logger.accessAssetsLogOff = cfg.AccessAssetsLogOff
logger.debug = cfg.Debug
logger.SetRotate(cfg.Rotate)
logger.SetEncoder(cfg.Encode)
logger.Level = filterZapAtomicLevelByViper(cfg.Level)
logger.Init()
}
func SetRotate(cfg RotateCfg) {
logger.rotate = cfg
logger.Init()
}
// OpenSQLLog set the sqlLogOpen true.
func OpenSQLLog() {
logger.sqlLogOpen = true
}
// Debug print the debug message.
func Debug(info ...interface{}) {
if !logger.infoLogOff {
if logger.Level <= zapcore.DebugLevel {
logger.sugaredLogger.Info(info...)
}
}
}
// Debugf print the debug message.
func Debugf(template string, args ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.DebugLevel {
logger.sugaredLogger.Infof(template, args...)
}
}
// Info print the info message.
func Info(info ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.InfoLevel {
logger.sugaredLogger.Info(info...)
}
}
// InfoCtx print the info message with ctx.
func InfoCtx(ctx *context.Context, format string, args ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.InfoLevel {
logCtx(ctx, logger.logger.Info, format, args...)
}
}
type logFunc func(msg string, fields ...zapcore.Field)
func logCtx(ctx *context.Context, logFunc logFunc, format string, args ...interface{}) {
logFunc(fmt.Sprintf(format, args...), zap.String("traceID", trace.GetTraceID(ctx)))
}
// Info print the info message.
func Infof(template string, args ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.InfoLevel {
logger.sugaredLogger.Infof(template, args...)
}
}
// Warn print the warning message.
func Warn(info ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.WarnLevel {
logger.sugaredLogger.Warn(info...)
}
}
// WarnCtx print the warning message with ctx.
func WarnCtx(ctx *context.Context, format string, args ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.WarnLevel {
logCtx(ctx, logger.logger.Warn, format, args...)
}
}
// Warnf print the warning message.
func Warnf(template string, args ...interface{}) {
if !logger.infoLogOff && logger.Level <= zapcore.WarnLevel {
logger.sugaredLogger.Warnf(template, args...)
}
}
// Error print the error message.
func Error(err ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.ErrorLevel {
logger.sugaredLogger.Error(err...)
}
}
// ErrorCtx print the error message with ctx.
func ErrorCtx(ctx *context.Context, format string, args ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.ErrorLevel {
logCtx(ctx, logger.logger.Error, format, args...)
}
}
// Errorf print the error message.
func Errorf(template string, args ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.ErrorLevel {
logger.sugaredLogger.Errorf(template, args...)
}
}
// Fatal print the fatal message.
func Fatal(info ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.ErrorLevel {
logger.sugaredLogger.Fatal(info...)
}
}
// FatalCtx print the fatal message with ctx.
func FatalCtx(ctx *context.Context, format string, args ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.FatalLevel {
logCtx(ctx, logger.logger.Fatal, format, args...)
}
}
// Fatalf print the fatal message.
func Fatalf(template string, args ...interface{}) {
if !logger.errorLogOff && logger.Level <= zapcore.ErrorLevel {
logger.sugaredLogger.Fatalf(template, args...)
}
}
// Fatal print the panic message.
func Panic(info ...interface{}) {
logger.sugaredLogger.Panic(info...)
}
// PanicCtx print the panic message with ctx.
func PanicCtx(ctx *context.Context, format string, args ...interface{}) {
logCtx(ctx, logger.logger.Panic, format, args...)
}
// Panicf print the panic message.
func Panicf(template string, args ...interface{}) {
logger.sugaredLogger.Panicf(template, args...)
}
// Access print the access message.
func Access(ctx *context.Context) {
if !logger.accessLogOff && logger.Level <= zapcore.InfoLevel {
if logger.accessAssetsLogOff {
if filepath.Ext(ctx.Path()) == "" {
logger.logger.Info("[GoAdmin] access log",
zap.String("traceID", trace.GetTraceID(ctx)),
zap.String("statuscode", strconv.Itoa(ctx.Response.StatusCode)),
zap.String("method", string(ctx.Method())),
zap.String("path", ctx.Path()))
}
} else {
logger.logger.Info("[GoAdmin] access log",
zap.String("traceID", trace.GetTraceID(ctx)),
zap.String("statuscode", strconv.Itoa(ctx.Response.StatusCode)),
zap.String("method", string(ctx.Method())),
zap.String("path", ctx.Path()))
}
}
}
// LogSQL print the sql info message.
func LogSQL(statement string, args []interface{}) {
if !logger.infoLogOff && logger.sqlLogOpen && statement != "" {
if logger.Level <= zapcore.InfoLevel {
logger.sugaredLogger.With("statement", statement, "args", args).Info("[GoAdmin]")
}
}
}
func filterZapEncoder(encoding string, encoderConfig zapcore.EncoderConfig) zapcore.Encoder {
var encoder zapcore.Encoder
switch encoding {
default:
encoder = zapcore.NewConsoleEncoder(encoderConfig)
case "json":
encoder = zapcore.NewJSONEncoder(encoderConfig)
case "console":
encoder = zapcore.NewConsoleEncoder(encoderConfig)
}
return encoder
}
func filterZapAtomicLevelByViper(level int8) zapcore.Level {
var atomViper zapcore.Level
switch level {
default:
atomViper = zap.InfoLevel
case -1:
atomViper = zap.DebugLevel
case 0:
atomViper = zap.InfoLevel
case 1:
atomViper = zap.WarnLevel
case 2:
atomViper = zap.ErrorLevel
}
return atomViper
}