Прямой ответ
Централизованная агрегация логов нужна, когда сервисов больше одного: «ssh на каждый сервер и grep» не масштабируется и не переживает пересоздание контейнеров (логи умирают вместе с ними). Выбор стека в 2026 чаще всего упирается в пару: Loki (Grafana-стек: индексируются только метки, текст сжимается как есть — дёшево и быстро в эксплуатации, запросы LogQL «grep-подобные») против EFK/Elastic (полнотекстовый индекс каждого поля — мощные поиск и аналитика, цена — ресурсы и сложность кластера). Практическое правило: если команда уже живёт в Prometheus/Grafana и объём логов измеряется десятками гигабайт в день — Loki закрывает потребности за долю ресурсов EFK; Elastic оправдан, когда по логам строится продуктовая аналитика и полнотекстовый поиск по произвольным полям — ежедневная задача. И независимо от стека: агрегация окупается только при структурированных логах (формат — в отдельной статье) — JSON-строка с уровнями и request_id превращает поиск из археологии в запрос.
Loki: как устроен и почему дешёвый
Архитектурная идея Loki: индексируются метки (labels: сервис, окружение, инстанс, уровень), а сам текст логов сжимается в объектном хранилище (S3/файлы) — как Prometheus для метрик, только для строк. Компоненты минимальны: агент на хосте (Promtail/Alloy — читает journal/docker-логи/файлы, добавляет метки, шлёт в Loki), сам Loki (приём, хранение, запросы), чтение — через Grafana (Explore/панели) или API. Следствия выбора: хранение дёшево (S3, недели-месяцы ретеншена без разорения), запуск — один бинарник + агент (docker-compose из трёх сервисов для старта), но «найди все логи, где поле user_id=42» без метки user_id — это скан (в LogQL — фильтр по тексту, медленнее индексного поиска Elastic; проектируйте метки под частые оси поиска). Запросы LogQL: {service="api", env="prod"} |= "timeout" (метки + grep-фильтр), | json | status >= 500 (распарсить JSON-строку и фильтровать по полю), rate({service="api"} |= "error" [5m]) (частота ошибок — для панелей и алертов).
EFK: когда полнотекстовый поиск оправдан
Elasticsearch+Fluent Bit/Filebeat+Kibana: каждое поле каждой записи индексируется — поиск «user_id=42 И status>=400 И сообщение содержит X за последние три дня» выполняется мгновенно, агрегации по произвольным полям (Kibana-визуализации, дашборды по логам) — из коробки. Цена: ресурсы (индекс обычно больше исходных логов в разы; JVM-кластер с настройкой шардов/реплик/heap — отдельная профессия), эксплуатация (маппинги, rollover-политики ILM, холодные/горячие узлы), и дисциплина полей (взрыв mapping'а при динамических ключах — классическая авария Elastic). Когда это оправдано: логи — источник продуктовой аналитики (кто что искал, воронки по событиям), требования compliance к полнотекстовому аудиту, объёмы и команда, для которых кластер — штатная инфраструктура. Для «инженерных логов разработки» EFK — стрельба из пушки: Loki+Grafana закрывают 95% запросов «что случилось в сервисе за последние полчаса».
Практика запросов и расследований
Сценарий, ради которого всё строилось: пользователь сообщает об ошибке с request_id. В Loki: {service="api"} |= "req-abc123" — вся цепочка обработки запроса одной строкой (request_id проходит через сервисы — ценность, заложенная ещё на этапе структурированного логирования); дальше — расширение по времени и соседним сервисам ({env="prod"} |= "req-abc123"), фильтр по уровням (| json | level="error"). Типовые сохранённые запросы команды: ошибки по сервису за час, «что нового в логах после деплоя» (сравнение двух окон), топ исключений (| json | level="error" | line_format "{{.exc_type}}" + агрегация). Алерты по логам — точечно (Loki ruler: rate({service="api"} |= "CRITICAL" [5m]) > 0 — пейдж; «алерт на каждую ERROR-строку» — шум): логи для расследований, метрики для алертинга — разделение ролей из статьи про метрики.
Практический сценарий: стек на docker-compose
Локальный/небольшой прод-стенд за вечер. В compose: loki (конфиг с файловым хранилищем; в проде — S3-бэкенд), promtail (монтирует /var/lib/docker/containers и /var/log read-only, pipeline-конфиг: парсинг docker-json, извлечение меток service/env из путей и лейблов контейнеров), grafana (datasource Loki provisioning-конфигом — из мониторинг-стека, там же Prometheus — логи и метрики в одном UI с переходами по времени). Приложения пишут JSON в stdout (никаких файлов — docker-драйвер перехватывает; ротация — настройками logging-драйвера max-size/max-file, иначе диск съедается незаметно). Проверка: ошибка в тестовом эндпоинте → Grafana Explore → {service="api"} |= "error" — строка найдена за секунды; панель «ошибки по сервисам» на общем дашборде (дашборды). Ретеншен: 30 дней в конфиге Loki; чувствительные поля (email, токены) вымарываются на этапе логирования, а не «потом в хранилище» — попавшее в агрегатор не удаляется бесследно.
FAQ
Можно ли вообще без агрегатора?
До двух-трёх сервисов — да: journalctl/docker logs + ssh (или docker compose logs) покрывают нужды. Агрегатор окупается, когда расследование требует логов нескольких сервисов за одно окно времени или контейнеры эфемерны.
Loki заменит ELK для security-аудита? Частично: хранение и поиск по меткам/тексту — да; аналитика по произвольным полям и зрелые SIEM-интеграции — территория Elastic. Гибрид (Loki для инженерных логов, Elastic для аудита) — частая рабочая схема.
Какой ретеншен держать? Инженерные логи — 2–4 недели горячего поиска достаточно (90% запросов — «за сегодня»); месяцы-годы — только для аудита/compliance, в дешёвом холодном хранилище. Логи без ретеншена — гарантированный инцидент с диском.
Promtail или Grafana Alloy? Alloy — преемник Promtail в экосистеме Grafana (единый агент для метрик/логов/трейсов); новые установки разумно начинать с Alloy, работающий Promtail срочной миграции не требует.
Источники: документация Loki (обзор, LogQL), Elasticsearch reference — ссылки в шапке.