Оптимизация журналирования событий
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user