""" Чтение логов SES через POST /ses/log. Позволяет получить логи за указанную дату для анализа ошибок. Функциональность пока отключена по умолчанию (config.yaml: monitoring.log_enabled), так как запрос логов может быть ресурсоёмким. """ from __future__ import annotations import logging from dataclasses import dataclass from datetime import datetime from typing import Any, Dict, List, Optional from ses_monitor.session_client import SESClient log = logging.getLogger("ses_monitor.log_client") @dataclass class LogCheckResult: """Результат проверки логов.""" date: str = "" fetch_error: str = "" lines_count: int = 0 # Паттерны для поиска ошибок (расширяются по мере необходимости) error_patterns: Dict[str, int] = None # type: ignore def __post_init__(self): if self.error_patterns is None: self.error_patterns = {} class LogChecker: """Проверяет логи SES на наличие ошибок. Ищет паттерны: - "ERROR" / "CRITICAL" — критические ошибки. - "HTTPError" / "RequestException" — ошибки внешних API. - "json.JSONDecodeError" — ошибки парсинга. - "connection refused" / "timeout" — сетевые проблемы. """ ERROR_PATTERNS = [ ("error_count", "ERROR"), ("critical_count", "CRITICAL"), ("http_error_count", "HTTPError"), ("request_exception_count", "RequestException"), ("json_error_count", "JSONDecodeError"), ("timeout_count", "timeout"), ("refused_count", "Connection refused"), ] async def check(self, client: SESClient) -> LogCheckResult: """Запрашивает и анализирует логи за сегодняшний день. Args: client: HTTP-клиент для SES API. Returns: Результат анализа логов. """ result = LogCheckResult(date=datetime.now().strftime("%Y-%m-%d")) try: log_data = await client.get_logs(result.date) except Exception as e: result.fetch_error = str(e) log.error("Log check: ошибка получения логов: %s", e) return result # Если ответ — строка (plain text логов) if isinstance(log_data, str): result.lines_count = log_data.count("\n") + 1 for key, pattern in self.ERROR_PATTERNS: result.error_patterns[key] = log_data.count(pattern) # Если ответ — словарь (структурированные данные) elif isinstance(log_data, dict): if log_data.get("error") == 0 and "data" in log_data: data = log_data["data"] if isinstance(data, str): result.lines_count = data.count("\n") + 1 for key, pattern in self.ERROR_PATTERNS: result.error_patterns[key] = data.count(pattern) log.info( "Log check: %d строк за %s, ошибок: %s", result.lines_count, result.date, {k: v for k, v in result.error_patterns.items() if v > 0}, ) return result