Оптимизация журналирования событий

This commit is contained in:
Maxim
2026-06-19 10:34:07 +03:00
parent 7fc5b79bf5
commit 311d09f0b3
2 changed files with 80 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
package logger
import (
"fmt"
"log"
"os"
"path/filepath"
@@ -70,37 +71,48 @@ func (r *Retention) Cleanup() {
return
}
if r.eventLogger != nil {
r.eventLogger.Event("ЗАПУЩЕНА_ОЧИСТКАОГОВ")
}
// 1. Удаляем старые файлы (если включено)
deletedByAge := 0
var deletedByAgeBytes int64
if r.maxAgeHours > 0 {
deletedByAge = r.cleanByAge(dataDir)
deletedByAge, deletedByAgeBytes = r.cleanByAge(dataDir)
}
// 2. Проверяем общий размер и удаляем самые старые если превышен лимит (если включено)
deletedBySize := 0
var deletedBySizeBytes int64
if r.maxSizeBytes > 0 {
deletedBySize = r.cleanBySize(dataDir)
deletedBySize, deletedBySizeBytes = r.cleanBySize(dataDir)
}
if r.eventLogger != nil && (deletedByAge > 0 || deletedBySize > 0) {
r.eventLogger.Event("УДАЛЕНОАЙЛОВ")
log.Printf("Очистка логов: удалено %d файлов (по возрасту: %d, по размеру: %d)",
deletedByAge+deletedBySize, deletedByAge, deletedBySize)
totalDeleted := deletedByAge + deletedBySize
totalDeletedBytes := deletedByAgeBytes + deletedBySizeBytes
// Логируем ТОЛЬКО если были удаления
if totalDeleted > 0 {
// Логируем суммарное событие
if r.eventLogger != nil {
eventMsg := fmt.Sprintf("ОЧИСТКАОГОВ_УДАЛЕНО_%d_ФАЙЛОВ_%d_MB",
totalDeleted, totalDeletedBytes/(1024*1024))
r.eventLogger.Event(eventMsg)
}
// Пишем в консоль для отладки
log.Printf("Очистка логов: удалено %d файлов (%.2f MB) [по возрасту: %d, по размеру: %d]",
totalDeleted, float64(totalDeletedBytes)/(1024*1024), deletedByAge, deletedBySize)
}
}
func (r *Retention) cleanByAge(dataDir string) int {
// cleanByAge возвращает количество удаленных файлов и их общий размер в байтах
func (r *Retention) cleanByAge(dataDir string) (int, int64) {
cutoff := time.Now().Add(-time.Duration(r.maxAgeHours) * time.Hour)
deleted := 0
var deletedBytes int64
// Получаем все .bin файлы
files, err := filepath.Glob(filepath.Join(dataDir, "gpio-*.bin"))
if err != nil {
return 0
return 0, 0
}
for _, file := range files {
@@ -118,25 +130,24 @@ func (r *Retention) cleanByAge(dataDir string) int {
if fileTime.Before(cutoff) {
if err := os.Remove(file); err == nil {
deleted++
if r.eventLogger != nil {
r.eventLogger.Event("УДАЛЕНАЙЛ_ПО_ВОЗРАСТУ")
}
deletedBytes += info.Size()
}
}
}
return deleted
return deleted, deletedBytes
}
func (r *Retention) cleanBySize(dataDir string) int {
// cleanBySize возвращает количество удаленных файлов и их общий размер в байтах
func (r *Retention) cleanBySize(dataDir string) (int, int64) {
// Получаем все файлы
files, err := filepath.Glob(filepath.Join(dataDir, "gpio-*.bin"))
if err != nil {
return 0
return 0, 0
}
if len(files) == 0 {
return 0
return 0, 0
}
// Сортируем по времени (старыми первыми)
@@ -175,22 +186,23 @@ func (r *Retention) cleanBySize(dataDir string) int {
// Удаляем самые старые пока не уложимся в лимит
deleted := 0
var deletedBytes int64
// Сохраняем как минимум 1 файл
for totalSize > r.maxSizeBytes && len(fileList) > 1 {
// Удаляем самый старый файл
oldest := fileList[0]
if err := os.Remove(oldest.path); err == nil {
totalSize -= oldest.size
deletedBytes += oldest.size
deleted++
fileList = fileList[1:]
if r.eventLogger != nil {
r.eventLogger.Event("УДАЛЕНАЙЛ_ПО_РАЗМЕРУ")
}
} else {
break
}
}
return deleted
return deleted, deletedBytes
}
func (r *Retention) parseFilenameTime(filename string) time.Time {

View File

@@ -23,8 +23,12 @@ type PipeReader struct {
lastAlertTime map[byte]time.Time
// Настройки
alertCooldownSec time.Duration
alertCooldownSec time.Duration
humanLogIntervalSec time.Duration
// Флаги состояния
pipeState string // "unknown", "found", "not_found"
lastLoggedState string // для отслеживания изменений
}
func NewPipeReader(
@@ -36,14 +40,26 @@ func NewPipeReader(
config *logger.Config,
) *PipeReader {
return &PipeReader{
buf: buf,
dataLogger: dataLogger,
humanLogger: humanLogger,
monitor: monitor,
eventLog: eventLog,
lastAlertTime: make(map[byte]time.Time),
alertCooldownSec: config.AlertCooldownSec,
buf: buf,
dataLogger: dataLogger,
humanLogger: humanLogger,
monitor: monitor,
eventLog: eventLog,
lastAlertTime: make(map[byte]time.Time),
alertCooldownSec: config.AlertCooldownSec,
humanLogIntervalSec: config.HumanLogIntervalSec,
pipeState: "unknown",
lastLoggedState: "unknown",
}
}
func (pr *PipeReader) logStateChange(newState string, eventName string) {
if newState != pr.lastLoggedState {
if pr.eventLog != nil {
pr.eventLog.Event(eventName)
}
pr.lastLoggedState = newState
}
}
@@ -59,8 +75,10 @@ func (pr *PipeReader) Start(ctx context.Context, pipePath string) {
}
if _, err := os.Stat(pipePath); os.IsNotExist(err) {
if pr.eventLog != nil {
pr.eventLog.Event("PIPE_НЕ_НАЙДЕН")
// Логируем ТОЛЬКО при смене состояния
if pr.pipeState != "not_found" {
pr.pipeState = "not_found"
pr.logStateChange("not_found", "PIPE_НЕ_НАЙДЕН")
}
time.Sleep(2 * time.Second)
continue
@@ -68,27 +86,38 @@ func (pr *PipeReader) Start(ctx context.Context, pipePath string) {
f, err := os.OpenFile(pipePath, os.O_RDONLY, 0)
if err != nil {
if pr.eventLog != nil {
pr.eventLog.Event("ОШИБКА_ОТКРЫТИЯ_PIPE")
if pr.pipeState != "error" {
pr.pipeState = "error"
pr.logStateChange("error", "ОШИБКА_ОТКРЫТИЯ_PIPE")
}
time.Sleep(time.Second)
continue
}
if pr.eventLog != nil {
pr.eventLog.Event("PIPE_ПОДКЛЮЧЕН")
// Pipe успешно открыт
if pr.pipeState != "found" {
pr.pipeState = "found"
pr.logStateChange("found", "PIPE_ПОДКЛЮЧЕН")
}
for {
n, err := f.Read(buffer)
if err != nil {
f.Close()
if pr.eventLog != nil {
pr.eventLog.Event("PIPE_ОТКЛЮЧЕН")
// Отключаемся только если были подключены
if pr.pipeState == "found" {
pr.pipeState = "disconnected"
pr.logStateChange("disconnected", "PIPE_ОТКЛЮЧЕН")
}
break
}
// Если были в состоянии ошибки/отключения, восстанавливаемся
if pr.pipeState != "found" {
pr.pipeState = "found"
pr.logStateChange("found", "PIPE_ПОДКЛЮЧЕН")
}
for i := 0; i < n; i++ {
rawByte := buffer[i]
now := time.Now()