Урок по треку Наблюдаемость и SRE 7 мин

Логи, Loki и ELK за 7 минут

Структурные логи, уровни, корреляция, Loki и LogQL, Elasticsearch и OpenSearch, хранение, стоимость и персональные данные.

Логи отвечают на вопрос «что именно произошло с этим запросом». Чтобы они помогали, а не просто занимали диск, их пишут структурно, связывают с трейсами и хранят ровно столько, сколько нужно.

Структурные логи

Строка ERROR failed to charge card for user 42 удобна человеку, но её трудно фильтровать. Структурный лог в JSON:

{"ts":"2026-10-15T10:01:02.345Z","level":"error","service":"billing","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","user_id":42,"msg":"charge failed","error":"card declined","duration_ms":312}

Теперь можно найти все ошибки сервиса, все события одного пользователя или запроса, посчитать среднее duration_ms.

Правила:

  • Одно событие, одна строка (многострочные стектрейсы сериализуют в поле).
  • Постоянные поля: время в UTC с миллисекундами, уровень, сервис, версия, окружение, trace_id.
  • Сообщение msg постоянное, детали в отдельных полях: не "user 42 not found", а "msg":"user not found","user_id":42. Тогда события группируются.
  • В контейнерах писать в stdout, сбор и доставку делает агент.

Уровни

  • ERROR: что-то не сделано и требует внимания.
  • WARN: необычное, но обработанное (повтор удался, деградация).
  • INFO: значимые бизнес-события и жизненный цикл (старт, конфиг, завершение задачи).
  • DEBUG: детали для отладки, в проде выключен или включается точечно.

Ошибка, которую обработали и вернули клиенту 404, обычно не ERROR. Если ERROR сыпется тысячами в норме, им перестают верить.

Корреляция

trace_id (или request_id) в каждой строке связывает логи одного запроса во всех сервисах. OpenTelemetry SDK кладёт идентификаторы трейса в контекст логгера автоматически. В Grafana из строки лога можно перейти к трейсу, а из трейса к его логам.

Доставка

Агент на узле читает stdout контейнеров или файлы и отправляет в хранилище: Fluent Bit, Vector, Grafana Alloy, Promtail (устарел, его заменяет Alloy), Filebeat, OpenTelemetry Collector. Агент буферизует при недоступности хранилища, добавляет метки (namespace, pod, node) и может отбрасывать мусор.

Loki

Loki индексирует только метки потока ({app="api", env="prod", namespace="billing"}), а содержимое строк хранит сжатыми кусками в объектном хранилище. Поэтому он дешёв и прост, но полнотекстовый поиск по большому периоду медленнее, чем в Elasticsearch.

LogQL:

{app="api", env="prod"} |= "error"                         # строки с подстрокой
{app="api"} | json | status >= 500 | line_format "{{.msg}}" # разобрать JSON и фильтровать по полю
sum by (app) (rate({env="prod"} |= "panic" [5m]))          # метрика из логов
count_over_time({app="api"} | json | level="error" [1h])

Главное правило Loki: метки должны иметь низкую кардинальность. user_id или trace_id в метках создают миллионы потоков и убивают Loki. Такие значения остаются в теле строки и ищутся фильтрами.

Elasticsearch и OpenSearch (ELK)

Классический стек: Elasticsearch (хранилище с полнотекстовым инвертированным индексом), Logstash или Beats для сбора и обработки, Kibana для поиска. OpenSearch это открытый форк Elasticsearch и Kibana, который ведёт AWS и сообщество.

Плюсы: быстрый полнотекстовый поиск и сложная аналитика по полям. Минусы: индексирование всего дорого по CPU, памяти и диску, кластер требует внимания (шарды, реплики, mapping, переполнение полей). Для управления жизненным циклом используют ILM (горячие, тёплые, холодные узлы и удаление по сроку).

Ещё вариант для больших объёмов: ClickHouse как хранилище логов, часто в РФ.

Хранение и стоимость

  • Разный ретеншн: DEBUG и access-логи дни, бизнес-события и аудит месяцы и годы, часто в отдельном хранилище.
  • Сэмплирование однотипных событий (каждый сотый успешный запрос, но все ошибки).
  • Мусор отбрасывать на агенте: health-check запросы, шумные библиотеки.
  • Логи не заменяют метрики: считать RPS по логам дорого. Метрики из логов уместны для редких событий.

Персональные данные

Логи с телефонами, паспортами, токенами и номерами карт превращают хранилище логов в базу персональных данных со всеми требованиями 152-ФЗ, а утечка логов становится утечкой ПД. Маскируйте на стороне приложения (или на агенте), не логируйте тела запросов целиком, токены и пароли никогда.

Частые ошибки

  • Текстовые логи без структуры, разный формат в каждом сервисе.
  • Нет trace_id: невозможно собрать картину запроса.
  • trace_id или ID пользователя в метках Loki.
  • ERROR на каждую ожидаемую ситуацию.
  • Пароли и персональные данные в логах.

Что спросят на собесе

  • Зачем структурные логи и какие поля обязательны.
  • Чем Loki отличается от Elasticsearch и когда что выбрать.
  • Как связать логи разных сервисов одного запроса.
  • Как снизить стоимость логов.
  • Что нельзя писать в логи.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.