package log import ( "errors" "fmt" "io/fs" "io/ioutil" "log" "os" "path" "time" "github.com/BurntSushi/toml" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/yaml.v2" ) var ( logger Logger ) type YLogger struct { Logger dynamicLevel zap.AtomicLevel } type Logger interface { Info(args ...interface{}) Warn(args ...interface{}) Error(args ...interface{}) Debug(args ...interface{}) Infof(fmt string, args ...interface{}) Warnf(fmt string, args ...interface{}) Errorf(fmt string, args ...interface{}) Debugf(fmt string, args ...interface{}) } func init() { var ( cfg LogCfg logCfg GlobalCfg ) log.Println("config file name -->", ConfigFile) log.Println("starting ...") if _, err := toml.DecodeFile(ConfigFile, &logCfg); err != nil { //log.Fatalf("Read config file err:%s", err.Error()) log.Println("failed to open config file") if err = InitLog("", cfg); nil != err { log.Println(err.Error()) } return } cfg = logCfg.Logs cfg.OutputPaths = cfg.LogPath + cfg.APPName + time.Now().Format("2006-01-02") + ".log" cfg.ErrorOutputPaths = cfg.LogPath + cfg.APPName + ".error" err := InitLog(cfg.LogConf, cfg) if err != nil { log.Printf("[InitLog] warn: %v", err) } } func ReloadLogger(configFile string) { var ( cfg LogCfg logCfg GlobalCfg ) log.Println("config file name -->", configFile) if _, err := toml.DecodeFile(configFile, &logCfg); err != nil { log.Fatalf("Read config file err:%s", err.Error()) } cfg = logCfg.Logs cfg.OutputPaths = cfg.LogPath + cfg.APPName + time.Now().Format("2006-01-02") + ".log" cfg.ErrorOutputPaths = cfg.LogPath + cfg.APPName + ".error" err := InitLog(cfg.LogConf, cfg) if err != nil { log.Printf("[ReloadLogger] warn: %v", err) } } func RotateLogger(cfg LogCfg) { cfg.OutputPaths = cfg.LogInfoPath + cfg.APPName + ".log" cfg.ErrorOutputPaths = cfg.LogErrPath + cfg.APPName + ".error" if _, err := os.Stat(cfg.OutputPaths); errors.Is(err, fs.ErrNotExist) { if _, err = os.Create(cfg.OutputPaths); nil != err { log.Printf("[RotateLogger] error: %s", err.Error()) return } } //if _, err := os.Stat(cfg.ErrorOutputPaths); errors.Is(err, fs.ErrNotExist) { // if _, err = os.Create(cfg.ErrorOutputPaths); nil != err { // log.Printf("[RotateLogger] error: %s", err.Error()) // return // } //} err := InitLog(cfg.LogConf, cfg) if err != nil { log.Printf("[RotateLogger] warn: %v", err) } } var defaultZapConfig = []byte(` level: "info" development: false disableCaller: false disableStacktrace: false sampling: encoding: "console" # encoder encoderConfig: messageKey: "message" levelKey: "level" timeKey: "time" nameKey: "logger" callerKey: "caller" stacktraceKey: "stacktrace" lineEnding: "" # levelEncoder: "capitalColor" timeEncoder: "iso8601" durationEncoder: "seconds" callerEncoder: "short" nameEncoder: "" `) func InitLog(logConfFile string, cfg LogCfg) error { conf := &zap.Config{} if logConfFile != "" { if path.Ext(logConfFile) != ".yml" { InitLogger(nil) return fmt.Errorf("log configure file name{%s} suffix must be .yml", logConfFile) } confFileStream, err := ioutil.ReadFile(logConfFile) if err != nil { InitLogger(nil) return fmt.Errorf("ioutil.ReadFile(file:%s) = error:%v", logConfFile, err) } err = yaml.Unmarshal(confFileStream, conf) if err != nil { InitLogger(nil) return fmt.Errorf("[Unmarshal]init logger error: %v", err) } } else { conf = &zap.Config{ Level: zap.NewAtomicLevel(), Development: false, DisableCaller: false, DisableStacktrace: false, Sampling: nil, Encoding: "console", EncoderConfig: zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", TimeKey: "time", NameKey: "logger", CallerKey: "caller", StacktraceKey: "stacktrace", EncodeTime: zapcore.EpochMillisTimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, EncodeName: nil, EncodeLevel: nil, }, } err := yaml.Unmarshal(defaultZapConfig, conf) if err != nil { InitLogger(nil) return fmt.Errorf("[Unmarshal]init logger error: %v", err) } } conf.OutputPaths = append(conf.OutputPaths, cfg.OutputPaths) conf.ErrorOutputPaths = append(conf.ErrorOutputPaths, cfg.ErrorOutputPaths) InitLogger(conf) return nil } func InitLogger(conf *zap.Config) { var zapLoggerConfig zap.Config if conf == nil { zapLoggerConfig = zap.NewDevelopmentConfig() zapLoggerEncoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "message", StacktraceKey: "stacktrace", EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } zapLoggerConfig.EncoderConfig = zapLoggerEncoderConfig } else { zapLoggerConfig = *conf } zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(1)) //logger = zapLogger.Sugar() logger = &YLogger{Logger: zapLogger.Sugar(), dynamicLevel: zapLoggerConfig.Level} } func SetLogger(log Logger) { logger = log } func GetLogger() Logger { return logger } func SetLoggerLevel(level string) bool { if l, ok := logger.(OpsLogger); ok { l.SetLoggerLevel(level) return true } return false } type OpsLogger interface { Logger SetLoggerLevel(level string) } func (dl *YLogger) SetLoggerLevel(level string) { l := new(zapcore.Level) l.Set(level) dl.dynamicLevel.SetLevel(*l) }