Реализовать автоматический postmortem
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать автоматический postmortem
1. Цель задачи
Разработать систему, которая после фиксации инцидента автоматически собирает логи, метрики и трейсы из целевых сервисов и формирует структурированный postmortem-отчёт в течение 5 минут. Система должна интегрироваться с существующим стеком observability (Elasticsearch, Prometheus, Jaeger) и запускаться по триггеру (вебхук, команда в чате или UI). Ключевой результат Отчёт в формате Markdown/HTML доступен для команды не позднее 5 минут после закрытия инцидента.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Время начала и окончания инцидента | Система алертинга (Alertmanager), PagerDuty или ручной ввод |
| Логи всех затронутых сервисов за период инцидента | Elasticsearch (или Loki) – индексы/метки сервисов |
| Метрики (CPU, память, RPS, ошибки) за период +/- 5 минут | Prometheus – query_range API |
| Трейсы (trace_id, duration, статус) для request-ов упавших/медленных | Jaeger (или Tempo) – поиск по сервису и временному окну |
| Список затронутых сервисов | Из алерта или меток логирования |
| Конфигурация postmortem-шаблона | Git-репозиторий (шаблон в формате Jinja2) |
Если нет реального инструмента — симулируем:
- Развернуть Docker Compose с elasticsearch:7.17, logstash, kibana, filebeat (или Loki + Promtail).
- Развернуть prometheus и node_exporter для метрик; добавить несколько тестовых меток (service="api-gateway", service="user-service").
- Развернуть jaeger all-in-one и эмитировать трейсы простым Python-скриптом (opentelemetry-sdk).
- Написать скрипт-генератор инцидента, который на заданный интервал создаёт аномалии в логах/метриках/трейсах.
- Использовать requests и curl для имитации запросов от Alertmanager.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Оркестрация инфраструктуры | Docker Compose | Локальный подъём стека observability |
| Хранение логов | Elasticsearch (Loki) | Агрегация и поиск логов за период инцидента |
| Хранение метрик | Prometheus | Сбор и запрос метрик (RPS, ошибки, ресурсы) |
| Хранение трейсов | Jaeger | Поиск трейсов по сервису и времени |
| Язык скрипта-агрегатора | Python 3.10+ | Запросы к API, парсинг, генерация отчёта |
| Шаблонизация | Jinja2 / Markdown | Постмортем-шаблон с подстановкой данных |
| Хранилище отчётов | Git-репозиторий / MinIO / веб-сервер | Версионирование и доступ к отчётам |
| CI / Автоматизация | GitLab CI (GitHub Actions) или cron | Триггер генерации после инцидента |
| Мониторинг процесса | Prometheus Blackbox Exporter | Healthcheck системы постмортема |
4. Этапы выполнения
Этап 1: Развёртывание инфраструктуры сбора данных (2 часа)
Действия
- Подготовить docker-compose.yml для стека: elasticsearch, logstash, kibana, filebeat, prometheus, node_exporter,
jaeger-all-in-one. - Настроить Filebeat для отправки тестовых логов (например, из /var/log/test-app/*.log) в Logstash/Elasticsearch.
- Настроить Prometheus для сбора метрик с node_exporter и добавить несколько scrape_configs для тестовых сервисов (например, service: 'api-gw', service: 'user-svc').
- Запустить Jaeger и проверить приём трейсов через Python-скрипт:
from opentelemetry import trace
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
resource = Resource(attributes={SERVICE_NAME: "api-gateway"})
provider = TracerProvider(resource=resource)
jaeger_exporter = JaegerExporter(
agent_host_name="localhost", agent_port=6831
)
provider.add_span_processor(BatchSpanProcessor(jaeger_exporter))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("test-request") as span:
span.set_attribute("http.status_code", 200)
- Сгенерировать тестовые данные (набор логов с уровнями ERROR, метрики с повышением CPU, трейсы с задержками).
Ожидаемый результат этапа Все три хранилища (логи, метрики, трейсы) работают, тестовые данные визуализируются в Kibana/Grafana/Jaeger UI.
Этап 2: Написание скрипта-агрегатора (3 часа)
Действия
- Создать Python-модуль
postmortem_collector.pyс функциями:- get_logs(service, start_ts, end_ts) – запрос к Elasticsearch (или Loki) через HTTP/REST. Пример:
import requests def get_logs(service, start, end): body = { "query": { "bool": { "must": [{"match": {"service": service}}], "filter": [{"range": {"@timestamp": {"gte": start, "lt": end}}}] } }, "size": 1000 } resp = requests.post("http://localhost:9200/logs-*/_search", json=body) return resp.json()["hits"]["hits"]- get_metrics(service, metric_names, start, end) – вызов prometheus.query_range (PromQL). Пример:
import requests def get_metrics(service, metric_names, start, end): results = {} for metric in metric_names: query = f'{metric}{{service="{service}"}}' resp = requests.get("http://localhost:9090/api/v1/query_range", params={"query": query, "start": start.isoformat(), "end": end.isoformat(), "step": "15s"}) results[metric] = resp.json()["data"]["result"] return results - Реализовать параллельное выполнение запросов через asyncio или ThreadPoolExecutor для ускорения (цель <5 мин).
- Обработать ошибки (timeout, недоступность) – логировать и вставлять заглушки.
Ожидаемый результат этапа Скрипт собирает все три типа данных за заданный интервал и возвращает структурированные словари (лог-записи, метрики с временными рядами, трейсы).
Этап 3: Генерация отчёта по шаблону (1 час)
Действия
- Подготовить шаблон отчёта
postmortem_template.md.j2в формате Jinja2. Разделы: Сводка, Временная шкала, Затронутые сервисы, Метрики (графики), Ключевые логи (ERROR), Трейсы (slow/error), Причина (root cause), Рекомендации. - Написать функцию
render_report(data, template_path):
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates'))
template = env.get_template('postmortem_template.md.j2')
report_md = template.render(
start_time=data['start'].isoformat(),
end_time=data['end'].isoformat(),
services=data['services'],
log_count=len(data['logs']),
metrics=data['metrics'],
traces=data['traces']
)
- Сохранить отчёт в папку reports/incident_{id}_{timestamp}.md. Дополнительно конвертировать в HTML (с графиками) с помощью
markdown2+ base64 графиков.
Ожидаемый результат этапа При запуске скрипта с тестовыми данными формируется читаемый отчёт.
Этап 4: Автоматизация и триггер (1.5 часа)
Действия
{
"incident_id": "INC-123",
"start_ts": "2025-02-01T10:30:00Z",
"end_ts": "2025-02-01T11:00:00Z",
"services": ["api-gateway", "user-service"]
}
Эндпоинт запускает сборщик и возвращает 202 Accepted, а после генерации сохраняет отчёт и отправляет ссылку в Slack (опционально).
2. Настроить периодический run через cron (если нет системы инцидентов) – скрипт читает последний закрытый алерт из Alertmanager.
3. Добавить healthcheck /health и метрики (Prometheus client) для наблюдения за временем генерации.
Ожидаемый результат этапа Отчёт генерируется по вызову API; время выполнения <5 мин.
Этап 5: Тестирование и документирование (1.5 часа)
Действия
- Написать unit-тесты для каждой функции сбора данных (моки API через
responsesилиrequests-mock). - Провести интеграционное тестирование: запустить полный цикл с симулированным инцидентом.
- Замерить время генерации (strace,
time). Оптимизировать при необходимости (например, агрессивное кэширование метрик). - Документировать README: как запустить стенд, как добавить новый сервис, как вызвать генерацию.
Ожидаемый результат этапа Все тесты проходят, документация готова, время генерации укладывается в 5 минут.
5. Критерии приемки (Definition of Done)
- Отчёт формируется и доступен не позднее 5 минут после триггера (измеряется Prometheus histogram).
- Отчёт содержит: уникальный ID инцидента, временные метки, список сервисов, графики метрик (CPU, RPS, ошибки), топ-10 ошибок логов, трейсы с длительностью > p95, вывод о root cause, рекомендации.
- Система обрабатывает случай, когда часть источников недоступна (без падения, с пометкой).
- Реализовано не менее одного автоматического триггера (API или webhook).
- Код размещён в Git-репозитории с CI-проверкой (линтер, тесты).
- README содержит инструкцию по локальному запуску и добавлению нового сервиса.
- Тесты покрывают >70% кода агрегатора и шаблонизатора.
6. Ожидаемый результат
- Основной артефакт Скрипт
postmortem_generator.pyи FastAPI-приложениеapp.py, которые генерируют отчёт в формате Markdown/HTML. - Содержание отчёта Сводка инцидента, временная шкала, метрики (встроенные ASCII-графики или base64 png), выдержки логов с указанием ошибок, список трейсов-кандидатов, гипотезы причины и рекомендации.
- Дополнительные результаты Docker Compose-стенд для разработки, CI-пайплайн в
.gitlab-ci.yml, Slack-интеграция (опционально).
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Нет реальных инцидентов для тестирования | Использовать скрипт-симулятор инцидента, создающий аномалии в реальном времени |
| Разные форматы данных от Elasticsearch и Loki | Абстрагировать слой доступа через единый интерфейс (ABC), реализовать два класса-провайдера |
| Высокая загрузка API при сборе данных | Использовать параллельные запросы (concurrent.futures), ставить таймауты 10 сек на каждый вызов |
| Графики метрик в Markdown сложно отобразить | Генерировать base64 PNG с помощью matplotlib или вставлять ссылки на Grafana iframe |
| Задержки трейсов при поиске по большому окну | Разбивать окно на части (2-минутные слоты) и объединять результаты |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| Этап 1: Развёртывание инфраструктуры | 2 |
| Этап 2: Сборщик данных | 3 |
| Этап 3: Генерация отчёта | 1 |
| Этап 4: Автоматизация | 1.5 |
| Этап 5: Тестирование и документация | 1.5 |
| Итого | 9 часов |
| Примечание: для первого раза заложите дополнительно 2 часа на отладку интеграции. |
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Как настроить централизованное логирование (ELK/Loki) |
| 34 | Автоматическое уведомление об инцидентах через Webhook |
| 56 | Анализ метрик Prometheus с помощью PromQL |
| 78 | Интеграция Jaeger в микросервисную архитектуру |
| 101 | Шаблоны postmortem-отчётов и их автоматизация |
| 145 | Оптимизация времени ответа API при параллельных запросах |
| 203 | CI/CD пайплайн для Python-приложений |
| 267 | Мониторинг времени генерации отчётов с помощью Prometheus |
| 312 | Тестирование интеграций с моками внешних сервисов |
| 401 | Управление конфигурацией через GitOps |
10. Чек-лист самопроверки
- Я запустил скрипт с тестовыми данными и убедился, что отчёт сформирован за <5 минут.
- Я проверил, что отчёт содержит логи, метрики и трейсы за правильный интервал.
- Я протестировал случай, когда один из источников (например, Jaeger) недоступен – отчёт не упал, а указал отсутствие данных.
- Я добавил в README инструкцию по регистрации нового сервиса (добавление scrape config и индекса).
- Я запустил
pytestи убедился, что покрытие >70%, а интеграционные тесты проходят.