159 lines
3.1 KiB
Go
159 lines
3.1 KiB
Go
package logging
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/pelletier/go-toml"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
)
|
|
|
|
type Config struct {
|
|
Logger LoggerConfig
|
|
}
|
|
|
|
type LoggerConfig struct {
|
|
Debug bool
|
|
Level string // debug/info/warn/error/dpanic/panic/fatal
|
|
CallerSkip int
|
|
File struct {
|
|
Enable bool
|
|
Path string
|
|
MaxSize int
|
|
MaxBackups int
|
|
}
|
|
Hooks []*HookConfig
|
|
}
|
|
|
|
type HookConfig struct {
|
|
Enable bool
|
|
Level string
|
|
Type string // gorm
|
|
MaxBuffer int
|
|
MaxThread int
|
|
Options map[string]string
|
|
Extra map[string]string
|
|
}
|
|
|
|
type HookHandlerFunc func(ctx context.Context, hookCfg *HookConfig) (*Hook, error)
|
|
|
|
func LoadConfigFromToml(filename string) (*LoggerConfig, error) {
|
|
cfg := &Config{}
|
|
buf, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := toml.Unmarshal(buf, cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfg.Logger, nil
|
|
}
|
|
|
|
func InitWithConfig(ctx context.Context, cfg *LoggerConfig, hookHandle ...HookHandlerFunc) (func(), error) {
|
|
var zconfig zap.Config
|
|
if cfg.Debug {
|
|
cfg.Level = "debug"
|
|
zconfig = zap.NewDevelopmentConfig()
|
|
} else {
|
|
zconfig = zap.NewProductionConfig()
|
|
}
|
|
|
|
level, err := zapcore.ParseLevel(cfg.Level)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
zconfig.Level.SetLevel(level)
|
|
|
|
var (
|
|
logger *zap.Logger
|
|
cleanFns []func()
|
|
)
|
|
|
|
if cfg.File.Enable {
|
|
filename := cfg.File.Path
|
|
_ = os.MkdirAll(filepath.Dir(filename), 0777)
|
|
fileWriter := &lumberjack.Logger{
|
|
Filename: filename,
|
|
MaxSize: cfg.File.MaxSize,
|
|
MaxBackups: cfg.File.MaxBackups,
|
|
Compress: false,
|
|
LocalTime: true,
|
|
}
|
|
|
|
cleanFns = append(cleanFns, func() {
|
|
_ = fileWriter.Close()
|
|
})
|
|
|
|
zc := zapcore.NewCore(
|
|
zapcore.NewJSONEncoder(zconfig.EncoderConfig),
|
|
zapcore.AddSync(fileWriter),
|
|
zconfig.Level,
|
|
)
|
|
logger = zap.New(zc)
|
|
} else {
|
|
ilogger, err := zconfig.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
logger = ilogger
|
|
}
|
|
|
|
skip := cfg.CallerSkip
|
|
if skip <= 0 {
|
|
skip = 2
|
|
}
|
|
|
|
logger = logger.WithOptions(
|
|
zap.WithCaller(true),
|
|
zap.AddStacktrace(zap.ErrorLevel),
|
|
zap.AddCallerSkip(skip),
|
|
)
|
|
|
|
for _, h := range cfg.Hooks {
|
|
if !h.Enable || len(hookHandle) == 0 {
|
|
continue
|
|
}
|
|
|
|
writer, err := hookHandle[0](ctx, h)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if writer == nil {
|
|
continue
|
|
}
|
|
|
|
cleanFns = append(cleanFns, func() {
|
|
writer.Flush()
|
|
})
|
|
|
|
hookLevel := zap.NewAtomicLevel()
|
|
if level, err := zapcore.ParseLevel(h.Level); err == nil {
|
|
hookLevel.SetLevel(level)
|
|
} else {
|
|
hookLevel.SetLevel(zap.InfoLevel)
|
|
}
|
|
|
|
hookEncoder := zap.NewProductionEncoderConfig()
|
|
hookEncoder.EncodeTime = zapcore.EpochMillisTimeEncoder
|
|
hookEncoder.EncodeDuration = zapcore.MillisDurationEncoder
|
|
hookCore := zapcore.NewCore(
|
|
zapcore.NewJSONEncoder(hookEncoder),
|
|
zapcore.AddSync(writer),
|
|
hookLevel,
|
|
)
|
|
|
|
logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
|
return zapcore.NewTee(core, hookCore)
|
|
}))
|
|
}
|
|
|
|
zap.ReplaceGlobals(logger)
|
|
return func() {
|
|
for _, fn := range cleanFns {
|
|
fn()
|
|
}
|
|
}, nil
|
|
}
|