浏览代码

refactor(log): 重构日志模块并优化日志记录功能- 新增按服务类型分割日志的功能,支持API和Task日志分开记录
- 增加按日期滚动日志文件的功能,提高日志管理的灵活性- 优化日志格式和编码,提高日志的可读性和性能
- 添加日志目录自动创建功能,确保日志记录的可靠性
- 更新日志配置参数,提供更多定制选项

fusu 3 月之前
父节点
当前提交
f5e84789a7

+ 1 - 1
api/v1/GameShield.go

@@ -25,7 +25,7 @@ type GameShieldSubmitResponse struct {
 type GetGameShieldRuleIdRequest struct {
 type GetGameShieldRuleIdRequest struct {
 	AppName string `json:"app_name" form:"app_name"`
 	AppName string `json:"app_name" form:"app_name"`
 	Name    string `json:"name" form:"name"`
 	Name    string `json:"name" form:"name"`
-	Id      int    `json:"id" form:"id"`
+	HostId  int    `json:"host_id" form:"host_id"`
 }
 }
 
 
 type GetGameShieldRequiredResponse struct {
 type GetGameShieldRequiredResponse struct {

+ 3 - 1
cmd/server/main.go

@@ -31,7 +31,9 @@ func main() {
 	flag.Parse()
 	flag.Parse()
 	conf := config.NewConfig(*envConf)
 	conf := config.NewConfig(*envConf)
 
 
-	logger := log.NewLog(conf)
+	// 检查是否有环境变量指定服务类型
+	serviceType := log.API
+	logger := log.NewServiceLog(conf, serviceType)
 
 
 	app, cleanup, err := wire.NewWire(conf, logger)
 	app, cleanup, err := wire.NewWire(conf, logger)
 	defer cleanup()
 	defer cleanup()

+ 3 - 1
cmd/task/main.go

@@ -13,7 +13,9 @@ func main() {
 	flag.Parse()
 	flag.Parse()
 	conf := config.NewConfig(*envConf)
 	conf := config.NewConfig(*envConf)
 
 
-	logger := log.NewLog(conf)
+	// 使用Task服务类型初始化日志
+	serviceType := log.Task
+	logger := log.NewServiceLog(conf, serviceType)
 	logger.Info("start task")
 	logger.Info("start task")
 	app, cleanup, err := wire.NewWire(conf, logger)
 	app, cleanup, err := wire.NewWire(conf, logger)
 	defer cleanup()
 	defer cleanup()

+ 11 - 3
config/local.yml

@@ -30,11 +30,19 @@ data:
 log:
 log:
   log_level: debug
   log_level: debug
   encoding: console           # json or console
   encoding: console           # json or console
+  log_format: "2006-01-02"   # 按天生成日志文件
+  # 区分API和Task日志
+  api_log_file: "./storage/logs/api-%s.log" # %s会被替换为日期
+  task_log_file: "./storage/logs/task-%s.log" # %s会被替换为日期
+  # 兼容旧版本配置
   log_file_name: "./storage/logs/server.log"
   log_file_name: "./storage/logs/server.log"
   max_backups: 30
   max_backups: 30
-  max_age: 7
-  max_size: 1024
-  compress: true
+  max_age: 30            # 保存30天日志
+  max_size: 200          # 单个文件最大200M
+  compress: true         # 自动压缩
+  # 日志过滤和美化
+  hide_sql_args: true    # 隐藏SQL参数详情
+  hide_request_body: false # 是否隐藏请求体内容
 
 
 crawler:
 crawler:
   username: "admin"
   username: "admin"

+ 11 - 3
config/prod.yml

@@ -30,8 +30,16 @@ data:
 log:
 log:
   log_level: info
   log_level: info
   encoding: json           # json or console
   encoding: json           # json or console
+  log_format: "2006-01-02"   # 按天生成日志文件
+  # 区分API和Task日志
+  api_log_file: "./storage/logs/api-%s.log" # %s会被替换为日期
+  task_log_file: "./storage/logs/task-%s.log" # %s会被替换为日期
+  # 兼容旧版本配置
   log_file_name: "./storage/logs/server.log"
   log_file_name: "./storage/logs/server.log"
   max_backups: 30
   max_backups: 30
-  max_age: 7
-  max_size: 1024
-  compress: true
+  max_age: 30            # 保存30天日志
+  max_size: 200          # 单个文件最大200M
+  compress: true         # 自动压缩
+  # 日志过滤和美化
+  hide_sql_args: true    # 隐藏SQL参数详情
+  hide_request_body: false # 是否隐藏请求体内容

+ 1 - 1
internal/handler/gameshield.go

@@ -79,7 +79,7 @@ func (h *GameShieldHandler) GetGameShieldKey(ctx *gin.Context) {
 		return
 		return
 	}
 	}
 
 
-	res, err := h.gameShieldService.GetGameShieldKey(ctx, req.Id)
+	res, err := h.gameShieldService.GetGameShieldKey(ctx, req.HostId)
 	if err != nil {
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 		return

+ 3 - 3
internal/repository/gameshield.go

@@ -15,7 +15,7 @@ type GameShieldRepository interface {
 	GetGameShieldIsBuy(ctx context.Context, uid int64) (int64, error)
 	GetGameShieldIsBuy(ctx context.Context, uid int64) (int64, error)
 	GetGameShieldNextduedate(ctx context.Context, uid int64, productID string) (string, error)
 	GetGameShieldNextduedate(ctx context.Context, uid int64, productID string) (string, error)
 	GetGameShieldNameByDunName(ctx context.Context, appName string) (string, error)
 	GetGameShieldNameByDunName(ctx context.Context, appName string) (string, error)
-	GetGameShieldIdByDunName(ctx context.Context, id int64) (string, error)
+	GetGameShieldHostIdByDunName(ctx context.Context, hostId string) (string, error)
 	GetGameShieldRuleIdByAppName(ctx context.Context, appName string) (int, error)
 	GetGameShieldRuleIdByAppName(ctx context.Context, appName string) (int, error)
 	UpdateGameShieldByHostId(ctx context.Context, gameShield *model.GameShield) error
 	UpdateGameShieldByHostId(ctx context.Context, gameShield *model.GameShield) error
 	GetGameShieldByHostId(ctx context.Context, hostId int) (*model.GameShield, error)
 	GetGameShieldByHostId(ctx context.Context, hostId int) (*model.GameShield, error)
@@ -112,10 +112,10 @@ func (r *gameShieldRepository) GetGameShieldNameByDunName(ctx context.Context, a
 	return res, nil
 	return res, nil
 }
 }
 
 
-func (r *gameShieldRepository) GetGameShieldIdByDunName(ctx context.Context, id int64) (string, error) {
+func (r *gameShieldRepository) GetGameShieldHostIdByDunName(ctx context.Context, hostId string) (string, error) {
 	var res string
 	var res string
 	if err := r.DB(ctx).Model(&model.GameShield{}).
 	if err := r.DB(ctx).Model(&model.GameShield{}).
-		Where("id = ?", id).
+		Where("host_id = ?", hostId).
 		Pluck("dun_name", &res).Error; err != nil {
 		Pluck("dun_name", &res).Error; err != nil {
 		return "", err
 		return "", err
 	}
 	}

+ 2 - 2
internal/service/gameshield.go

@@ -143,8 +143,8 @@ func (service *gameShieldService) DeleteGameShield(ctx context.Context, id int)
 	return res, nil
 	return res, nil
 }
 }
 
 
-func (service *gameShieldService) GetGameShieldKey(ctx context.Context, id int) (string, error) {
-	dunName, err := service.gameShieldRepository.GetGameShieldIdByDunName(ctx, int64(id))
+func (service *gameShieldService) GetGameShieldKey(ctx context.Context, hostId int) (string, error) {
+	dunName, err := service.gameShieldRepository.GetGameShieldHostIdByDunName(ctx, strconv.Itoa(hostId))
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err
 	}
 	}

+ 99 - 17
pkg/log/log.go

@@ -2,24 +2,66 @@ package log
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/viper"
 	"github.com/spf13/viper"
 	"go.uber.org/zap"
 	"go.uber.org/zap"
 	"go.uber.org/zap/zapcore"
 	"go.uber.org/zap/zapcore"
 	"gopkg.in/natefinch/lumberjack.v2"
 	"gopkg.in/natefinch/lumberjack.v2"
 	"os"
 	"os"
+	"path/filepath"
 	"time"
 	"time"
 )
 )
 
 
 const ctxLoggerKey = "zapLogger"
 const ctxLoggerKey = "zapLogger"
 
 
+// ServiceType 服务类型
+type ServiceType int
+
+const (
+	API  ServiceType = iota // API服务
+	Task                    // Task服务
+)
+
 type Logger struct {
 type Logger struct {
 	*zap.Logger
 	*zap.Logger
 }
 }
 
 
+// NewLog 创建一个新的日志实例,兼容旧版本配置
 func NewLog(conf *viper.Viper) *Logger {
 func NewLog(conf *viper.Viper) *Logger {
-	// log address "out.log" User-defined
-	lp := conf.GetString("log.log_file_name")
+	return NewServiceLog(conf, API)
+}
+
+// NewServiceLog 创建特定服务类型的日志实例
+func NewServiceLog(conf *viper.Viper, serviceType ServiceType) *Logger {
+	var logPath string
+
+	// 根据服务类型和日期生成日志文件名
+	logFormat := conf.GetString("log.log_format") // 日期格式,如"2006-01-02"
+	currentDate := time.Now().Format(logFormat)
+
+	if serviceType == API && conf.IsSet("log.api_log_file") {
+		// 使用API日志路径
+		logPath = conf.GetString("log.api_log_file")
+		logPath = fmt.Sprintf(logPath, currentDate) // 替换日期占位符
+	} else if serviceType == Task && conf.IsSet("log.task_log_file") {
+		// 使用Task日志路径
+		logPath = conf.GetString("log.task_log_file")
+		logPath = fmt.Sprintf(logPath, currentDate) // 替换日期占位符
+	} else {
+		// 如果未配置专用日志路径,则使用旧配置
+		logPath = conf.GetString("log.log_file_name")
+	}
+
+	// 确保日志目录存在
+	if err := ensureDirExists(logPath); err != nil {
+		// 如果创建目录失败,回退到临时目录
+		fmt.Printf("Error creating log directory: %v, using default path\n", err)
+		logPath = "./logs/app.log"
+		ensureDirExists(logPath)
+	}
+
+	// 获取日志级别
 	lv := conf.GetString("log.log_level")
 	lv := conf.GetString("log.log_level")
 	var level zapcore.Level
 	var level zapcore.Level
 	//debug<info<warn<error<fatal<panic
 	//debug<info<warn<error<fatal<panic
@@ -35,14 +77,17 @@ func NewLog(conf *viper.Viper) *Logger {
 	default:
 	default:
 		level = zap.InfoLevel
 		level = zap.InfoLevel
 	}
 	}
+
+	// 日志轮转配置
 	hook := lumberjack.Logger{
 	hook := lumberjack.Logger{
-		Filename:   lp,                             // Log file path
-		MaxSize:    conf.GetInt("log.max_size"),    // Maximum size unit for each log file: M
-		MaxBackups: conf.GetInt("log.max_backups"), // The maximum number of backups that can be saved for log files
-		MaxAge:     conf.GetInt("log.max_age"),     // Maximum number of days the file can be saved
-		Compress:   conf.GetBool("log.compress"),   // Compression or not
+		Filename:   logPath,                        // 日志文件路径
+		MaxSize:    conf.GetInt("log.max_size"),    // 每个日志文件的最大大小单位:M
+		MaxBackups: conf.GetInt("log.max_backups"), // 日志文件最多保存的备份数
+		MaxAge:     conf.GetInt("log.max_age"),     // 文件最多保存的天数
+		Compress:   conf.GetBool("log.compress"),   // 是否压缩
 	}
 	}
 
 
+	// 配置日志编码器
 	var encoder zapcore.Encoder
 	var encoder zapcore.Encoder
 	if conf.GetString("log.encoding") == "console" {
 	if conf.GetString("log.encoding") == "console" {
 		encoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
 		encoder = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
@@ -60,7 +105,7 @@ func NewLog(conf *viper.Viper) *Logger {
 		})
 		})
 	} else {
 	} else {
 		encoder = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
 		encoder = zapcore.NewJSONEncoder(zapcore.EncoderConfig{
-			TimeKey:        "ts",
+			TimeKey:        "time",
 			LevelKey:       "level",
 			LevelKey:       "level",
 			NameKey:        "logger",
 			NameKey:        "logger",
 			CallerKey:      "caller",
 			CallerKey:      "caller",
@@ -69,24 +114,61 @@ func NewLog(conf *viper.Viper) *Logger {
 			StacktraceKey:  "stacktrace",
 			StacktraceKey:  "stacktrace",
 			LineEnding:     zapcore.DefaultLineEnding,
 			LineEnding:     zapcore.DefaultLineEnding,
 			EncodeLevel:    zapcore.LowercaseLevelEncoder,
 			EncodeLevel:    zapcore.LowercaseLevelEncoder,
-			EncodeTime:     zapcore.EpochTimeEncoder,
-			EncodeDuration: zapcore.SecondsDurationEncoder,
+			EncodeTime:     timeEncoder, // 使用自定义时间格式
+			EncodeDuration: zapcore.StringDurationEncoder,
 			EncodeCaller:   zapcore.ShortCallerEncoder,
 			EncodeCaller:   zapcore.ShortCallerEncoder,
 		})
 		})
 	}
 	}
-	core := zapcore.NewCore(
-		encoder,
-		zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // Print to console and file
-		level,
+
+	// 创建日志核心
+	logOutput := zapcore.NewMultiWriteSyncer(
+		zapcore.AddSync(os.Stdout), // 同时输出到控制台
+		zapcore.AddSync(&hook),     // 和文件
 	)
 	)
+	core := zapcore.NewCore(encoder, logOutput, level)
+
+	// 开发环境与生产环境的差异化配置
+	var logger *zap.Logger
 	if conf.GetString("env") != "prod" {
 	if conf.GetString("env") != "prod" {
-		return &Logger{zap.New(core, zap.Development(), zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))}
+		logger = zap.New(core,
+			zap.Development(),
+			zap.AddCaller(),
+			zap.AddStacktrace(zap.ErrorLevel),
+		)
+	} else {
+		logger = zap.New(core,
+			zap.AddCaller(),
+			zap.AddStacktrace(zap.ErrorLevel),
+		)
+	}
+
+	// 添加服务类型标识
+	serviceTypeField := zap.String("service", serviceTypeToString(serviceType))
+	logger = logger.With(serviceTypeField)
+
+	return &Logger{logger}
+}
+
+// ensureDirExists 确保日志目录存在
+func ensureDirExists(filePath string) error {
+	dir := filepath.Dir(filePath)
+	return os.MkdirAll(dir, 0755)
+}
+
+// serviceTypeToString 将服务类型转换为字符串
+func serviceTypeToString(serviceType ServiceType) string {
+	switch serviceType {
+	case API:
+		return "api"
+	case Task:
+		return "task"
+	default:
+		return "unknown"
 	}
 	}
-	return &Logger{zap.New(core, zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))}
 }
 }
 
 
+// timeEncoder 自定义时间编码器,提供高精度时间戳
 func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
 func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
-	//enc.AppendString(t.Format("2006-01-02 15:04:05"))
 	enc.AppendString(t.Format("2006-01-02 15:04:05.000000000"))
 	enc.AppendString(t.Format("2006-01-02 15:04:05.000000000"))
 }
 }