Наблюдаемость и мониторинг стали необходимыми компетенциями для QA-инженеров по мере перехода систем к распределённым микросервисным архитектурам. По данным отчёта Dynatrace 2023, 85% организаций столкнулись со сбоем цифровых сервисов за прошлый год, при этом среднее время обнаружения (MTTD) превышало 70 минут в организациях без зрелых практик наблюдаемости. По данным DORA State of DevOps, высокопроизводительные команды восстанавливают сервисы в 100 раз быстрее — и наблюдаемость является ключевым отличительным фактором. Для QA-инженеров это означает переход от реактивного обнаружения багов к проактивному измерению качества.
TL;DR: Наблюдаемость QA охватывает три столпа: метрики (SLI, SLO, частота ошибок), логи (структурированное логирование, correlation ID) и трассировки (распределённая трассировка с OpenTelemetry). Используй Grafana + Prometheus для метрик, Jaeger для трассировки и определяй SLO качества.
Понимание Мониторинга vs. Observability
Хотя часто используются взаимозаменяемо, мониторинг и observability служат разным целям:
Мониторинг
Определение: Сбор, агрегация и анализ предопределенных метрик для обнаружения известных проблем.
Характеристики:
- Отвечает на известные вопросы: “Система работает?” “Использование CPU выше 80%?”
- Реактивный подход: Алерты срабатывают при превышении порогов
- Фокусируется на здоровье и доступности системы
- Работает с предопределенными дашбордами и алертами
Пример: Алерт, когда время ответа API превышает 500мс в течение 5 последовательных минут.
Observability
Определение: Понимание внутреннего состояния системы на основе внешних выходов (логи, метрики, трейсы) для ответа на произвольные вопросы.
Характеристики:
- Отвечает на неизвестные вопросы: “Почему checkout падает для iOS (как обсуждается в Bug Anatomy: From Discovery to Resolution) пользователей в Европе?”
- Проактивный подход: Позволяет исследование и отладку
- Фокусируется на понимании поведения системы
- Работает с гибкими запросами и корреляцией
Пример: Расследование того, почему не удалась транзакция конкретного пользователя путем корреляции логов, метрик и трейсов через множество сервисов.
Три столпа Observability
- Логи: Дискретные события с таймстампами, описывающие, что произошло
- Метрики: Числовые измерения во времени, показывающие производительность системы
- Трейсы: End-to-end путь запросов через распределенные системы
“Monitoring tells you when something is wrong. Observability tells you why. QA engineers who master both can catch issues in production before customers report them — that’s a fundamentally different quality posture.” — Yuri Kan, Senior QA Lead
ELK Stack для управления логами
ELK Stack (Elasticsearch, Logstash, Kibana) предоставляет мощные возможности агрегации, поиска и визуализации логов.
Архитектура ELK Stack
Elasticsearch: Распределенный движок поиска и аналитики для хранения и запроса логов Logstash: Серверный pipeline обработки данных для приема, трансформации и отправки логов Kibana: Инструмент визуализации и исследования для данных Elasticsearch Beats (часто добавляется): Легковесные сборщики данных для пересылки логов из приложений
Настройка ELK Stack
Setup Docker Compose (docker-compose.yml):
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.10.0
container_name: elasticsearch
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- xpack.security.enabled=false
ports:
- "9200:9200"
- "9300:9300"
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
networks:
- elk
logstash:
image: docker.elastic.co/logstash/logstash:8.10.0
container_name: logstash
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "5044:5044"
networks:
- elk
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana:8.10.0
container_name: kibana
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
networks:
- elk
depends_on:
- elasticsearch
volumes:
elasticsearch-data:
networks:
elk:
driver: bridge
Конфигурация pipeline Logstash (logstash/pipeline/logstash.conf):
input {
beats {
port => 5044
}
tcp {
port => 5000
codec => json
}
}
filter {
# Парсить JSON логи
if [message] =~ /^\{.*\}$/ {
json {
source => "message"
}
}
# Извлечь уровень лога
grok {
match => {
"message" => "%{LOGLEVEL:log_level}"
}
}
# Парсить таймстамп
date {
match => [ "timestamp", "ISO8601", "yyyy-MM-dd HH:mm:ss,SSS" ]
target => "@timestamp"
}
# Фильтровать логи healthcheck
if [path] == "/health" or [url] == "/healthz" {
drop { }
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logs-%{[service][name]}-%{+YYYY.MM.dd}"
}
stdout {
codec => rubydebug
}
}
Использование Kibana для QA
Создание Index Patterns:
- Перейти в Management → Stack Management → Index Patterns
- Создать паттерн:
logs-* - Выбрать поле timestamp:
@timestamp
Построение QA-фокусированных дашбордов:
Дашборд мониторинга выполнения тестов:
{
"title": "Test Execution Monitoring",
"panels": [
{
"title": "Test Pass Rate",
"type": "metric",
"query": "service.name:test-runner AND test.status:*"
},
{
"title": "Failed Tests Over Time",
"type": "line",
"query": "test.status:failed"
},
{
"title": "Test Duration Distribution",
"type": "histogram",
"field": "test.duration"
}
]
}
Полезные примеры Kibana Query Language (KQL):
# Найти все ошибки в checkout сервисе
service.name:"checkout" AND log_level:ERROR
# Найти медленные API ответы (>1 секунды)
http.response.time_ms > 1000
# Найти неудачные попытки аутентификации
event.action:"login" AND event.outcome:"failure"
# Найти ошибки, влияющие на конкретного пользователя
user.id:"12345" AND log_level:ERROR
# Найти ошибки подключения к базе данных
message:"connection refused" OR message:"timeout"
# Найти ошибки за последние 15 минут
log_level:ERROR AND @timestamp >= now-15m
# Исключить логи healthcheck и мониторинга
NOT (url:"/health" OR url:"/metrics")
Корреляция логов для QA
Коррелировать логи через сервисы, используя trace ID:
Логирование приложения с контекстом трейса (пример Node.js):
const winston = require('winston');
const { v4: uuidv4 } = require('uuid');
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'app.log' })
]
});
// Middleware для добавления trace ID
function traceMiddleware(req, res, next) {
req.traceId = req.headers['x-trace-id'] || uuidv4();
res.setHeader('X-Trace-ID', req.traceId);
req.logger = logger.child({
traceId: req.traceId,
service: 'api-gateway',
environment: process.env.NODE_ENV
});
next();
}
// Использовать в запросах
app.use(traceMiddleware);
app.post('/checkout', async (req, res) => {
req.logger.info('Checkout initiated', {
userId: req.user.id,
cartItems: req.body.items.length
});
try {
const result = await processCheckout(req.body, req.traceId);
req.logger.info('Checkout completed', { orderId: result.orderId });
res.json(result);
} catch (error) {
req.logger.error('Checkout failed', {
error: error.message,
userId: req.user.id
});
res.status(500).json({ error: 'Checkout failed' });
}
});
Prometheus и Grafana для метрик
Prometheus собирает и хранит метрики как данные временных рядов, в то время как Grafana предоставляет визуализацию и алерты.
Архитектура Prometheus
Компоненты:
- Prometheus Server: Собирает и хранит метрики
- Exporters: Экспонируют метрики из приложений и инфраструктуры
- Pushgateway: Позволяет кратковременным задачам отправлять метрики
- Alertmanager: Обрабатывает алерты и уведомления
Настройка Prometheus
Добавление Docker Compose:
prometheus:
image: prom/prometheus:v2.47.0
container_name: prometheus
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
ports:
- "9090:9090"
networks:
- monitoring
grafana:
image: grafana/grafana:10.1.0
container_name: grafana
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus
Конфигурация Prometheus (prometheus/prometheus.yml):
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'api-gateway'
static_configs:
- targets: ['api-gateway:8080']
metrics_path: '/metrics'
- job_name: 'checkout-service'
static_configs:
- targets: ['checkout:8081']
Инструментация приложений для Prometheus
Метрики приложения Node.js (Express + prom-client):
const express = require('express');
const promClient = require('prom-client');
const app = express();
const register = new promClient.Registry();
promClient.collectDefaultMetrics({ register });
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.5, 1, 2, 5]
});
const checkoutTotal = new promClient.Counter({
name: 'checkout_total',
help: 'Total number of checkout attempts',
labelNames: ['status', 'payment_method']
});
register.registerMetric(httpRequestDuration);
register.registerMetric(checkoutTotal);
// Middleware для отслеживания запросов
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
const route = req.route ? req.route.path : req.path;
httpRequestDuration
.labels(req.method, route, res.statusCode)
.observe(duration);
});
next();
});
// Эндпоинт метрик
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
app.listen(8080);
Дашборды Grafana для QA
Полезные PromQL запросы для QA:
# Частота запросов в секунду
rate(http_requests_total[5m])
# Процент ошибок
(rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m])) * 100
# 95-й процентиль времени ответа
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# Провалившиеся checkout за последний час
increase(checkout_total{status="failure"}[1h])
# Средняя длительность checkout
rate(checkout_duration_seconds_sum[5m]) / rate(checkout_duration_seconds_count[5m])
# Процент использования памяти
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
# Использование CPU
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Distributed Tracing
Distributed tracing отслеживает запросы по мере их прохождения через микросервисы, обеспечивая end-to-end видимость.
Настройка Jaeger
Добавление Docker Compose:
jaeger:
image: jaegertracing/all-in-one:1.50
container_name: jaeger
environment:
- COLLECTOR_OTLP_ENABLED=true
ports:
- "16686:16686" # UI
- "14250:14250"
- "14268:14268"
networks:
- tracing
Инструментация Node.js с OpenTelemetry:
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const provider = new NodeTracerProvider();
const exporter = new JaegerExporter({
endpoint: 'http://jaeger:14268/api/traces',
});
provider.addSpanProcessor(new opentelemetry.tracing.SimpleSpanProcessor(exporter));
provider.register();
const tracer = provider.getTracer('checkout-service');
async function processCheckout(order) {
const span = tracer.startSpan('process_checkout');
span.setAttributes({
'order.id': order.id,
'user.id': order.userId,
});
try {
const result = await createOrder(order);
span.setStatus({ code: opentelemetry.SpanStatusCode.OK });
return result;
} catch (error) {
span.recordException(error);
throw error;
} finally {
span.end();
}
}
Synthetic Monitoring
Synthetic monitoring проактивно тестирует доступность и производительность системы с точки зрения пользователя.
Использование Prometheus Blackbox Exporter
Конфигурация (blackbox.yml):
modules:
http_2xx:
prober: http
timeout: 5s
http:
method: GET
valid_status_codes: [200]
http_post_checkout:
prober: http
timeout: 10s
http:
method: POST
headers:
Content-Type: application/json
body: '{"userId": "test", "items": [{"id": "123"}]}'
valid_status_codes: [200, 201]
Alerting для QA
Правила алертов Prometheus (alerts/qa-alerts.yml):
groups:
- name: qa_alerts
interval: 30s
rules:
- alert: HighErrorRate
expr: |
(rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m])) * 100 > 5
for: 5m
labels:
severity: critical
annotations:
summary: "Обнаружена высокая частота ошибок"
description: "Частота ошибок составляет {{ $value }}%"
- alert: SlowAPIResponse
expr: |
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2
for: 10m
labels:
severity: warning
annotations:
summary: "Время ответа API ухудшилось"
- alert: ServiceDown
expr: up{job="api-gateway"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Сервис {{ $labels.job }} недоступен"
Заключение
Мониторинг и observability — это существенные компоненты современных QA практик. Используя инструменты вроде ELK Stack для логов, Prometheus и Grafana для метрик, distributed tracing с Jaeger и synthetic monitoring, QA команды могут переключиться с реактивного обнаружения багов на проактивное обеспечение качества.
Эти инструменты позволяют QA-специалистам понимать поведение системы в продакшене, выявлять узкие места производительности, коррелировать проблемы через сервисы и обнаруживать проблемы до того, как они повлияют на пользователей.
Ключевые выводы:
- Observability расширяет QA за пределы традиционного тестирования
- Логи, метрики и трейсы обеспечивают комплексную видимость системы
- ELK Stack обеспечивает мощный поиск и анализ логов
- Prometheus и Grafana отслеживают метрики производительности во времени
- Distributed tracing раскрывает взаимодействия сервисов и узкие места
- Synthetic monitoring проактивно валидирует доступность системы
- Alerting обеспечивает быстрый ответ на проблемы качества
- Интеграция с CI/CD обеспечивает непрерывные инсайты качества
Смотрите также
- Стратегия автоматизации тестирования — построение комплексной стратегии автоматизации
- Непрерывное тестирование в DevOps — интеграция тестирования в CI/CD пайплайн
- Тестирование производительности API — нагрузочное тестирование API
- Тестирование безопасности API — защита API от уязвимостей
- Playwright Framework Guide — современный фреймворк для E2E тестирования
Официальные ресурсы
FAQ
В чём разница между мониторингом и наблюдаемостью?
Мониторинг отслеживает заранее определённые метрики и оповещает об известных условиях сбоя. Наблюдаемость — это свойство системы, позволяющее понять её внутреннее состояние по внешним выходным данным (метрики, логи, трассировки). Наблюдаемость позволяет отлаживать неизвестные сбои; мониторинг обрабатывает известные.
Что такое SLI и SLO?
SLI (Service Level Indicator) — измеримая метрика поведения сервиса: процент доступности, перцентиль задержки, частота ошибок. SLO (Service Level Objective) — целевое значение для SLI. QA-инженеры используют SLO для определения критериев приёмки тестов и порогов алертинга.
Как OpenTelemetry помогает QA-инженерам?
OpenTelemetry предоставляет независимую от вендора инструментацию для распределённой трассировки. QA-инженеры используют трассировки для понимания того, какие сервисы вызывались при сбое теста, измерения задержки между сервисами и проверки того, что тестовые сценарии охватывают ожидаемые пути кода.
Какие метрики должны мониторить QA-инженеры?
Ключевые метрики качества: частота ошибок (цель < 0,1%), задержка p50/p95/p99, доступность, пропускная способность, время запроса к базе данных, процент попаданий в кэш и метрики, ориентированные на пользователя (время загрузки страницы, Core Web Vitals).
See Also
- Azure DevOps Pipelines для QA: Полное Руководство по Реализации - Освойте Azure DevOps Pipelines для QA команд: YAML pipelines,…
- Обнаружение дрифта в инфраструктуре: Полное руководство по управлению состоянием IaC - Освойте обнаружение дрифта инфраструктуры с Terraform, AWS Config…
- Тестирование и безопасность Docker-образов: Полное руководство по сканированию уязвимостей контейнеров - Освойте безопасность Docker-образов с Trivy, Snyk и Grype….
- Тестирование оценки затрат для Infrastructure as Code: Полное руководство - Освойте тестирование оценки затрат для IaC с Infracost, анализом…
