123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- package simple_zap
- import (
- "context"
- "fmt"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "log"
- "os"
- "sync"
- "time"
- )
- const loggerCtxKey = "baozhida"
- var (
- Logger *zap.Logger
- mutex sync.RWMutex
- )
- func init() {
- // 确保日志目录存在
- if err := os.MkdirAll("./log", 0755); err != nil {
- log.Fatalf("Failed to create log directory: %v", err)
- }
- // 设置不同级别的日志文件
- levelFiles, err := setupLevelBasedLogFiles()
- if err != nil {
- log.Fatalf("Failed to setup level-based log files: %v", err)
- }
- // 配置zap的各个级别输出
- var cores []zapcore.Core
- encoderConfig := zap.NewProductionEncoderConfig()
- encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
- for level, file := range levelFiles {
- core := zapcore.NewCore(
- zapcore.NewJSONEncoder(encoderConfig),
- zapcore.AddSync(file),
- level, // 指定日志级别
- )
- cores = append(cores, core)
- }
- // 组合所有核心为一个TeeCore,这样所有级别的日志都会被正确路由
- core := zapcore.NewTee(cores...)
- Logger = zap.New(core)
- startDailyLogFileSwitcher()
- }
- func setupLevelBasedLogFiles() (map[zapcore.Level]*os.File, error) {
- levelFiles := make(map[zapcore.Level]*os.File)
- levels := []zapcore.Level{zap.DebugLevel, zap.InfoLevel, zap.WarnLevel, zap.ErrorLevel, zap.DPanicLevel, zap.PanicLevel, zap.FatalLevel}
- for _, level := range levels {
- today := time.Now().Format("2006-01-02")
- logFile := fmt.Sprintf("./log/%s-%s.log", level.String(), today)
- file, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
- if err != nil {
- return nil, fmt.Errorf("failed to open log file for level %s: %w", level.String(), err)
- }
- levelFiles[level] = file
- }
- return levelFiles, nil
- }
- // startDailyLogFileSwitcher 启动一个定时任务,每天定时切换日志文件。
- func startDailyLogFileSwitcher() {
- ticker := time.NewTicker(24 * time.Hour)
- go func() {
- for range ticker.C {
- switchLogFile()
- }
- }()
- }
- // switchLogFile 根据文件大小或日期切换到新的日志文件。
- func switchLogFile() {
- mutex.Lock()
- defer mutex.Unlock()
- // 获取当前日志文件信息
- currentLogFile := fmt.Sprintf("./log/app-%s.log", time.Now().Format("2006-01-02"))
- info, err := os.Stat(currentLogFile)
- if err != nil {
- Logger.Fatal("Error getting current log file info", zap.Error(err))
- }
- // 如果文件大小超过1GB,或者日期已改变
- if info.Size() >= 1<<30 || time.Now().Format("2006-01-02") != info.ModTime().Format("2006-01-02") {
- // 获取第二天的日期
- tomorrow := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
- newLogFile := fmt.Sprintf("./log/app-%s.log", tomorrow)
- // 关闭当前日志文件
- Logger.Sync()
- // 重新打开新的日志文件
- newFile, err := os.OpenFile(newLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
- if err != nil {
- Logger.Fatal("Error opening new log file", zap.Error(err))
- }
- // 更新zap的输出目标
- Logger = zap.New(zapcore.NewCore(
- zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
- zapcore.AddSync(newFile),
- zap.DebugLevel,
- ))
- // 记录日志,表明日志文件已切换
- Logger.Info("Switched to new log file", zap.String("file", newLogFile))
- }
- }
- // NewCtx 给 ctx 注入一个 logger, logger 中包含Field(内含日志打印的 k-v对)
- func NewCtx(ctx context.Context, fields ...zapcore.Field) context.Context {
- return context.WithValue(ctx, loggerCtxKey, Logger.With(fields...))
- }
- // WithCtx 尝试从 context 中获取带有 traceId Field的 logger
- func WithCtx(ctx context.Context) *zap.Logger {
- if ctx == nil {
- return Logger
- }
- ctxLogger, ok := ctx.Value(loggerCtxKey).(*zap.Logger)
- if ok {
- return ctxLogger
- }
- return Logger
- }
|