Как снимал логи с тестового симулятора
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегия логирования тестового симулятора
Логирование тестового симулятора — критически важная практика для анализа поведения системы, воспроизведения дефектов и аудита тестовых прогонов. Подход зависит от архитектуры симулятора (интегрированный в приложение, внешний сервис, эмулятор устройства) и его назначения (симуляция сетевых сбоев, данных, аппаратуры).
Основные источники логов в тестовом симуляторе
- Логи самого симулятора: Сообщения о его старте/остановке, конфигурации, состоянии, ошибках внутренней логики.
- Логи взаимодействия: Запросы/ответы между тестируемым приложением и симулятором (например, HTTP, gRPC, WebSocket).
- Логи тестового фреймворка: Сообщения от тест-раннера (JUnit, pytest, TestNG), которые могут содержать ID теста, этапы и результаты.
- Системные логи: При использовании контейнеров (Docker) или оркестраторов (Kubernetes) — логи stdout/stderr контейнера с симулятором.
Практические методы сбора логов
Я комбинирую несколько методов для создания полной картины.
1. Интеграция с фреймворком логирования
Самый надёжный способ — внедрить в код симулятора библиотеку логирования (Log4j2, Logback для Java, loguru или structlog для Python, Winston для Node.js). Это позволяет управлять уровнями логирования (DEBUG, INFO, WARN, ERROR), форматами и аппендерами (вывод в файл, консоль, syslog, Sentry).
Пример конфигурации Logback для Java-симулятора:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/simulator-${date:yyyy-MM-dd}.log</file>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} [Test: %X{testId}] - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} %-5level %logger{20} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Ключевой приём — использование Mapped Diagnostic Context (MDC) для автоматического добавления в каждую запись идентификатора теста (testId), что позволяет потом легко фильтровать логи по конкретному тест-кейсу.
2. Перехват трафика (для симуляторов-серверов)
Для симуляторов, выступающих в роли сервера (мок API, имитатор бэкенда), необходимо логировать весь входящий и исходящий трафик.
- HTTP: Использовать фильтры/интерсепторы (в Spring —
HandlerInterceptor, в Express.js — middleware). - Базы данных: Логировать SQL-запросы через настройки драйвера (например,
log4jdbcдля JDBC).
Пример логирующего интерсептора на Python (FastAPI):
import logging
from fastapi import Request
import uuid
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("simulator")
@app.middleware("http")
async def log_requests(request: Request, call_next):
test_id = request.headers.get("X-Test-ID", str(uuid.uuid4()))
request_id = str(uuid.uuid4())
logger.info(f"Request started | test_id={test_id} | request_id={request_id} | "
f"method={request.method} | url={request.url}")
response = await call_next(request)
logger.info(f"Request completed | test_id={test_id} | request_id={request_id} | "
f"status_code={response.status_code}")
return response
3. Сбор через контейнеризацию и оркестрацию
Если симулятор запущен в Docker-контейнере, логи по умолчанию попадают в stdout/stderr. Их можно собрать с помощью драйверов логирования Docker (json-file, journald, syslog) или отправлять напрямую в централизованную систему (например, ELK Stack или Loki).
Пример Docker Compose с перенаправлением логов:
version: '3.8'
services:
test-simulator:
image: my-simulator:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
environment:
- LOG_LEVEL=DEBUG
4. Связывание логов с тест-кейсом
Это самый важный аспект. Каждый запуск симулятора в контексте теста должен иметь уникальный идентификатор, который передаётся:
- Через заголовки HTTP (
X-Test-ID). - Через переменные окружения.
- Через глобальный контекст (тот же MDC в логгере).
Это позволяет в системах типа Kibana или Grafana выполнить запрос вида test_id: "test_login_001" и получить ВСЕ логи, относящиеся только к этому прогону: сообщения симулятора, HTTP-запросы, ответы, ошибки.
5. Автоматизация в CI/CD пайплайне
В Jenkins, GitLab CI или GitHub Actions процесс выглядит так:
- Перед прогоном тестов: Запускается симулятор, его логи начинают писаться в файл или отправляться в централизованный лог-сервис.
- Во время тестов: Каждый тест передаёт в симулятор свой уникальный
correlation_id. - После прогона (успешного или падения):
* Логи симулятора за последний прогон автоматически прикрепляются к артефактам сборки.
* В случае падения теста — логи анализируются, и ключевые ошибки выводятся в отчёт.
* Все логи сохраняются с привязкой к номеру сборки.
Резюме и лучшие практики
- Используйте структурированное логирование (JSON), а не plain text. Это упрощает парсинг и интеграцию.
- Внедряйте correlation id (testId) на самом старте теста и пробрасывайте его через все слои.
- Настройте разные уровни детализации: DEBUG — для отладки на dev-стенде, INFO — для CI, WARN/ERROR — для продакшена.
- Не логируйте конфиденциальные данные (пароли, токены, персональные данные). Используйте маскировку.
- Реализуйте ротацию лог-файлов, чтобы они не заполнили диск.
- Интегрируйте с алертингом: Критические ошибки симулятора (например, отказ запуска) должны сразу уходить в чат-оповещения (Telegram, Slack).
Такой комплексный подход превращает логи из бесполезного текстового мусора в мощный инструмент анализа, который позволяет за минуты локализовать причину даже самого сложного бага, воспроизвести сценарий и доказать разработчику, где именно система ведёт себя не так, как ожидалось.