QA Interview Hub · База знань · Тести

Логи й observability

Інструменти й запити

ELK / OpenSearch і Kibana: KQL

ELK (Elastic Stack) — Elasticsearch (сховок і пошук), Logstash або легші Beats/Elastic Agent (збір і обробка), Kibana (інтерфейс). OpenSearch — форк з аналогом Dashboards. Логи індексуються за часом (індекси чи data streams), тому в Kibana завжди обирають часовий діапазон і data view.

Основна мова пошуку в Kibana Discover — KQL (Kibana Query Language):

log.level: "error" and service.name: "checkout"
log.level: "error" and not message: "healthcheck"
http.response.status_code >= 500
trace.id: "4bf92f3577b34da6a3ce929d0e0e4736"
user.email: *@example.com and event.action: "login"

Правила: поле: значення, оператори and, or, not, дужки для групування, порівняння >, >= для чисел і дат, шаблон *, значення з пробілами беруть у лапки. Назви полів залежать від схеми (часто Elastic Common Schema: log.level, service.name, trace.id).

Типовий робочий процес QA в Kibana:

  1. обрати часове вікно навколо відтворення бага;
  2. звузити за сервісом/оточенням, потім за рівнем ERROR;
  3. або одразу шукати за trace.id/request id з відповіді;
  4. додати колонки (поля) в таблицю, відсортувати за часом, відкрити документ і прочитати стек;
  5. зберегти пошук чи зробити візуалізацію (кількість помилок за часом) для звіту.

Окрім KQL, є Lucene-синтаксис і ES|QL (конвеєрна мова запитів Elastic); у співбесіді достатньо розуміти фільтр за полями, часом і trace id.

Grafana Loki, LogQL, Datadog і Sentry

Grafana Loki — система логів, яка індексує лише мітки (labels) потоку (сервіс, оточення, pod), а не повний текст; решту фільтрують під час запиту. Запити пишуть мовою LogQL у Grafana (Explore). Запит починається з селектора потоку у фігурних дужках, далі йдуть фільтри:

{app="checkout", env="staging"} |= "timeout"
{app="checkout"} |= "error" != "healthcheck"
{app="checkout"} |~ "order (8841|8842)"
{app="checkout"} | json | level="error" | durationMs > 1000
sum by (app) (count_over_time({env="staging"} |= "error" [5m]))
  • |= містить рядок, != не містить, |~ збігається з regex, !~ не збігається;
  • | json (або | logfmt) розбирає рядок і створює мітки з полів, які далі фільтрують (level="error");
  • метричні запити (count_over_time, rate) перетворюють логи на ряд для графіка чи алерта; діапазон задають у квадратних дужках.

Datadog — SaaS для логів, метрик і APM-трейсів в одному місці; за відповідного налаштування логи пов’язуються з трейсами (поля dd.trace_id, dd.span_id), тому з трейса одним кліком переходять до його логів.

Sentry — трекер помилок: збирає винятки (фронтенд і бекенд), групує їх у issues за стеком, показує breadcrumbs (що відбувалось перед помилкою), оточення та версію release. Для QA корисно: побачити, чи нова помилка з’явилась саме в цьому релізі, скільки користувачів зачеплено, і чи вона регресує після «виправлення». Для читабельних стеків фронтенду завантажують source maps.

Вибір інструмента залежить від компанії; важливо вміти сформулювати загальну послідовність: час → сервіс/оточення → рівень → ідентифікатор запиту → першопричина.

Командний рядок: docker logs, kubectl logs, grep, jq

Навіть коли є Kibana чи Grafana, логи локального оточення й CI читають у терміналі.

Docker:

docker logs -f --tail 100 api            # стежити, останні 100 рядків
docker logs --since 10m api              # за останні 10 хвилин
docker compose logs -f --tail=50 api db  # кілька сервісів compose
docker compose logs --no-color --timestamps > compose.log

Kubernetes:

kubectl logs deploy/checkout --since=15m
kubectl logs -f pod/checkout-7d9f -c app      # конкретний контейнер
kubectl logs pod/checkout-7d9f --previous     # контейнер, що впав і перезапустився
kubectl logs -l app=checkout --tail=100 --prefix   # за міткою, з іменами pod

--previous — те, що люблять питати: якщо pod у CrashLoopBackOff, поточний контейнер ще порожній, причину падіння дивляться в логах попереднього.

Файли й текст:

tail -f app.log | grep --line-buffered ERROR   # живий потік помилок
grep -n -C 3 "orderId=8841" app.log            # 3 рядки контексту навколо
grep -c "ERROR" app.log                        # кількість
zgrep "timeout" app.log.2026-10-11.gz          # у стисненому архіві

JSON-логи через jq:

jq -c 'select(.level=="error")' app.log
jq -r 'select(.traceId=="4bf92f35...") | [.ts,.service,.msg] | @tsv' app.log
jq -s 'group_by(.error) | map({error: .[0].error, n: length})' app.log

У PowerShell аналог grep — Select-String, а tail -f — Get-Content -Wait -Tail 50.