feat(database): 新增命令行参数解析、空值检查和数据库配置管理功能

- 实现了 command 包用于控制台参数和选项解析
- 添加了 empty 包提供变量空值/零值检查功能
- 集成了 Viper 库进行配置文件管理和环境变量支持
- 提供了数据库配置初始化和默认值设置功能
- 实现了配置值获取、设置和结构化解析方法
- 添加了服务器、数据库和JWT配置的便捷获取方法
- 实现了完整的数据库接口定义和事务管理功能
This commit is contained in:
maguodong
2026-04-08 09:33:59 +08:00
parent 6dcd564206
commit af0a8f4043
132 changed files with 14331 additions and 10719 deletions
+100 -34
View File
@@ -9,6 +9,7 @@ import (
"regexp"
"runtime/debug"
"strings"
"sync"
"time"
"github.com/gogf/gf/v2/os/gfile"
@@ -16,13 +17,13 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
)
var (
type sLogger struct {
logPath string
sysLog *log.Logger
filePath string
currentDate string // 当前日志文件对应的日期
fileLogger *lumberjack.Logger
)
}
const (
Reset = "\033[0m"
@@ -63,21 +64,26 @@ func (w *logWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
var (
logs *sLogger
initMu sync.Mutex // 用于保护初始化过程的互斥锁
)
// cleanOldLogs 删除指定天数之前的日志文件(包括主文件和备份文件)
func cleanOldLogs(days int) {
if !gfile.Exists(logPath) {
if !gfile.Exists(logs.logPath) {
return
}
// 获取所有日志文件
files, err := gfile.DirNames(logPath)
files, err := gfile.DirNames(logs.logPath)
if err != nil {
return
}
now := time.Now()
for _, file := range files {
path := filepath.Join(logPath, file)
path := filepath.Join(logs.logPath, file)
if gfile.IsDir(path) {
continue
}
@@ -128,12 +134,12 @@ func cleanOldLogs(days int) {
// checkAndRotateLogFile 检查是否需要切换日志文件(跨天时)
func checkAndRotateLogFile() {
date := gtime.Date()
if currentDate != date {
if logs.currentDate != date {
// 日期变化,需要重新初始化
currentDate = date
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
fileLogger = &lumberjack.Logger{
Filename: filePath,
logs.currentDate = date
logs.filePath = gfile.Join(logs.logPath, fmt.Sprintf("log-%s.log", logs.currentDate))
logs.fileLogger = &lumberjack.Logger{
Filename: logs.filePath,
MaxSize: 2, // 单个文件最大 10MB
MaxBackups: 5, // 最多保留 5 个备份
MaxAge: 30, // 保留 30 天
@@ -142,9 +148,9 @@ func checkAndRotateLogFile() {
// 创建新的 writer
multiWriter := &logWriter{
console: os.Stdout,
file: fileLogger,
file: logs.fileLogger,
}
sysLog = log.New(multiWriter, "", 0)
logs.sysLog = log.New(multiWriter, "", 0)
// 清理 30 天前的旧日志
cleanOldLogs(30)
@@ -152,49 +158,109 @@ func checkAndRotateLogFile() {
}
func Init() {
if sysLog != nil {
checkAndRotateLogFile() // 检查是否需要切换文件
// 如果已经初始化,检查是否需要切换文件
if logs != nil && logs.sysLog != nil {
checkAndRotateLogFile()
return
}
logPath = gfile.Join(gfile.Pwd(), "logs")
currentDate = gtime.Date()
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
fileLogger = &lumberjack.Logger{
// 加锁确保线程安全
initMu.Lock()
defer initMu.Unlock()
// 双重检查,避免重复初始化
if logs != nil && logs.sysLog != nil {
return
}
// 初始化日志器
currentDate := gtime.Date()
logPath := gfile.Join(gfile.Pwd(), "logs")
filePath := gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
// 创建 lumberjack 日志文件处理器
fileLogger := &lumberjack.Logger{
Filename: filePath,
MaxSize: 2, // 单个文件最大 10MB
MaxSize: 2, // 单个文件最大 2MB
MaxBackups: 5, // 最多保留 5 个备份
MaxAge: 30, // 保留 30 天
Compress: false, // 启用压缩
Compress: false, // 不启用压缩
}
// 使用自定义 writer 实现控制台带颜色、文件无颜色的输出
multiWriter := &logWriter{
console: os.Stdout,
file: fileLogger,
}
sysLog = log.New(multiWriter, "", 0)
logs = &sLogger{
logPath: logPath,
sysLog: log.New(multiWriter, "", 0),
fileLogger: fileLogger,
filePath: filePath,
currentDate: currentDate,
}
// 启动时清理 30 天前的旧日志
cleanOldLogs(30)
}
func Info(v ...any) {
func (s *sLogger) Info(v ...any) {
Init()
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[INFO]%s ", time.Now().Format("2006-01-02 15:04:05"), Green, Reset))
sysLog.Println(fmt.Sprint(v...))
s.sysLog.SetPrefix(fmt.Sprintf("[%s] %s[INFO]%s ", time.Now().Format("2006-01-02 15:04:05"), Green, Reset))
s.sysLog.Println(fmt.Sprint(v...))
}
func (s *sLogger) Error(v ...any) {
Init()
s.sysLog.SetPrefix(fmt.Sprintf("[%s] %s[ERROR]%s ", time.Now().Format("2006-01-02 15:04:05"), Red, Reset))
msg := fmt.Sprint(v...)
s.sysLog.Println(msg, strings.TrimSpace(string(debug.Stack())))
}
func (s *sLogger) Warn(v ...any) {
Init()
s.sysLog.SetPrefix(fmt.Sprintf("[%s] %s[WARN]%s ", time.Now().Format("2006-01-02 15:04:05"), Yellow, Reset))
s.sysLog.Println(fmt.Sprint(v...))
}
func (s *sLogger) Debug(v ...any) {
Init()
s.sysLog.SetPrefix(fmt.Sprintf("[%s] %s[DEBUG]%s ", time.Now().Format("2006-01-02 15:04:05"), Blue, Reset))
s.sysLog.Println(fmt.Sprint(v...))
}
func Info(v ...any) {
if logs == nil {
Init()
}
logs.Info(v...)
}
func Error(v ...any) {
Init()
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[ERROR]%s ", time.Now().Format("2006-01-02 15:04:05"), Red, Reset))
msg := fmt.Sprint(v...)
sysLog.Println(msg, strings.TrimSpace(string(debug.Stack())))
if logs == nil {
Init()
}
logs.Error(v...)
}
func Warn(v ...any) {
Init()
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[WARN]%s ", time.Now().Format("2006-01-02 15:04:05"), Yellow, Reset))
sysLog.Println(fmt.Sprint(v...))
if logs == nil {
Init()
}
logs.Warn(v...)
}
func Debug(v ...any) {
Init()
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[DEBUG]%s ", time.Now().Format("2006-01-02 15:04:05"), Blue, Reset))
sysLog.Println(fmt.Sprint(v...))
if logs == nil {
Init()
}
logs.Debug(v...)
}
// GetLogger 返回自定义日志器实例,实现 ILogger 接口
func GetLogger() ILogger {
Init()
return logs
}
type ILogger interface {
Info(v ...any)
Error(v ...any)
Warn(v ...any)
Debug(v ...any)
}