* Copyright (c) 2024 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package zlog
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
const (
defaultConfigPath = "/etc/installer-service/log-config"
defaultConfigName = "installer-service"
defaultConfigType = "yaml"
defaultLogPath = "/var/log"
)
var logger *zap.SugaredLogger
var logLevel = map[string]zapcore.Level{
"debug": zapcore.DebugLevel,
"info": zapcore.InfoLevel,
"warn": zapcore.WarnLevel,
"error": zapcore.ErrorLevel,
}
var watchOnce = sync.Once{}
type logConfig struct {
Level string
EncoderType string
Path string
FileName string
MaxSize int
MaxBackups int
MaxAge int
LocalTime bool
Compress bool
OutMod string
}
func init() {
var conf *logConfig
var err error
if conf, err = loadConfig(); err != nil {
fmt.Printf("loadConfig fail err is %v. use DefaultConf\n", err)
conf = getDefaultConf()
}
logger = getLogger(conf)
}
func loadConfig() (*logConfig, error) {
viper.AddConfigPath(defaultConfigPath)
viper.SetConfigName(defaultConfigName)
viper.SetConfigType(defaultConfigType)
config, err := parseConfig()
if err != nil {
return nil, err
}
watchConfig()
return config, nil
}
func getDefaultConf() *logConfig {
var defaultConf = &logConfig{
Level: "info",
EncoderType: "console",
Path: defaultLogPath,
FileName: "root.log",
MaxSize: 20,
MaxBackups: 5,
MaxAge: 30,
LocalTime: false,
Compress: true,
OutMod: "both",
}
exePath, err := os.Executable()
if err != nil {
return defaultConf
}
serviceName := strings.TrimSuffix(filepath.Base(exePath), filepath.Ext(filepath.Base(exePath)))
defaultConf.Path = filepath.Join(defaultLogPath, serviceName)
return defaultConf
}
func getLogger(conf *logConfig) *zap.SugaredLogger {
writeSyncer := getLogWriter(conf)
encoder := getEncoder(conf)
level, ok := logLevel[strings.ToLower(conf.Level)]
if !ok {
level = logLevel["info"]
}
core := zapcore.NewCore(encoder, writeSyncer, level)
logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
return logger.Sugar()
}
func watchConfig() {
watchOnce.Do(func() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
logger.Warn("Config file changed")
conf, err := parseConfig()
if err != nil {
logger.Warnf("Error reloading config file: %v\n", err)
} else {
logger = getLogger(conf)
}
})
})
}
func parseConfig() (*logConfig, error) {
err := viper.ReadInConfig()
if err != nil {
return nil, err
}
var config logConfig
err = viper.Unmarshal(&config)
if err != nil {
return nil, err
}
return &config, nil
}
func getEncoder(conf *logConfig) zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
if strings.ToLower(conf.EncoderType) == "json" {
return zapcore.NewJSONEncoder(encoderConfig)
}
return zapcore.NewConsoleEncoder(encoderConfig)
}
func getLogWriter(conf *logConfig) zapcore.WriteSyncer {
if conf.OutMod == "console" {
return zapcore.AddSync(os.Stdout)
}
lumberJackLogger := &lumberjack.Logger{
Filename: filepath.Join(conf.Path, conf.FileName),
MaxSize: conf.MaxSize,
MaxBackups: conf.MaxBackups,
MaxAge: conf.MaxAge,
LocalTime: conf.LocalTime,
Compress: conf.Compress,
}
if conf.OutMod == "both" {
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(lumberJackLogger), zapcore.AddSync(os.Stdout))
}
if conf.OutMod == "file" {
return zapcore.AddSync(lumberJackLogger)
}
return zapcore.AddSync(os.Stdout)
}
func With(args ...interface{}) *zap.SugaredLogger {
return logger.With(args...)
}
func Error(args ...interface{}) {
logger.Error(args...)
}
func Warn(args ...interface{}) {
logger.Warn(args...)
}
func Info(args ...interface{}) {
logger.Info(args...)
}
func Debug(args ...interface{}) {
logger.Debug(args...)
}
func Fatal(args ...interface{}) {
logger.Fatal(args...)
}
func Panic(args ...interface{}) {
logger.Panic(args...)
}
func DPanic(args ...interface{}) {
logger.DPanic(args...)
}
func Errorf(template string, args ...interface{}) {
logger.Errorf(template, args...)
}
func Warnf(template string, args ...interface{}) {
logger.Warnf(template, args...)
}
func Infof(template string, args ...interface{}) {
logger.Infof(template, args...)
}
func Debugf(template string, args ...interface{}) {
logger.Debugf(template, args...)
}
func Fatalf(template string, args ...interface{}) {
logger.Fatalf(template, args...)
}
func Panicf(template string, args ...interface{}) {
logger.Panicf(template, args...)
}
func DPanicf(template string, args ...interface{}) {
logger.DPanicf(template, args...)
}
func Errorw(msg string, keysAndValues ...interface{}) {
logger.Errorw(msg, keysAndValues...)
}
func Warnw(msg string, keysAndValues ...interface{}) {
logger.Warnw(msg, keysAndValues...)
}
func Infow(msg string, keysAndValues ...interface{}) {
logger.Infow(msg, keysAndValues...)
}
func Debugw(msg string, keysAndValues ...interface{}) {
logger.Debugw(msg, keysAndValues...)
}
func Fatalw(msg string, keysAndValues ...interface{}) {
logger.Fatalw(msg, keysAndValues...)
}
func Panicw(msg string, keysAndValues ...interface{}) {
logger.Panicw(msg, keysAndValues...)
}
func DPanicw(msg string, keysAndValues ...interface{}) {
logger.DPanicw(msg, keysAndValues...)
}
func Errorln(args ...interface{}) {
logger.Errorln(args...)
}
func Warnln(args ...interface{}) {
logger.Warnln(args...)
}
func Infoln(args ...interface{}) {
logger.Infoln(args...)
}
func Debugln(args ...interface{}) {
logger.Debugln(args...)
}
func Fatalln(args ...interface{}) {
logger.Fatalln(args...)
}
func Panicln(args ...interface{}) {
logger.Panicln(args...)
}
func DPanicln(args ...interface{}) {
logger.DPanicln(args...)
}
func Sync() error {
return logger.Sync()
}