Налаштування логування бекенду мобільного додатка ELK Stack
Уявіть: бекенд мобільного додатка генерує десятки тисяч рядків логів на хвилину на кількох серверах. Помилка в production — ви через ssh перебираєте grep-запити годинами. ELK Stack (Elasticsearch, Logstash, Kibana) перетворює цей хаос на централізований пошук з фільтрами за секунди. Ми інтегрували таке рішення для 40+ проектів, від стартапів до enterprise, і скоротили час діагностики в 10 разів. Нижче — як це працює.
Чому варто налаштувати ELK стек для логування бекенду мобільного додатка?
Тому що економія часу та ресурсів очевидна. На одному з проектів (геймінг, 5 млн користувачів) ми знизили витрати на інфраструктуру на 30% і прискорили пошук помилок з годин до секунд. Розробники перестали колупатися в логах вручну — дашборди Kibana відображають error rate в real-time, а алерти приходять у Telegram при перевищенні порогу. Проект окупається за 2 місяці за рахунок скорочення часу інцидентів.
Що саме налаштовуємо
Стек збору логів складається з трьох частин: структуроване логування на рівні додатка, агент для збору та відправки (Fluent Bit або Logstash), сховище з пошуковим двигуном Elasticsearch та UI Kibana.
Структуровані логи
Додаток має писати логи в JSON — не в plain text. Рядок виду [ERROR] Jan 15 14:23:11 UserService: null pointer — сміття для Elasticsearch. JSON-лог — дані, які можна парсити та фільтрувати:
import structlog
logger = structlog.get_logger()
def authenticate_user(user_id: str, device_id: str):
logger.info(
"auth_attempt",
user_id=user_id,
device_id=device_id,
platform="ios",
app_version="3.2.1",
)
try:
token = auth_service.verify(user_id)
logger.info("auth_success", user_id=user_id, token_expires_in=3600)
return token
except InvalidTokenError as e:
logger.warning("auth_failed", user_id=user_id, reason=str(e))
raise
import "github.com/rs/zerolog/log"
log.Error().
Str("user_id", userID).
Str("device_id", deviceID).
Str("endpoint", "/api/v1/auth").
Int("status_code", 401).
Dur("duration_ms", elapsed).
Msg("authentication failed")
Обов’язкові поля в кожному лозі: timestamp (ISO 8601), level, service, request_id (для трасування запиту через кілька сервісів), user_id (якщо застосовно). request_id — UUID, який генерується на вхідному запиті в middleware і пробрасовується у всі дочірні виклики через context.
| Поле | Тип | Опис |
|---|---|---|
| timestamp | date | ISO 8601 |
| level | keyword | error, warn, info, debug |
| service | keyword | Ім’я сервісу |
| user_id | keyword | Ідентифікатор користувача |
| request_id | keyword | UUID запиту |
| message | text | Опис події |
| duration_ms | long | Час виконання (мс) |
| status_code | integer | HTTP-статус |
Fluent Bit vs Logstash
| Параметр | Fluent Bit | Logstash |
|---|---|---|
| Споживання RAM | ~1 MB | ~500 MB |
| Конфігурація | YAML/INI | Ruby DSL |
| Запуск | DaemonSet, sidecar | DaemonSet |
| Продуктивність | 50K подій/сек на 1 vCPU | 30K подій/сек на 1 vCPU |
Fluent Bit кращий за Logstash у 500 разів за споживанням пам’яті та в 1.6 рази продуктивніший на одному vCPU. Для більшості setup’ів Fluent Bit — оптимальний вибір. Згідно з документацією Fluent Bit, споживання пам’яті не перевищує 1MB.
Приклад конфігурації Fluent Bit
[INPUT]
Name tail
Path /var/log/app/*.log
Parser json
Tag app.*
Refresh_Interval 5
[FILTER]
Name grep
Match app.*
Regex level (warn|error|fatal)
[OUTPUT]
Name es
Match app.*
Host elasticsearch
Port 9200
Index mobile-backend-logs
Type _doc
Logstash_Format On
Logstash_Prefix mobile-backend
Фільтр grep на рівні Fluent Bit знижує обсяг даних в Elasticsearch — debug-логи не потрапляють у сховище.
Переваги Fluent Bit
При типовому навантаженні мобільного бекенду (до 10M подій на добу) економія на інфраструктурі сягає 30% порівняно з Logstash. Fluent Bit легший в обслуговуванні — оновлюється через Rolling Update в Kubernetes без даунтайму.
Як захистити дані в логах від витоків
Логи містять user_id, device information, іноді фрагменти даних запитів. Ніколи не логуємо: паролі, токени в повному вигляді, номери карток, персональні дані. PII в логах — це GDPR-порушення. Маскуємо на рівні логера за допомогою простого фільтра: sensitive fields замінюються на ***. Це гарантує, що жодні конфіденційні дані не потраплять в Elasticsearch.
Elasticsearch та індекс
Для мобільного бекенду з помірним навантаженням (до 10M подій на добу) достатньо однієї ноди Elasticsearch або managed-кластера (Elastic Cloud, AWS OpenSearch). Index lifecycle management (ILM) — обов’язковий: логи старші 30 днів переводимо в cold tier або видаляємо, інакше диск закінчиться за тиждень.
{
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"user_id": { "type": "keyword" },
"request_id": { "type": "keyword" },
"message": { "type": "text" },
"duration_ms": { "type": "long" },
"status_code": { "type": "integer" }
}
}
}
Dynamic mapping — джерело проблем: Elasticsearch автоматично виведе тип поля з першого значення, і якщо status_code перший раз прийшов як рядок — всі наступні числові значення викличуть помилку мапінгу. Тому ми задаємо шаблон мапінгу заздалегідь.
Kibana: пошук та дашборди
Після налаштування збору створюємо Index Pattern у Kibana, налаштовуємо Discover для пошуку за полями, будуємо Lens-дашборди:
- Error rate по endpoint за останню годину
- Топ-10 повільних запитів (duration_ms > 1000)
- Активні користувачі за user_id у реалтаймі
- Heatmap помилок по годинах і днях
KQL (Kibana Query Language) для пошуку простіше, ніж SQL: level: error AND service: auth-service AND duration_ms > 500 — і одразу бачиш усі повільні помилки авторизації.
Logstash: випадки застосування
Logstash виправданий, якщо потрібен складний парсинг (наприклад, мультирядкові логи) або інтеграція з legacy-системами за протоколом TCP/UDP. Однак для більшості мобільних бекендів Fluent Bit покриває всі сценарії та економить ресурси.
Що входить у роботу
- Аудит поточного логування: виявлення проблем (відсутність request_id, неструктурований вивід)
- Налаштування структурованих логів у коді (JSON з обов’язковими полями)
- Розгортання EFK/ELK стеку: Docker Compose для розробки, Kubernetes Helm чарти для продакшена
- Налаштування Index Lifecycle Management (ILM) — оптимізація зберігання
- Створення дашбордів у Kibana під ваші ключові метрики
- Налаштування алертів (Kibana Watcher або Prometheus Alertmanager)
- Документація з експлуатації та навчання команди
- Підтримка протягом 1 місяця після здачі
Як ми це робимо: покроковий план
- Аналіз: вивчаємо поточну архітектуру, типи логів, рівень навантаження.
- Структурування: додаємо JSON-логер з необхідними полями.
- Розгортання агента: встановлюємо Fluent Bit через DaemonSet або sidecar-контейнер.
- Налаштування Elasticsearch: створюємо шаблон мапінгу, політики ILM.
- Kibana: налаштовуємо Index Pattern і будуємо дашборди.
- Тестування: перевіряємо збір, пошук, коректність алертів.
- Деплой: викочуємо на staging та production.
Строки
Базовий EFK-стек з Docker Compose, структуроване логування одного сервісу, базові Kibana-дашборди: від 2 до 3 днів. Production-ready setup з ILM, алертами, кількома сервісами та security: від 5 до 8 днів. Вартість розраховується індивідуально.
Оцінимо ваш проект за 1 робочий день — просто напишіть нам. У листі вкажіть поточний стек і приблизне навантаження, і ми запропонуємо оптимальне рішення. Отримайте консультацію вже сьогодні та почніть бачити всі помилки бекенду в одному вікні.







