package logger import ( "fmt" "path/filepath" "sync" "time" ) type RotatingLogger struct { dataLogger *DataLogger currentHour int baseDir string mu sync.Mutex eventLogger *EventLogger checkInterval time.Duration } func NewRotatingLogger(eventLogger *EventLogger, checkInterval time.Duration) (*RotatingLogger, error) { // Получаем директорию для бинарных данных dataDir, err := GetDataLogsDir() if err != nil { return nil, err } // Интервал проверки по умолчанию if checkInterval == 0 { checkInterval = 1 * time.Minute } r := &RotatingLogger{ baseDir: dataDir, eventLogger: eventLogger, checkInterval: checkInterval, } if err := r.rotate(); err != nil { return nil, err } go r.rotationLoop() return r, nil } func (r *RotatingLogger) getFilename() string { now := time.Now() return filepath.Join(r.baseDir, fmt.Sprintf("gpio-%04d-%02d-%02d-%02d.bin", now.Year(), now.Month(), now.Day(), now.Hour())) } func (r *RotatingLogger) rotate() error { r.mu.Lock() defer r.mu.Unlock() now := time.Now() newHour := now.Hour() // Если уже правильный час и логгер существует - ок if r.dataLogger != nil && r.currentHour == newHour { return nil } // Закрываем старый if r.dataLogger != nil { r.dataLogger.Close() } // Открываем новый filename := r.getFilename() dataLogger, err := NewDataLogger(filename) if err != nil { if r.eventLogger != nil { r.eventLogger.Event("ПЛАНОВАЯ_РОТАЦИЯ_НЕУДАЧНА") } return err } r.dataLogger = dataLogger r.currentHour = newHour if r.eventLogger != nil { r.eventLogger.Event("ПЛАНОВАЯ_РОТАЦИЯ") } return nil } func (r *RotatingLogger) Write(s Sample) { r.mu.Lock() logger := r.dataLogger r.mu.Unlock() if logger != nil { logger.Write(s) } } func (r *RotatingLogger) rotationLoop() { ticker := time.NewTicker(r.checkInterval) defer ticker.Stop() for range ticker.C { r.rotate() } } func (r *RotatingLogger) Close() error { r.mu.Lock() defer r.mu.Unlock() if r.dataLogger != nil { return r.dataLogger.Close() } return nil }