做完了一部分,备份一下,防止以外删除

This commit is contained in:
2025-11-11 15:16:38 +08:00
parent 9600e5b6e0
commit e98dd4d725
39 changed files with 2423 additions and 183 deletions

146
pkg/logger/logger.go Normal file
View File

@@ -0,0 +1,146 @@
package logger
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
var (
// appLogger 应用日志记录器
appLogger *zap.Logger
// accessLogger 访问日志记录器
accessLogger *zap.Logger
)
// InitLoggers 初始化应用和访问日志记录器
func InitLoggers(
level string,
development bool,
appLogConfig LogRotationConfig,
accessLogConfig LogRotationConfig,
) error {
// 解析日志级别
zapLevel := parseLevel(level)
// 创建编码器配置
encoderConfig := zapcore.EncoderConfig{
TimeKey: "timestamp",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder, // RFC3339 格式
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
// 选择编码器(开发模式使用控制台,生产使用 JSON
var encoder zapcore.Encoder
if development {
encoder = zapcore.NewConsoleEncoder(encoderConfig)
} else {
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
// 创建应用日志核心
appCore := zapcore.NewCore(
encoder,
zapcore.AddSync(newLumberjackLogger(appLogConfig)),
zapLevel,
)
// 创建访问日志核心(始终使用 JSON
accessCore := zapcore.NewCore(
zapcore.NewJSONEncoder(encoderConfig),
zapcore.AddSync(newLumberjackLogger(accessLogConfig)),
zapcore.InfoLevel, // 访问日志始终使用 info 级别
)
// 构建日志记录器
if development {
// 开发模式:添加调用者信息和堆栈跟踪
appLogger = zap.New(appCore, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel), zap.Development())
} else {
// 生产模式:添加调用者信息,仅在 error 时添加堆栈跟踪
appLogger = zap.New(appCore, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
}
// 访问日志不需要调用者信息
accessLogger = zap.New(accessCore)
return nil
}
// GetAppLogger 返回应用日志记录器
func GetAppLogger() *zap.Logger {
if appLogger == nil {
// 如果未初始化,返回 nop logger
return zap.NewNop()
}
return appLogger
}
// GetAccessLogger 返回访问日志记录器
func GetAccessLogger() *zap.Logger {
if accessLogger == nil {
// 如果未初始化,返回 nop logger
return zap.NewNop()
}
return accessLogger
}
// Sync 刷新所有日志缓冲区
func Sync() error {
if appLogger != nil {
if err := appLogger.Sync(); err != nil {
return err
}
}
if accessLogger != nil {
if err := accessLogger.Sync(); err != nil {
return err
}
}
return nil
}
// parseLevel 解析日志级别字符串
func parseLevel(level string) zapcore.Level {
switch level {
case "debug":
return zapcore.DebugLevel
case "info":
return zapcore.InfoLevel
case "warn":
return zapcore.WarnLevel
case "error":
return zapcore.ErrorLevel
default:
return zapcore.InfoLevel
}
}
// newLumberjackLogger 创建 Lumberjack 日志轮转器
func newLumberjackLogger(config LogRotationConfig) *lumberjack.Logger {
return &lumberjack.Logger{
Filename: config.Filename,
MaxSize: config.MaxSize,
MaxBackups: config.MaxBackups,
MaxAge: config.MaxAge,
Compress: config.Compress,
LocalTime: true, // 使用本地时间
}
}
// LogRotationConfig 日志轮转配置(从 config 包复制以避免循环依赖)
type LogRotationConfig struct {
Filename string
MaxSize int
MaxBackups int
MaxAge int
Compress bool
}

52
pkg/logger/middleware.go Normal file
View File

@@ -0,0 +1,52 @@
package logger
import (
"time"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
// Middleware 创建 Fiber 日志中间件
// 记录所有 HTTP 请求到访问日志
func Middleware() fiber.Handler {
return func(c *fiber.Ctx) error {
// 记录请求开始时间
startTime := time.Now()
c.Locals(constants.ContextKeyStartTime, startTime)
// 处理请求
err := c.Next()
// 计算请求持续时间
duration := time.Since(startTime)
// 获取请求 ID由 requestid 中间件设置)
requestID := ""
if rid := c.Locals(constants.ContextKeyRequestID); rid != nil {
requestID = rid.(string)
}
// 获取用户 ID由 auth 中间件设置)
userID := ""
if uid := c.Locals(constants.ContextKeyUserID); uid != nil {
userID = uid.(string)
}
// 记录访问日志
accessLogger := GetAccessLogger()
accessLogger.Info("",
zap.String("method", c.Method()),
zap.String("path", c.Path()),
zap.Int("status", c.Response().StatusCode()),
zap.Float64("duration_ms", float64(duration.Microseconds())/1000.0),
zap.String("request_id", requestID),
zap.String("ip", c.IP()),
zap.String("user_agent", c.Get("User-Agent")),
zap.String(constants.ContextKeyUserID, userID),
)
return err
}
}