simple_zap.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package simple_zap
  2. import (
  3. "context"
  4. "fmt"
  5. "go.uber.org/zap"
  6. "go.uber.org/zap/zapcore"
  7. "log"
  8. "os"
  9. "sync"
  10. "time"
  11. )
  12. const loggerCtxKey = "baozhida"
  13. var (
  14. Logger *zap.Logger
  15. mutex sync.RWMutex
  16. )
  17. func init() {
  18. // 确保日志目录存在
  19. if err := os.MkdirAll("./log", 0755); err != nil {
  20. log.Fatalf("Failed to create log directory: %v", err)
  21. }
  22. // 设置不同级别的日志文件
  23. levelFiles, err := setupLevelBasedLogFiles()
  24. if err != nil {
  25. log.Fatalf("Failed to setup level-based log files: %v", err)
  26. }
  27. // 配置zap的各个级别输出
  28. var cores []zapcore.Core
  29. encoderConfig := zap.NewProductionEncoderConfig()
  30. encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
  31. for level, file := range levelFiles {
  32. core := zapcore.NewCore(
  33. zapcore.NewJSONEncoder(encoderConfig),
  34. zapcore.AddSync(file),
  35. level, // 指定日志级别
  36. )
  37. cores = append(cores, core)
  38. }
  39. // 组合所有核心为一个TeeCore,这样所有级别的日志都会被正确路由
  40. core := zapcore.NewTee(cores...)
  41. Logger = zap.New(core)
  42. startDailyLogFileSwitcher()
  43. }
  44. func setupLevelBasedLogFiles() (map[zapcore.Level]*os.File, error) {
  45. levelFiles := make(map[zapcore.Level]*os.File)
  46. levels := []zapcore.Level{zap.DebugLevel, zap.InfoLevel, zap.WarnLevel, zap.ErrorLevel, zap.DPanicLevel, zap.PanicLevel, zap.FatalLevel}
  47. for _, level := range levels {
  48. today := time.Now().Format("2006-01-02")
  49. logFile := fmt.Sprintf("./log/%s-%s.log", level.String(), today)
  50. file, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
  51. if err != nil {
  52. return nil, fmt.Errorf("failed to open log file for level %s: %w", level.String(), err)
  53. }
  54. levelFiles[level] = file
  55. }
  56. return levelFiles, nil
  57. }
  58. // startDailyLogFileSwitcher 启动一个定时任务,每天定时切换日志文件。
  59. func startDailyLogFileSwitcher() {
  60. ticker := time.NewTicker(24 * time.Hour)
  61. go func() {
  62. for range ticker.C {
  63. switchLogFile()
  64. }
  65. }()
  66. }
  67. // switchLogFile 根据文件大小或日期切换到新的日志文件。
  68. func switchLogFile() {
  69. mutex.Lock()
  70. defer mutex.Unlock()
  71. // 获取当前日志文件信息
  72. currentLogFile := fmt.Sprintf("./log/app-%s.log", time.Now().Format("2006-01-02"))
  73. info, err := os.Stat(currentLogFile)
  74. if err != nil {
  75. Logger.Fatal("Error getting current log file info", zap.Error(err))
  76. }
  77. // 如果文件大小超过1GB,或者日期已改变
  78. if info.Size() >= 1<<30 || time.Now().Format("2006-01-02") != info.ModTime().Format("2006-01-02") {
  79. // 获取第二天的日期
  80. tomorrow := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
  81. newLogFile := fmt.Sprintf("./log/app-%s.log", tomorrow)
  82. // 关闭当前日志文件
  83. Logger.Sync()
  84. // 重新打开新的日志文件
  85. newFile, err := os.OpenFile(newLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
  86. if err != nil {
  87. Logger.Fatal("Error opening new log file", zap.Error(err))
  88. }
  89. // 更新zap的输出目标
  90. Logger = zap.New(zapcore.NewCore(
  91. zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
  92. zapcore.AddSync(newFile),
  93. zap.DebugLevel,
  94. ))
  95. // 记录日志,表明日志文件已切换
  96. Logger.Info("Switched to new log file", zap.String("file", newLogFile))
  97. }
  98. }
  99. // NewCtx 给 ctx 注入一个 logger, logger 中包含Field(内含日志打印的 k-v对)
  100. func NewCtx(ctx context.Context, fields ...zapcore.Field) context.Context {
  101. return context.WithValue(ctx, loggerCtxKey, Logger.With(fields...))
  102. }
  103. // WithCtx 尝试从 context 中获取带有 traceId Field的 logger
  104. func WithCtx(ctx context.Context) *zap.Logger {
  105. if ctx == nil {
  106. return Logger
  107. }
  108. ctxLogger, ok := ctx.Value(loggerCtxKey).(*zap.Logger)
  109. if ok {
  110. return ctxLogger
  111. }
  112. return Logger
  113. }