Логи — это дневник приложения. Каждое событие: пользователь зашёл, форма отправилась, запрос к базе выполнился, ошибка произошла. Если логировать всё подряд без структуры — получится мусор. Если логировать мало — не найдёте причину проблемы.

Хорошее логирование — это не «больше логов», а «правильные логи». Структурированные, с правильными уровнями, доступные для поиска и связи с мониторингом. Разбираем, как это настроить.

Зачем это бизнесу

Проблемы случаются у всех. Разница в том, как быстро вы их найдёте. С хорошими логами — 5 минут. Без логов — день поиска причины. Логирование напрямую влияет на стоимость поддержки.

1. Уровни логирования

Каждое сообщение имеет уровень важности. Это позволяет фильтровать: на продакшене — только WARN и выше, при отладке — всё до DEBUG.

  • DEBUG. Детали для разработки: «получен параметр X = 5», «выполнен запрос к БД за 12 мс». На продакшене почти всегда выключен — слишком много данных.
  • INFO. Обычные события: «пользователь вошёл», «заказ оформлен», «письмо отправлено». Помогают восстановить ход событий.
  • WARN. Что-то подозрительное, но не сломалось: «внешний API ответил за 4 секунды» (медленно), «пользователь ввёл невалидный email». Обратить внимание.
  • ERROR. Что-то сломалось: «не удалось сохранить заказ», «упал запрос к платежному API». Требует реакции, но приложение продолжает работать.
  • FATAL. Критическая ошибка, приложение падает. Максимальный приоритет, требует немедленного вмешательства.
Главное правило: ERROR должен означать «человек должен посмотреть». Если у вас 100 ERROR в час, но никто на них не реагирует — они не работают. Лучше 1 ERROR, который действительно значит «срочно», чем 100 «на всякий случай».

2. Structured logging: логи как данные

Классические логи — это строки текста. Их легко читать человеку, но тяжело парсить машине. Если вы хотите искать «все ошибки от пользователя с id=42 за последний час» — со строками это ад.

Structured logging — запись логов в формате JSON. Каждое поле — отдельный атрибут. Можно фильтровать, группировать, строить графики.

Плохо (просто строка):

[2026-09-24 14:32:18] ERROR: Could not process order for user 42. Amount was 5000, but payment failed with code 'insufficient_funds'

Хорошо (structured):

{
  "timestamp": "2026-09-24T14:32:18.421Z",
  "level": "error",
  "event": "order_payment_failed",
  "user_id": 42,
  "order_id": "ORD-7891",
  "amount": 5000,
  "currency": "RUB",
  "payment_error": "insufficient_funds",
  "service": "orders",
  "version": "1.4.2"
}

Из этой записи можно делать запросы: «показать все ошибки с payment_error=insufficient_funds», «сколько заказов упало из-за оплаты за неделю», «какая версия сервиса даёт больше всего ошибок». Со строками — всё это невозможно без регулярных выражений.

Как выглядит в коде (Rust):

use tracing::{error, info, warn};

info!(
    user_id = 42,
    order_id = "ORD-7891",
    amount = 5000,
    "user_created_order"
);

error!(
    user_id = 42,
    order_id = "ORD-7891",
    payment_error = "insufficient_funds",
    "order_payment_failed"
);

Библиотеки structured logging есть в каждом языке: tracing в Rust, structlog в Python, pino в Node.js, monolog в PHP. Они делают одно и то же — превращают логи в структурированные события.

3. Куда писать логи

Есть несколько мест, куда могут идти логи. Каждое подходит для своего сценария.

  • Файл. Классика. Пишется в /var/log/app/app.log. Удобно смотреть через tail, grep, но плохо масштабируется — на нескольких серверах придётся бегать между ними.
  • stdout. Современный стандарт для контейнеров (Docker, Kubernetes). Приложение пишет в стандартный вывод, а система логирования (Docker, journald) сама решает, куда это деть. Удобно.
  • Syslog / journald. Системный журнал Linux. Хорошо для системных сервисов и критических ошибок. Легко смотреть через journalctl.
  • Централизованное хранилище. Loki, Elasticsearch, ClickHouse. Приложение шлёт логи туда по сети. Все сервисы пишут в одно место, и вы ищете по всем сразу. Правильный вариант для серьёзного проекта.

Рекомендация: пишите в stdout, а сбор логов отдайте системе. Это самый гибкий подход — легко подключить любой сборщик, не меняя код приложения.

4. Ротация: как не забить диск

Приложение пишет логи каждую секунду. За сутки накапливаются гигабайты. Через месяц — сотни гигабайт, диск заполнен, сервер упал. Это одна из самых частых причин падения по вине самого разработчика.

Ротация логов через logrotate:

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload myapp > /dev/null 2>&1 || true
    endscript
}

Что это делает:

  • Ежедневно переименовывает лог в архив
  • Хранит 14 последних архивов (2 недели)
  • Сжимает старые логи через gzip (экономия 90%)
  • Удаляет самые старые

Настройте ротацию сразу, как только запустите проект. Потом будет поздно — когда диск заполнится, придётся чистить вручную и разбираться, почему всё упало.

5. Централизованный сбор

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

Три популярных варианта:

  • Grafana Loki. Лёгкий, простой, дешёвый. Хранит логи в сжатом виде, ищет быстро. Идеален для небольших проектов. Легко ставится через Docker Compose вместе с Grafana.
  • ELK (Elasticsearch + Logstash + Kibana). Мощнее, но тяжелее. Elasticsearch жрёт много памяти (минимум 4 ГБ). Для крупных проектов с тысячами логов в секунду.
  • ClickHouse + Vector. Современный подход. ClickHouse отлично жмёт и ищет, Vector собирает. Отличное соотношение «мощность / ресурсы».

Пример docker-compose для Loki + Grafana:

version: '3'
services:
  loki:
    image: grafana/loki:latest
    ports: ["3100:3100"]
    volumes:
      - ./loki-config.yml:/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log
      - ./promtail-config.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.yml

  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
    depends_on: [loki]
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true

Через 10 минут после запуска у вас Grafana на порту 3000, где можно искать по всем логам сразу. Запрос «показать все ERROR за последний час» — одна строка в интерфейсе.

6. Что логировать в веб-приложении

Не «всё подряд», а конкретные события. Вот минимум, без которого отладка превращается в гадание.

  • Входящие HTTP-запросы. Метод, URL, статус, время обработки. Есть на уровне веб-сервера (nginx), обычно не нужно дублировать в приложении.
  • Бизнес-события. «Пользователь зарегистрировался», «заказ оформлен», «платёж прошёл». По ним видно, работает ли сайт по назначению.
  • Ошибки в бизнес-логике. «Не удалось применить промокод», «товар закончился при оформлении». Это не 500-е ошибки, но клиенты их видят.
  • Внешние вызовы. Запросы к API платёжной системы, службы доставки, SMS-шлюза. С временем ответа и статусом. Это критично для отладки.
  • Медленные запросы. SQL-запросы дольше 500 мс. Помогают находить узкие места.
  • Изменения конфигурации. Кто и когда менял настройки. Для аудита.
  • Аутентификацию. Успешные и неудачные попытки входа. Важно для безопасности.

7. Что НЕЛЬЗЯ логировать

Логи часто утекают: их копируют, отправляют в поддержку, загружают в сторонние сервисы. Если в логах персональные данные — это уже нарушение 152-ФЗ.

  • Пароли. Никогда. Даже хешированные. Восстановление пароля — через ссылку, а не через «мы посмотрели ваш пароль в логах».
  • Номера банковских карт, CVV. Категорически. Для отладки достаточно последних 4 цифр карты и первых 6 (BIN).
  • Токены и API-ключи. Не только свои, но и клиентские. Если нужно отладить запрос к внешнему API — логируйте факт запроса, но не сам токен.
  • Персональные данные в явном виде. Полные паспортные данные, СНИЛС, ИНН. Если нужно — маскируйте: 1234****90.
  • Тела запросов с данными пользователей. Целые формы, письма, сообщения в чате. Только метаданные: длина, тип, статус.
Маскирование — обязательная практика

Даже если сами логи не утекают, их могут увидеть не те люди. Маскируйте персональные данные автоматически: +7 (___) ***-**-42, user_42@***.ru. Тогда даже при случайной утечке ничего критичного не потеряется.

8. Связь с мониторингом

Логи и метрики работают в паре. Метрики показывают «что-то не так» (график ошибок пошёл вверх), логи объясняют «что именно» (вот конкретные ошибки с контекстом).

Идеальная связка: в каждой строке лога есть trace_id — уникальный идентификатор запроса. Метрика показывает проблему, по trace_id находите все логи этого запроса, видите полную картину: какой пользователь, что делал, где упало.

Такой подход называется distributed tracing. Если проект разрастается до микросервисов — без него отладка становится невыносимой. Для монолита достаточно просто добавлять trace_id к каждому запросу.

Логи — это не «для разработчиков». Это инструмент бизнеса. Когда клиент пишет «у меня не работает», вы открываете логи и за минуту находите причину. Когда SEO-трафик падает — по логам видите, какие страницы чаще отдают ошибку. Когда готовите новую фичу — по логам понимаете, какие функции реально используют.

Настроим логирование и мониторинг

Развернём Loki, настроим structured logging, свяжем с алертами в Telegram. От 10 000 ₽.