package logger import ( "strings" "sync" "time" "douyu_go/internal/constants" "douyu_go/internal/types" ) // MemoryLogStore 内存日志缓冲,实现 io.Writer 接口。 type MemoryLogStore struct { mu sync.RWMutex nextID int64 max int filePath string entries []types.LogEntry } // NewMemoryLogStore 创建内存日志缓冲,最多保留 max 条最新日志。 func NewMemoryLogStore(max int) *MemoryLogStore { if max <= 0 { max = 500 } return &MemoryLogStore{ max: max, entries: make([]types.LogEntry, 0, max), } } // Write 实现 io.Writer,把标准 log 输出转存为内存日志。 func (s *MemoryLogStore) Write(p []byte) (int, error) { text := strings.TrimRight(string(p), "\r\n") if text == "" { return len(p), nil } s.mu.Lock() defer s.mu.Unlock() for _, line := range strings.Split(text, "\n") { line = strings.TrimRight(line, "\r") if strings.TrimSpace(line) == "" { continue } category, level := ParseLogMeta(line) if level == "" { level = DetectLogLevel(line) } s.nextID++ s.entries = append(s.entries, types.LogEntry{ ID: s.nextID, Time: time.Now().In(constants.CST).Format("2006-01-02 15:04:05.000"), Level: level, Category: category, Message: line, }) if len(s.entries) > s.max { copy(s.entries, s.entries[len(s.entries)-s.max:]) s.entries = s.entries[:s.max] } } return len(p), nil } // SetFilePath 保存当前日志文件路径。 func (s *MemoryLogStore) SetFilePath(path string) { s.mu.Lock() defer s.mu.Unlock() s.filePath = path } // Since 返回 ID 大于 since 的日志。 func (s *MemoryLogStore) Since(since int64) []types.LogEntry { s.mu.RLock() defer s.mu.RUnlock() out := make([]types.LogEntry, 0, len(s.entries)) for _, entry := range s.entries { if entry.ID > since { out = append(out, entry) } } return out } // FilePath 返回当前日志文件路径。 func (s *MemoryLogStore) FilePath() string { s.mu.RLock() defer s.mu.RUnlock() return s.filePath }