You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
8.5 KiB
276 lines
8.5 KiB
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 `yaml:"path" json:"path" toml:"path"` // 文件保存地方 |
|
Prefix string `yaml:"prefix" json:"prefix" toml:"prefix"` // 日志文件前缀 |
|
ErrorFileSuffix string `yaml:"errorFileSuffix" json:"errorFileSuffix" toml:"errorFileSuffix"` // error日志文件后缀 |
|
WarnFileSuffix string `yaml:"warnFileSuffix" json:"warnFileSuffix" toml:"warnFileSuffix"` // warn日志文件后缀 |
|
InfoFileSuffix string `yaml:"infoFileSuffix" json:"infoFileSuffix" toml:"infoFileSuffix"` // info日志文件后缀 |
|
DebugFileSuffix string `yaml:"debugFileSuffix" json:"debugFileSuffix" toml:"debugFileSuffix"` // debug日志文件后缀 |
|
Level zapcore.Level `yaml:"level" json:"level" toml:"level"` // 日志等级 |
|
MaxSize int `yaml:"maxSize" json:"maxSize" toml:"maxSize"` // 日志文件大小(M) |
|
MaxBackups int `yaml:"maxBackups" json:"maxBackups" toml:"maxBackups"` // 最多存在多少个切片文件 |
|
MaxAge int `yaml:"maxAge" json:"maxAge" toml:"maxAge"` // 保存的最大天数 |
|
Development bool `yaml:"development" json:"development" toml:"development"` // 是否是开发模式 |
|
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: "\n", |
|
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() + "]") |
|
}
|
|
|