Сбор логов с нескольких серверов: с чего начать
Инфраструктура выросла с одного сервера до пяти-десяти, а логи как лежали локально на каждой машине, так и лежат. Пока всё работает — это не мешает. Но в момент реального инцидента, когда нужно понять, какой из серверов отвечает медленно или на каком из них упала служба, приходится вручную заходить по SSH на каждый и вручную же листать journalctl или /var/log. Разберём, как собрать логи со всех серверов в одном месте и почему это стоит сделать раньше, чем вы думаете.
Содержание
Проблема: логи разбросаны, а инцидент один
Пока у вас один сервер, tail -f /var/log/nginx/error.log решает любую проблему за секунды. Как только серверов становится несколько — а тем более когда за приложением стоит балансировщик и запрос может уйти на любой из трёх бэкендов — картина меняется.
Типичный сценарий: пользователи жалуются, что сайт иногда отдаёт 502. Вы не знаете заранее, на каком именно сервере это произошло — балансировщик распределяет нагрузку, и упасть могла любая из нод. Приходится:
- Подключаться по SSH к серверу №1, смотреть логи nginx и приложения за нужный промежуток времени.
- Ничего не найти, подключаться к серверу №2.
- Повторить для серверов №3, №4 — и так, пока не найдётся тот самый, где реально что-то сломалось.
- При этом на каждом сервере свой часовой пояс в логах, свой формат, и сопоставлять записи из разных источников приходится вручную, в голове.
Каждый такой обход — это 5-15 минут потерянного времени, а инцидент тем временем продолжается. Проблема не в том, что логов нет — они есть, и подробные. Проблема в том, что они физически разбросаны, и добраться до нужной строчки означает сначала угадать, на какой машине она лежит.
Это же касается менее драматичных задач: посчитать, сколько всего было ошибок определённого типа за сутки по всей инфраструктуре, разом посмотреть все обращения одного IP-адреса ко всем серверам, найти, с какого момента на всех нодах разом начали расти тайм-ауты к базе данных. Без централизации каждый такой вопрос — это N ручных проверок вместо одной.
Принцип: агент на каждом сервере, хранилище — одно
Решение не требует изобретения велосипеда, схема стандартная и работает одинаково что для трёх серверов, что для тридцати:
- На каждом сервере, где есть логи, ставится лёгкий агент сбора — процесс, который следит за локальными файлами логов (или журналом systemd) и пересылает новые записи дальше по сети.
- Все агенты отправляют данные в одно центральное хранилище — отдельный сервер (или сервис), где логи со всех источников складываются вместе и индексируются для поиска.
- Доступ к логам идёт не через SSH на каждую машину, а через один веб-интерфейс, где можно искать сразу по всей инфраструктуре: «покажи все ошибки уровня error на любом сервере за последний час» — это один запрос, а не десять сессий SSH.
Агент — это не сборщик логики и не парсер бизнес-данных, это просто транспорт. Он читает файл, добавляет метаданные (имя хоста, имя сервиса, время) и отправляет пакет по сети — обычно по TCP/UDP на syslog-совместимый порт, по HTTP на API, либо через специализированный протокол вроде gRPC у Loki. Нагрузка на CPU и память у таких агентов минимальна: promtail или vector в режиме простого чтения файлов обычно занимают единицы-десятки мегабайт памяти.
Разница между инструментами — в том, что происходит на стороне хранилища и как строится поиск, но сам принцип «источник → агент → сеть → центральное хранилище» одинаков что для Graylog, что для Grafana Loki, что для ELK-стека.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSШаг 1. Выбор центрального хранилища логов
Первое решение — куда именно будут стекаться логи. Здесь не нужно сразу строить отказоустойчивый кластер на три ноды: если у вас 3-10 серверов и логов немного (условно, до нескольких гигабайт в день), с задачей справится один выделенный сервер под хранилище логов, а не сложная распределённая система.
Три реалистичных варианта на конец 2026 года:
| Вариант | Когда подходит | Требования к ресурсам |
|---|---|---|
| Grafana Loki | Логи + метрики уже в Grafana, хочется единого дашборда, не нужен полнотекстовый поиск по всему телу сообщения | Легче остальных, экономит диск за счёт индексации только по меткам |
| Graylog | Нужен полноценный поиск по содержимому логов, готовые дашборды, ролевой доступ для команды | Требует Elasticsearch/OpenSearch и MongoDB под капотом, ресурсоёмче Loki |
| ELK/OpenSearch напрямую | Уже есть опыт с Elasticsearch, нужна максимальная гибкость запросов | Самый прожорливый по памяти вариант из трёх |
Если у вас уже развёрнут связанный стек наблюдаемости, который объединяет метрики, трейсы и логи в одном инструменте — часто такая платформа уже включает приём и хранение логов «из коробки», и заводить для этого отдельный сервис не требуется. Проверьте, что уже стоит в инфраструктуре, прежде чем поднимать новый компонент с нуля.
Для старта на 3-5 серверов достаточно одной VPS с 4 ГБ RAM под Loki либо 8 ГБ под Graylog — это не производственная нагрузка на тысячи запросов в секунду, а разумный первый шаг. Расширять хранилище (диск, память, при необходимости — вынос на отдельный кластер) можно позже, когда объём логов реально это потребует.
Практический пример: поднимаем Loki в Docker Compose на выделенном сервере.
# docker-compose.yml на центральном сервере логов
version: "3.8"
services:
loki:
image: grafana/loki:3.1.0
ports:
- "3100:3100"
volumes:
- ./loki-data:/loki
command: -config.file=/etc/loki/local-config.yaml
grafana:
image: grafana/grafana:11.2.0
ports:
- "3000:3000"
volumes:
- ./grafana-data:/var/lib/grafana
depends_on:
- loki
После docker compose up -d порт 3100 должен принимать записи от агентов с других серверов, а Grafana на порту 3000 — служить единым интерфейсом для поиска. Порт 3100 стоит закрыть файрволом от внешнего мира и открывать только для IP-адресов ваших серверов-источников (или заворачивать через VPN/WireGuard между машинами — так трафик логов не идёт через открытый интернет).
Шаг 2. Установка агента сбора на каждом существующем сервере
Второй шаг — на каждом сервере, логи которого нужно видеть централизованно, ставится агент, настроенный слать данные на адрес хранилища из шага 1. Это единственное действие, которое повторяется на всех машинах — и его удобно выполнить через любой инструмент управления конфигурацией (Ansible, простой shell-скрипт по SSH), чтобы не настраивать каждый сервер вручную заново.
Пример для связки с Loki — агент Promtail, который читает системные логи и логи nginx:
# /etc/promtail/config.yml — ставится на КАЖДОМ сервере-источнике
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://IP_ЦЕНТРАЛЬНОГО_СЕРВЕРА:3100/loki/api/v1/push
scrape_configs:
- job_name: nginx-error
static_configs:
- targets: [localhost]
labels:
job: nginx
host: web-01 # уникальное имя каждого сервера
__path__: /var/log/nginx/error.log
- job_name: app-error
static_configs:
- targets: [localhost]
labels:
job: app
host: web-01
__path__: /var/log/myapp/error.log
Ключевой момент — метка host должна быть уникальной для каждого сервера (web-01, web-02, db-01 и так далее). Именно по ней потом в интерфейсе поиска отличают, откуда пришла конкретная запись, и строят фильтры вида «покажи ошибки только с серверов группы web-*».
Если стек — Graylog, вместо Promtail на каждом сервере обычно ставится Filebeat или rsyslog с пересылкой по GELF/syslog:
# /etc/rsyslog.d/60-forward.conf — минимальный вариант через системный rsyslog
*.* @@IP_ЦЕНТРАЛЬНОГО_СЕРВЕРА:5140
Двойной @@ означает TCP (надёжнее, чем UDP с одним @, при пересылке по сети — пакеты не теряются молча). Это самый простой способ начать без установки дополнительного агента, если сервер уже использует rsyslog — но он ограничен возможностями самого rsyslog и подходит скорее для системных логов, чем для логов конкретного приложения.
После установки агента на первом сервере стоит сразу проверить, что записи доходят до хранилища, и только потом тиражировать конфиг на остальные — отличаться между серверами должна только метка host, всё остальное можно сохранить как единый шаблон.
Шаг 3. Структурированный формат вместо простого текста
Когда логи только начинают собираться в одном месте, они часто остаются в том виде, в каком писались изначально — свободным текстом вроде:
2026-08-29 14:32:07 ERROR Failed to connect to database: timeout after 5000ms
Такую строку можно найти по подстроке, но сложно фильтровать и агрегировать: нельзя одним запросом вычленить только ошибки конкретного типа отдельно от таймаутов конкретной длительности — придётся парсить текст регулярками уже на стороне поиска.
Там, где это возможно — в первую очередь в собственном приложении — стоит перейти на структурированные логи в формате JSON с явными полями:
{"timestamp":"2026-08-29T14:32:07Z","level":"error","service":"api","event":"db_connect_failed","timeout_ms":5000,"host":"web-01"}
Разница на практике: вместо поиска по подстроке "Failed to connect" вы получаете возможность фильтровать точно — level=error AND event=db_connect_failed AND timeout_ms>3000 — и строить агрегации (сколько таких ошибок за час, на каких хостах чаще). Большинство современных логирующих библиотек (zap и zerolog для Go, structlog для Python, встроенный JSON-форматтер в Winston для Node.js) умеют писать в этом формате из коробки — обычно это вопрос смены форматтера, а не переписывания логики логирования.
Для системных логов и логов сторонних сервисов (nginx, PostgreSQL) полная структуризация не всегда реалистична и не обязательна с первого дня — можно включить JSON-формат логов там, где это конфигурируется одной строкой (например, log_format json_combined в nginx), а остальное оставить как есть и парсить на стороне хранилища через готовые парсеры (grok-паттерны, конвейеры обработки в Loki/Graylog).
С чего начать на практике: не всё и сразу
Соблазн — сразу построить идеальную систему, которая с первого дня охватывает все логи со всех серверов: системные журналы, логи всех приложений, логи баз данных, логи сетевого оборудования. На практике это растягивает внедрение на недели и часто заканчивается тем, что проект бросают на середине.
Более рабочий подход:
- Начните с самого критичного. Логи ошибок приложения и логи веб-сервера (nginx/Apache access и error) на 1-2 самых важных серверах — обычно именно там находится причина большинства реальных инцидентов.
- Проверьте, что это действительно работает — записи доходят до хранилища, поиск по ним быстрый и понятный, метка
hostкорректно проставляется. - Расширяйте охват по мере необходимости, а не по плану «на бумаге». Столкнулись с инцидентом, где не хватило логов конкретного сервиса — добавьте именно его на следующий день. Так система растёт вслед за реальными задачами, а не опережает их.
- Только после этого переходите к менее критичным источникам: логам системных служб, логам cron-задач, аудиту авторизаций.
Такой поэтапный запуск занимает часы, а не недели, и уже после первого шага даёт ощутимую пользу: диагностика проблемы на нескольких серверах перестаёт требовать обхода каждого из них по отдельности. Разница между «идти по SSH на все пять серверов» и «ввести один запрос в общем интерфейсе» — это ровно то время, которое в момент реального инцидента стоит дороже всего.
Отдельный практический момент: заведите ротацию и retention с самого начала, а не после того, как диск на сервере хранилища закончится. Логи со всех серверов в одном месте растут быстрее, чем локальные логи на одной машине — потому что суммируются данные сразу от всех источников.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько ресурсов нужно центральному серверу логов на старте?
Для 3-5 серверов и умеренного трафика логов (условно, до пары гигабайт в день) хватает VPS с 4 ГБ RAM под Loki или 8 ГБ под Graylog — это ориентир, а не точная цифра, реальное потребление зависит от объёма и глубины хранения (retention).
Нужно ли сразу собирать абсолютно все логи со всех серверов?
Нет — начните с логов ошибок приложения и веб-сервера на самых важных серверах, расширяйте охват по мере реальной необходимости, а не по заранее составленному исчерпывающему списку.
Что делать, если сеть между серверами и центральным хранилищем нестабильна?
Использовать TCP вместо UDP для пересылки (агенты вроде Promtail и Filebeat это делают по умолчанию) и держать локальный буфер — большинство агентов умеют дозаписывать данные при временной недоступности хранилища и не терять их.
Обязательно ли переводить все логи в JSON сразу?
Нет — начните со своего приложения, где это дешевле всего внедрить, а логи сторонних сервисов подключайте к структурированному формату постепенно, там где это конфигурируется без переписывания кода.
Можно ли собирать логи с серверов в разных локациях (RU/US/UK) в одно хранилище?
Да, технически ограничений нет — важно защитить канал передачи (VPN или TLS между агентом и хранилищем) и учесть задержку сети при выборе TCP-таймаутов в конфиге агента.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →