chore: 初始化仓库,排除二进制文件和覆盖率文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
Test / test (push) Has been cancelled
Test / lint (push) Has been cancelled
Test / build (push) Has been cancelled

This commit is contained in:
lan
2025-11-28 23:30:49 +08:00
commit 4b4980820f
107 changed files with 20755 additions and 0 deletions

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

@@ -0,0 +1,68 @@
package logger
import (
"os"
"path/filepath"
"carrotskin/pkg/config"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// New 创建新的日志记录器
func New(cfg config.LogConfig) (*zap.Logger, error) {
// 配置日志级别
var level zapcore.Level
switch cfg.Level {
case "debug":
level = zapcore.DebugLevel
case "info":
level = zapcore.InfoLevel
case "warn":
level = zapcore.WarnLevel
case "error":
level = zapcore.ErrorLevel
default:
level = zapcore.InfoLevel
}
// 配置编码器
var encoder zapcore.Encoder
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.TimeKey = "timestamp"
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
if cfg.Format == "console" {
encoder = zapcore.NewConsoleEncoder(encoderConfig)
} else {
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
// 配置输出
var writeSyncer zapcore.WriteSyncer
if cfg.Output == "" || cfg.Output == "stdout" {
writeSyncer = zapcore.AddSync(os.Stdout)
} else {
// 自动创建日志目录
logDir := filepath.Dir(cfg.Output)
if err := os.MkdirAll(logDir, 0755); err != nil {
return nil, err
}
file, err := os.OpenFile(cfg.Output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
writeSyncer = zapcore.AddSync(file)
}
// 创建核心
core := zapcore.NewCore(encoder, writeSyncer, level)
// 创建日志记录器
logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
return logger, nil
}

50
pkg/logger/manager.go Normal file
View File

@@ -0,0 +1,50 @@
package logger
import (
"carrotskin/pkg/config"
"fmt"
"sync"
"go.uber.org/zap"
)
var (
// loggerInstance 全局日志实例
loggerInstance *zap.Logger
// once 确保只初始化一次
once sync.Once
// initError 初始化错误
initError error
)
// Init 初始化日志记录器(线程安全,只会执行一次)
func Init(cfg config.LogConfig) error {
once.Do(func() {
loggerInstance, initError = New(cfg)
if initError != nil {
return
}
})
return initError
}
// GetLogger 获取日志实例(线程安全)
func GetLogger() (*zap.Logger, error) {
if loggerInstance == nil {
return nil, fmt.Errorf("日志未初始化,请先调用 logger.Init()")
}
return loggerInstance, nil
}
// MustGetLogger 获取日志实例如果未初始化则panic
func MustGetLogger() *zap.Logger {
logger, err := GetLogger()
if err != nil {
panic(err)
}
return logger
}

View File

@@ -0,0 +1,47 @@
package logger
import (
"carrotskin/pkg/config"
"testing"
)
// TestGetLogger_NotInitialized 测试未初始化时获取日志实例
func TestGetLogger_NotInitialized(t *testing.T) {
_, err := GetLogger()
if err == nil {
t.Error("未初始化时应该返回错误")
}
expectedError := "日志未初始化,请先调用 logger.Init()"
if err.Error() != expectedError {
t.Errorf("错误消息 = %q, want %q", err.Error(), expectedError)
}
}
// TestMustGetLogger_Panic 测试MustGetLogger在未初始化时panic
func TestMustGetLogger_Panic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("MustGetLogger 应该在未初始化时panic")
}
}()
_ = MustGetLogger()
}
// TestInit_Logger 测试日志初始化逻辑
func TestInit_Logger(t *testing.T) {
cfg := config.LogConfig{
Level: "info",
Format: "json",
Output: "stdout",
}
// 验证Init函数存在且可调用
err := Init(cfg)
if err != nil {
// 初始化可能失败(例如缺少依赖),这是可以接受的
t.Logf("Init() 返回错误(可能正常): %v", err)
}
}