logging/logger.go

277 lines
7.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package logging
import (
"os"
"path/filepath"
"sync"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
type ModOptions func(options *Options)
// Options 日志文件配置选项
type Options struct {
Path string // 文件保存地方
Prefix string // 日志文件前缀
ErrorFileSuffix string // error日志文件后缀
WarnFileSuffix string // warn日志文件后缀
InfoFileSuffix string // info日志文件后缀
DebugFileSuffix string // debug日志文件后缀
Level zapcore.Level // 日志等级
MaxSize int // 日志文件大小M
MaxBackups int // 最多存在多少个切片文件
MaxAge int // 保存的最大天数
Development bool // 是否是开发模式
zap.Config
}
var (
logger *Logger
sp = string(filepath.Separator)
errWS, warnWS, infoWS, debugWS zapcore.WriteSyncer // IO输出
debugConsoleWS = zapcore.Lock(os.Stdout) // 控制台标准输出
errorConsoleWS = zapcore.Lock(os.Stderr)
LogLevel = make(map[string]zapcore.Level)
)
type Logger struct {
*zap.Logger
sync.RWMutex
Opts *Options `json:"opts"`
zapConfig zap.Config
initialized bool
}
func NewLogger(mod ...ModOptions) *Logger {
logger = &Logger{}
logger.Lock()
defer logger.Unlock()
if logger.initialized {
logger.Info("[NewLogger] logger initEd")
return nil
}
logger.Opts = &Options{
Path: "",
Prefix: "app",
ErrorFileSuffix: "error.log",
WarnFileSuffix: "warn.log",
InfoFileSuffix: "info.log",
DebugFileSuffix: "debug.log",
Level: zapcore.DebugLevel,
MaxSize: 100,
MaxBackups: 60,
MaxAge: 30,
}
if logger.Opts.Path == "" {
logger.Opts.Path, _ = filepath.Abs(filepath.Dir(filepath.Join(".")))
logger.Opts.Path += sp + "logs" + sp
}
if logger.Opts.Development {
logger.zapConfig = zap.NewDevelopmentConfig()
logger.zapConfig.EncoderConfig.EncodeTime = timeEncoder
} else {
logger.zapConfig = zap.NewProductionConfig()
logger.zapConfig.EncoderConfig.EncodeTime = timeEncoder
}
if logger.Opts.OutputPaths == nil || len(logger.Opts.OutputPaths) == 0 {
logger.zapConfig.OutputPaths = []string{"stdout"}
}
if logger.Opts.ErrorOutputPaths == nil || len(logger.Opts.ErrorOutputPaths) == 0 {
logger.zapConfig.OutputPaths = []string{"stderr"}
}
for _, fn := range mod {
fn(logger.Opts)
}
logger.zapConfig.Level.SetLevel(logger.Opts.Level)
logger.init()
logger.initialized = true
return logger
}
func (logger *Logger) init() {
logger.setSyncs()
var err error
logger.Logger, err = logger.zapConfig.Build(logger.cores())
if err != nil {
panic(err)
}
LogLevel["debug"] = zap.DebugLevel
LogLevel["info"] = zap.InfoLevel
LogLevel["warn"] = zap.WarnLevel
LogLevel["error"] = zap.ErrorLevel
LogLevel["dpanic"] = zap.DPanicLevel
LogLevel["panic"] = zap.PanicLevel
LogLevel["fatal"] = zap.FatalLevel
defer logger.Logger.Sync()
}
func (logger *Logger) setSyncs() {
f := func(fN string) zapcore.WriteSyncer {
return zapcore.AddSync(&lumberjack.Logger{
Filename: logger.Opts.Path + sp + logger.Opts.Prefix + "-" + fN,
MaxSize: logger.Opts.MaxSize,
MaxBackups: logger.Opts.MaxBackups,
MaxAge: logger.Opts.MaxAge,
Compress: true,
LocalTime: true,
})
}
errWS = f(logger.Opts.ErrorFileSuffix)
warnWS = f(logger.Opts.WarnFileSuffix)
infoWS = f(logger.Opts.InfoFileSuffix)
debugWS = f(logger.Opts.DebugFileSuffix)
}
func SetMaxSize(MaxSize int) ModOptions {
return func(option *Options) {
option.MaxSize = MaxSize
}
}
func SetMaxBackups(MaxBackups int) ModOptions {
return func(option *Options) {
option.MaxBackups = MaxBackups
}
}
func SetMaxAge(MaxAge int) ModOptions {
return func(option *Options) {
option.MaxAge = MaxAge
}
}
func SetPath(Path string) ModOptions {
return func(option *Options) {
option.Path = Path
}
}
func SetPrefix(Prefix string) ModOptions {
return func(option *Options) {
option.Prefix = Prefix
}
}
func SetLevel(Level zapcore.Level) ModOptions {
return func(option *Options) {
option.Level = Level
}
}
func SetErrorFileSuffix(ErrorFileSuffix string) ModOptions {
return func(option *Options) {
option.ErrorFileSuffix = ErrorFileSuffix
}
}
func SetWarnFileSuffix(WarnFileSuffix string) ModOptions {
return func(option *Options) {
option.WarnFileSuffix = WarnFileSuffix
}
}
func SetInfoFileSuffix(InfoFileSuffix string) ModOptions {
return func(option *Options) {
option.InfoFileSuffix = InfoFileSuffix
}
}
func SetDebugFileSuffix(DebugFileSuffix string) ModOptions {
return func(option *Options) {
option.DebugFileSuffix = DebugFileSuffix
}
}
func SetDevelopment(Development bool) ModOptions {
return func(option *Options) {
option.Development = Development
}
}
// getDefaultLogger returns the default logger.
func getDefaultLogger() *Logger {
return logger
}
// L returns the default logger.
func L() *Logger {
return getDefaultLogger()
}
func (logger *Logger) cores() zap.Option {
fileEncoder := zapcore.NewJSONEncoder(logger.zapConfig.EncoderConfig)
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.EncodeTime = timeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
consoleEncoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller_line",
FunctionKey: zapcore.OmitKey,
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: " ",
EncodeLevel: encodeLevel,
EncodeTime: encodeTime,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: encodeCaller,
})
errPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.ErrorLevel && zapcore.ErrorLevel-logger.zapConfig.Level.Level() > -1
})
warnPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.WarnLevel && zapcore.WarnLevel-logger.zapConfig.Level.Level() > -1
})
infoPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.InfoLevel && zapcore.InfoLevel-logger.zapConfig.Level.Level() > -1
})
debugPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl == zapcore.DebugLevel && zapcore.DebugLevel-logger.zapConfig.Level.Level() > -1
})
cores := []zapcore.Core{
zapcore.NewCore(fileEncoder, errWS, errPriority),
zapcore.NewCore(fileEncoder, warnWS, warnPriority),
zapcore.NewCore(fileEncoder, infoWS, infoPriority),
zapcore.NewCore(fileEncoder, debugWS, debugPriority),
}
if logger.Opts.Development {
cores = append(cores, []zapcore.Core{
zapcore.NewCore(consoleEncoder, errorConsoleWS, errPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, warnPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, infoPriority),
zapcore.NewCore(consoleEncoder, debugConsoleWS, debugPriority),
}...)
}
return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
return zapcore.NewTee(cores...)
})
}
func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}
// encodeLevel 自定义日志级别显示
func encodeLevel(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString("[" + level.CapitalString() + "]")
}
// encodeTime 自定义时间格式显示
func encodeTime(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString("[" + t.Format("2006-01-02 15:04:05.000") + "]")
}
// encodeCaller 自定义行号显示
func encodeCaller(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString("[" + caller.TrimmedPath() + "]")
}