MAATRIX / Блог / Логи занимали 300 ГБ и никто их не читал

Логи занимали 300 ГБ и никто их не читал

MAATRIX

На сервере кончается место, вы идёте разбираться — и находите каталог с логами размером в сотни гигабайт, который копился годами. Открываете пару файлов и понимаете: последний раз в них кто-то заглядывал очень давно, а большая часть записей — это DEBUG-мусор от компонента, который никто уже не трогал. Ситуация до банальности типичная, и в этой статье — как логи превращаются в мёртвый груз и что сделать, чтобы это не повторялось.

Как это вообще накапливается

Обычно это не одна причина, а комбинация из трёх привычек, каждая из которых по отдельности выглядит безобидно.

Уровень логирования «на всякий случай». Когда сервис только разрабатывался или отлаживался, кто-то выставил уровень DEBUG или TRACE — чтобы видеть всё при разборе проблемы. Проблему поймали, в продакшен часто уезжает та же конфигурация: никто не переключил уровень обратно на INFO или WARN. В логах остаются трассировки SQL-запросов, входящие HTTP-заголовки, содержимое очередей — объём на порядок больше, чем нужен для мониторинга здоровья сервиса.

# было при отладке
log_level: DEBUG

# осталось в проде спустя два года
log_level: DEBUG

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

Отсутствие ротации и срока хранения вообще. Самая частая находка: logrotate либо не настроен для конкретного лог-файла, либо настроен только на ротацию по размеру без ограничения по количеству копий — файлы access.log.1access.log.400 лежат рядом до бесконечности. Ещё чаще встречается сценарий, когда приложение пишет в один файл без ротации вообще, и он просто растёт, пока не кончится диск. Если логи дополнительно уезжают во внешнюю систему сбора (Graylog, ELK, Grafana Loki), то там retention policy по умолчанию нередко стоит «хранить вечно» или не настроена совсем — и индексы распухают параллельно с локальными файлами.

Отдельно стоит Docker: контейнеры по умолчанию пишут логи через драйвер json-file без ограничения размера, и если это не переопределить явно, лог одного шумного контейнера может занять весь диск быстрее, чем данные приложения. Разбор похожего случая — в статье Docker съел весь диск логами: разбор.

Почему «хранить всё на всякий случай» — обманчивая экономия

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

Практическая ценность логов для расследования инцидента резко падает уже в первые недели после события. Если инцидент не был замечен и разобран сразу, шансы, что кто-то через полгода откроет архивные логи и найдёт там причину — крайне малы: контекст утерян, метрики за тот период уже недоступны отдельно, а часто и сама проблема к этому моменту решена другим способом (откат деплоя, замена компонента, патч). Логи месячной и тем более годовой давности практически никогда не открываются вручную — это подтверждает любой, кто пробовал реально найти что-то в старом архиве логов вместо того, чтобы просто перезапустить проблемный сервис.

При этом расходы не останавливаются:

  • Дисковое пространство на сервере продолжает уменьшаться, что рано или поздно приводит к переполнению — а переполненный диск чаще всего роняет не только логирование, но и саму базу данных или приложение, которое туда же пишет. О похожем сценарии — в статье Диск заполнился на 100%: что отвалилось первым.
  • Хранение в системе агрегации — если логи улетают в Graylog, Loki, Elasticsearch или облачный сервис логирования — почти всегда тарифицируется по объёму хранимых данных или по объёму индекса. Чем больше исторических данных вы держите без пользы, тем дороже обходится сама система сбора логов, независимо от того, смотрит их кто-то или нет.
  • Скорость поиска в интерфейсе агрегатора падает пропорционально объёму индекса — чем больше там мёртвого груза, тем дольше выполняется любой запрос, даже к свежим логам за сегодня.

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Пересматриваем уровни логирования по компонентам

Первый шаг — не трогать retention, а честно пересмотреть, что вообще нужно писать. Практический подход:

  1. Выпишите список сервисов и компонентов, которые пишут логи на сервере.
  2. Для каждого ответьте на вопрос: когда в последний раз кто-то реально читал логи именно этого компонента при разборе инцидента?
  3. Если ответ — «давно» или «никогда», понижайте уровень до INFO (для основного потока событий) или WARN (если компонент стабилен и интересны только ошибки).
  4. Оставляйте DEBUG только там, где сейчас идёт активная разработка или разбирается конкретная известная проблема — и не забудьте вернуть уровень обратно, когда проблема решена.

Для systemd-сервисов уровень логирования обычно задаётся в конфиге самого приложения, но общий журнал можно ограничить на уровне journald:

# /etc/systemd/journald.conf
[Journal]
SystemMaxUse=2G
MaxRetentionSec=30day

Для приложений на Python — типичная точка, где уровень логирования выставлен слишком низко и забыт:

import logging
logging.basicConfig(level=logging.INFO)  # было DEBUG

Для Java-стека (Logback/Log4j2) уровень задаётся по пакетам — это удобно, потому что можно понизить шумный модуль отдельно, не трогая остальное приложение:

<logger name="com.example.legacy.worker" level="WARN"/>
<logger name="com.example.core" level="INFO"/>

Для Nginx полезно разделять access-лог по важности запросов, а не писать всё подряд с одинаковой детализацией:

error_log /var/log/nginx/error.log warn;

Общие практики логирования, включая выбор уровней и структурированный формат, разобраны отдельно в статье Лучшие практики логирования в Docker.

Ротация и срок хранения: logrotate и retention policies

Пересмотр уровней логирования снижает объём новых данных, но не решает вопрос старых. Здесь нужна ротация с реальным сроком хранения, а не просто ротация по размеру.

Базовый конфиг logrotate с ограничением и по времени, и по количеству копий:

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
    daily
    rotate 14
    maxage 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

Здесь rotate 14 держит не больше 14 архивных копий, а maxage 30 дополнительно гарантирует, что файлы старше 30 дней будут удалены, даже если ротация по каким-то причинам шла реже, чем ожидалось. Проверить, что ротация реально применяется и не сломана, можно так:

logrotate -d /etc/logrotate.d/myapp   # dry-run, показывает, что будет сделано

Подробный разбор настройки самого logrotate, включая частые ошибки конфигурации, — в статье Ротация логов, чтобы не забивался диск.

Для Docker логи ограничиваются на уровне демона или конкретного контейнера:

// /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Если логи агрегируются во внешней системе, там тоже нужна явная retention policy — по умолчанию многие системы её не ограничивают. В Graylog retention настраивается на уровне индекс-сетов (System → Indices): задаётся максимальное число индексов и/или срок хранения ротации. В Grafana Loki — параметром retention_period в конфигурации компактора:

# loki-config.yaml
limits_config:
  retention_period: 720h   # 30 дней

compactor:
  retention_enabled: true

Как выбрать между Graylog и Loki с учётом объёма и стоимости хранения — в статье Graylog или Grafana Loki: что выгоднее и когда.

Сжатие и архивация старых логов

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

  • Сжатие на месте. Опции compress и delaycompress в logrotate (см. пример выше) сжимают ротированные файлы gzip'ом, что обычно даёт кратное сокращение объёма для текстовых логов — конкретная степень сжатия зависит от содержимого и заранее не гарантируется.
  • Перенос в холодное хранилище. Логи старше определённого возраста (например, старше 30-60 дней) можно перекладывать на более дешёвый диск или в объектное хранилище вместо того, чтобы держать их на основном системном разделе рядом с рабочими данными.
  • Архивация вместо удаления для регуляторных требований. Если по вашей юрисдикции или контракту логи определённого типа должны храниться дольше (например, логи VPN-подключений — см. Логи VPN-подключений: что хранить по закону), сжатые архивы дешевле держать на отдельном томе, чем оставлять в горячем индексе агрегатора.

Важно: сжатие и архивация — это отсрочка решения, а не его замена. Если архив никто никогда не открывает и хранит без ограничения срока, вы просто медленнее приходите к той же проблеме переполненного диска.

Что хранить дольше: security и audit-логи

Правило «удаляем старое» не должно применяться одинаково ко всем логам без разбора. Есть категория, для которой длительное хранение оправдано осмысленной причиной, а не привычкой:

  • Audit-логи (auditd в Linux) — фиксируют изменения прав доступа, запуск привилегированных команд, доступ к чувствительным файлам. Их держат дольше именно потому, что инцидент безопасности может быть обнаружен спустя недели или месяцы после факта, и без этих записей расследование становится невозможным.
  • Логи аутентификации (/var/log/auth.log, sshd) — история попыток входа нужна при разборе компрометации учётной записи, которая часто вскрывается не сразу.
  • Логи VPN- и сетевых подключений — во многих юрисдикциях есть формальные требования к сроку хранения именно этой категории, отдельно от общих логов приложения.

Ключевое отличие от «логов на всякий случай» из первого раздела: здесь срок хранения — осознанное решение с понятной причиной (требование законодательства, политика безопасности, реальный сценарий расследования), а не результат забытой настройки. Практическая настройка auditd и работа с его логами разобраны в статье Аудит логов сервера: настройка auditd.

Разумный подход — держать security- и audit-логи на отдельном retention-профиле с более долгим сроком (например, 90-365 дней в зависимости от требований), а остальные операционные логи — на существенно более коротком.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Какой срок хранения логов выбрать по умолчанию?

Универсального числа нет, но для большинства операционных логов (доступ, ошибки приложения) разумной отправной точкой считается диапазон от нескольких недель до 1-3 месяцев — этого обычно достаточно, чтобы разобрать инцидент, пока он ещё актуален. Security- и audit-логи держат отдельно и дольше, исходя из требований.

Можно ли сразу удалить старые логи, не сжимая?

Можно, если вы уверены, что они не понадобятся и не подпадают под требования к хранению (например, для VPN-логов в вашей юрисдикции). Если не уверены — сначала сожмите и перенесите в холодное хранилище, удаление всегда можно сделать позже.

Что делать, если логи уже переполнили диск прямо сейчас?

Сначала освободите место безопасно — сожмите или удалите самые старые ротированные файлы (*.log.1.gz, *.log.2.gz и так далее), а не активный лог-файл, в который идёт запись. Затем уже настраивайте retention на будущее, чтобы ситуация не повторилась.

Нужно ли настраивать retention отдельно в logrotate и в системе агрегации логов, если используются обе?

Да — это независимые хранилища. Локальный logrotate управляет файлами на диске сервера-источника, а retention в Graylog/Loki/ELK — данными в индексе агрегатора. Настройка одного без другого оставляет вторую точку накопления нетронутой.

Как понять, какие компоненты можно перевести на менее подробный уровень логирования?

Постройте список компонентов и честно оцените, обращались ли к их логам за последние несколько месяцев при разборе реальных проблем. Если нет — это кандидат на понижение уровня с DEBUG/TRACE до INFO или WARN.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →