github.com/jtzjtz/kit@v1.0.2/log/zap_log.go (about)

     1  package log
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/jtzjtz/kit/file"
     7  	"github.com/lestrrat/go-file-rotatelogs"
     8  	"go.uber.org/zap"
     9  	"go.uber.org/zap/zapcore"
    10  	"io"
    11  	"time"
    12  )
    13  
    14  //全局日志实例(程序启动前调用InitLog(appName string, logDir string))
    15  var Logger *zap.SugaredLogger
    16  
    17  func initLog(appName string, logDir string) (er error) {
    18  	defer func() {
    19  		if err := recover(); err != nil {
    20  			er = err.(error)
    21  		}
    22  	}()
    23  	if len(logDir) == 0 {
    24  		logDir = "./"
    25  	}
    26  	if exists, _ := file.ExistsDir(logDir); !exists {
    27  		if er = file.CreateDir(logDir); er != nil {
    28  			return er
    29  		}
    30  	}
    31  	if exists, _ := file.ExistsDir(logDir + "/backup"); !exists {
    32  		if er = file.CreateDir(logDir + "/backup"); er != nil {
    33  			return er
    34  		}
    35  	}
    36  	// 设置一些基本日志格式 具体含义还比较好理解,直接看zap源码也不难懂
    37  	encoder := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
    38  		MessageKey:  "msg",
    39  		LevelKey:    "level",
    40  		EncodeLevel: zapcore.CapitalLevelEncoder,
    41  		TimeKey:     "time",
    42  		EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
    43  			enc.AppendString(t.Format("2006-01-02 15:04:05"))
    44  		},
    45  		CallerKey:    "file",
    46  		EncodeCaller: zapcore.ShortCallerEncoder,
    47  		EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
    48  			enc.AppendInt64(int64(d) / 1000000)
    49  		},
    50  	})
    51  
    52  	// 实现两个判断日志等级的interface
    53  	infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
    54  		return lvl == zapcore.InfoLevel
    55  	})
    56  
    57  	errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
    58  		return lvl == zapcore.ErrorLevel
    59  	})
    60  	debugLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
    61  		return lvl == zapcore.DebugLevel
    62  	})
    63  
    64  	// 获取 info、error日志文件的io.Writer 抽象 getWriter() 在下方实现
    65  	accessWriter := getWriter(appName, "access", logDir)
    66  	infoWriter := getWriter(appName, "info", logDir)
    67  	errorWriter := getWriter(appName, "error", logDir)
    68  
    69  	// 最后创建具体的Logger
    70  	core := zapcore.NewTee(
    71  		zapcore.NewCore(encoder, zapcore.AddSync(accessWriter), debugLevel),
    72  		zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel),
    73  		zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel),
    74  	)
    75  
    76  	log := zap.New(core) // 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数, 有点小坑
    77  	Logger = log.Sugar()
    78  	if Logger == nil {
    79  		return errors.New("初始化日志实例失败")
    80  	}
    81  	return nil
    82  }
    83  
    84  func getWriter(appName, logType, logDir string) io.Writer {
    85  	// 生成rotatelogs的Logger 实际生成的文件名 demo.log.YYmmddHH
    86  	// demo.log是指向最新日志的链接
    87  	// 保存7天内的日志,每天分割一次日志
    88  	hook, err := rotatelogs.New(
    89  		logDir+"/backup/"+appName+"-"+logType+"%Y%m%d.log",
    90  		rotatelogs.WithLinkName(fmt.Sprintf("%s/%s-%s.log", logDir, appName, logType)),
    91  		rotatelogs.WithMaxAge(time.Hour*24*365*2),
    92  		rotatelogs.WithRotationTime(time.Hour*24),
    93  	)
    94  
    95  	if err != nil {
    96  		panic(err)
    97  	}
    98  	//ch :=make( chan os.Signal)
    99  	//signal.Notify(ch, syscall.SIGHUP)
   100  	//
   101  	//go func(ch chan os.Signal) {
   102  	//	<-ch
   103  	//	hook.Rotate()
   104  	//}(ch)
   105  	return hook
   106  }