Files
nl-im-websocket-demo/utils/logger.go

122 lines
3.0 KiB
Go
Raw Normal View History

2025-07-03 09:16:16 +08:00
package utils
import (
"log"
"os"
2025-07-03 12:49:49 +08:00
"path/filepath"
2025-07-03 09:16:16 +08:00
"time"
)
2025-07-03 12:49:49 +08:00
// DailyFileWriter 日志文件写入器
2025-07-03 09:16:16 +08:00
type DailyFileWriter struct {
2025-07-03 12:49:49 +08:00
Dir string
Freq string
Prefix string
File *os.File
Current string
Logger *log.Logger
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
// NewDailyFileWriter 创建每日日志写入器
func NewDailyFileWriter(dir, freq string, logger *log.Logger, prefix string) *DailyFileWriter {
writer := &DailyFileWriter{
Dir: dir,
Freq: freq,
Prefix: prefix,
Logger: logger,
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
writer.rotate()
return writer
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
func (w *DailyFileWriter) getLogFileName() string {
baseName := w.Prefix + "-"
2025-07-03 09:16:16 +08:00
2025-07-03 12:49:49 +08:00
switch w.Freq {
case "daily":
return baseName + time.Now().Format("2006-01-02") + ".log"
case "hourly":
return baseName + time.Now().Format("2006-01-02-15") + ".log"
default: // 默认按分钟(适合开发)
return baseName + time.Now().Format("2006-01-02-15-04") + ".log"
2025-07-03 09:16:16 +08:00
}
}
2025-07-03 12:49:49 +08:00
func (w *DailyFileWriter) rotate() {
filename := w.getLogFileName()
filePath := filepath.Join(w.Dir, filename)
2025-07-03 09:16:16 +08:00
2025-07-03 12:49:49 +08:00
// 如果已经打开了相同的文件,则不需要重新打开
if w.Current == filePath {
return
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
// 关闭当前文件(如果存在)
if w.File != nil {
w.File.Close()
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
// 确保目录存在(双重保障)
if err := os.MkdirAll(w.Dir, 0755); err != nil {
// 如果创建目录失败,尝试使用备用目录
if w.Dir != "logs" {
w.Logger.Printf("⚠️ 无法创建日志目录 %s尝试使用备用目录: %v", w.Dir, err)
w.Dir = "logs"
if err := os.MkdirAll(w.Dir, 0755); err != nil {
w.Logger.Fatalf("❌ 无法创建备用日志目录: %v", err)
}
} else {
w.Logger.Fatalf("❌ 无法创建日志目录: %v", err)
}
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
// 打开文件(如果文件不存在则创建)
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
2025-07-03 09:16:16 +08:00
if err != nil {
2025-07-03 12:49:49 +08:00
// 如果打开文件失败,尝试使用系统临时目录作为备选
fallbackPath := filepath.Join(os.TempDir(), "xk-websocket-logs", filename)
w.Logger.Printf("⚠️ 无法打开日志文件 %s尝试备选路径: %s (%v)", filePath, fallbackPath, err)
// 确保备选目录存在
if err := os.MkdirAll(filepath.Dir(fallbackPath), 0755); err != nil {
w.Logger.Fatalf("❌ 无法创建备选日志目录: %v", err)
}
file, err = os.OpenFile(fallbackPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
w.Logger.Fatalf("❌ 无法打开备选日志文件: %v", err)
}
}
w.File = file
w.Current = filePath
}
// Write 实现io.Writer接口
func (w *DailyFileWriter) Write(p []byte) (n int, err error) {
// 检查是否需要轮转日志
needRotate := false
switch w.Freq {
case "daily":
needRotate = time.Now().Day() != time.Now().Add(-time.Second).Day()
case "hourly":
needRotate = time.Now().Hour() != time.Now().Add(-time.Second).Hour()
default: // 每分钟轮转(开发模式)
needRotate = true
}
if needRotate {
w.rotate()
2025-07-03 09:16:16 +08:00
}
2025-07-03 12:49:49 +08:00
return w.File.Write(p)
}
// Close 关闭日志文件
func (w *DailyFileWriter) Close() error {
if w.File != nil {
return w.File.Close()
2025-07-03 09:16:16 +08:00
}
return nil
}