Настройка сбора логов в Linux: syslog, journald и отправка на удалённый сервер | AdminWiki

Настройка сбора логов в Linux: syslog, journald и отправка на удалённый сервер

11 сентября 2026 14 мин. чтения
Содержание статьи

Короткий ответ: в RHEL 9 и 10, Ubuntu 22.04 и 24.04, Debian 12 и 13, AlmaLinux и Rocky локальные логи собирает systemd-journald, а на удалённый сервер их отправляет rsyslog через модуль omfwd по TCP с очередью на диске. Такая связка закрывает большинство задач централизованного сбора. Syslog-ng выбирают там, где нужна сложная маршрутизация: несколько приёмников, разбор и перезапись полей, десятки фильтров.

Надёжность схемы держится на четырёх настройках: TCP вместо UDP, буфер queue.type="disk" на случай недоступности приёмника, TLS для шифрования и фильтр, который отсекает debug-шум. Логи пропадают почти всегда из-за того, что один из этих пунктов пропущен.

Дальше: сравнение технологий, готовые конфиги rsyslog и syslog-ng, постоянное хранилище journald, права и ротация, чек-лист диагностики потери сообщений. Каждый пример проверяется на стенде за 20-30 минут.

Какую систему логирования выбрать: syslog, rsyslog, syslog-ng или journald

Четыре названия часто используют как синонимы, хотя это разные уровни стека. Путаница в терминологии приводит к тому, что администратор ищет документацию не для того компонента.

Чем syslog отличается от rsyslog и syslog-ng

syslog - это протокол обмена сообщениями. Первый формат зафиксирован в RFC 3164 (2001 год, BSD-строка с приоритетом и меткой времени без года), актуальный - в RFC 5424 (2009 год): структурированные блоки данных SD-ID, точность времени до микросекунд, обязательная кодировка UTF-8, идентификатор сообщения MSGID.

rsyslog и syslog-ng - демоны, которые принимают и отправляют сообщения в обоих форматах и добавляют то, чего в протоколе нет: очереди на диск, TLS, RELP, шаблоны имён файлов, фильтры по десяткам свойств. Rsyslog входит в базовую поставку RHEL, AlmaLinux, Rocky, Fedora, Debian и Ubuntu. Syslog-ng ставят в SUSE Linux Enterprise и openSUSE, часто выбирают в компаниях с большим парком сетевого оборудования, где нужны цепочки маршрутизации. Пакеты есть в репозиториях большинства дистрибутивов, поэтому выбор не привязан к платформе.

Journald: когда systemd-логов достаточно, а когда нет

journald входит в systemd и пишет структурированные записи в бинарный журнал. Каждое сообщение несёт поля _PID, _UID, _GID, _COMM, _SYSTEMD_UNIT, _HOSTNAME, _BOOT_ID, MESSAGE. Для локальной отладки это удобнее текстовых файлов: команда journalctl -u nginx --since "1 hour ago" -p err возвращает только ошибки конкретного сервиса.

Ограничения конкретны. Бинарный формат читается через journalctl или journal-gatewayd. Родной протокол journald не рассчитан на передачу по сети: systemd-journal-upload умеет отправлять журнал на journal-remote, но фильтрация и маршрутизация там беднее, чем в rsyslog. Журнал привязан к systemd, а в контейнерах без systemd он недоступен. Поэтому в схеме с централизацией journald выступает источником, а транспорт выполняет rsyslog или syslog-ng. Как читать журнал, фильтровать по сервису, PID и времени, настраивать хранение и ротацию, разобрано в практическом руководстве по journalctl.

Критерийjournaldrsyslogsyslog-ng
Формат хранениябинарный журналтекстовые файлы, шаблонытекстовые файлы, шаблоны
Поставка по умолчаниювсе дистрибутивы с systemdRHEL, Debian, Ubuntu, FedoraSUSE, ставится отдельным пакетом
Фильтрацияполя и юниты, только локальноproperty-based фильтры, RainerScriptfilter и parser, свой язык конфигурации
Передача по сетиjournal-upload, ограниченноTCP, UDP, TLS, RELPTCP, UDP, TLS, disk-buffer
Очередь при сбое сетинетqueue.type="disk"disk-buffer()
Структурированные поляестьчерез imjournalчерез systemd-journal()
Порог входанизкийсреднийвыше среднего

Для типового парка серверов оптимальна связка journald + rsyslog: журнал остаётся локально для отладки, rsyslog отправляет копии по сети. Syslog-ng берут при маршрутизации в несколько приёмников и разборе нестандартных форматов. Rsyslog без journald уместен в контейнерах и системах без systemd. Чистый journald оставляют на одиночных машинах, где централизованный сбор не нужен.

Локальный сбор логов: настройка journald и rsyslog

Удалённая отправка бесполезна, если локально логи не сохраняются. По умолчанию journald в ряде сборок пишет в /run/log/journal, то есть в оперативную память: после перезагрузки записи исчезают.

Включаем persistent storage в journald

Правка /etc/systemd/journald.conf:

[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=2week
Compress=yes
ForwardToSyslog=yes

Storage=persistent создаёт каталог /var/log/journal при первом запуске. Значение auto пишет на диск только если каталог уже существует, и именно это поведение встречается в части сборок. SystemMaxUse=500M ограничивает журнал, SystemKeepFree=1G оставляет свободное место на разделе, чтобы journald не заполнил диск целиком. MaxRetentionSec=2week удаляет записи старше двух недель независимо от размера. Compress=yes сжимает блоки данных, доступ к записям через journalctl остаётся прозрачным.

Применение и проверка:

systemctl restart systemd-journald
ls -la /var/log/journal
journalctl --disk-usage

Последняя команда выводит строку вида "Archived and active journals take up 128.0M in the file system". Если каталог /var/log/journal пуст или отсутствует, настройка не применилась: проверьте переопределения в /etc/systemd/journald.conf.d/*.conf и вывод systemctl status systemd-journald.

Базовая конфигурация rsyslog

Файл /etc/rsyslog.conf делится на три части. Модули: module(load="imuxsock") читает локальный сокет, module(load="imjournal") читает журнал systemd, module(load="imklog") забирает сообщения ядра. Глобальные параметры: $WorkDirectory /var/spool/rsyslog задаёт каталог для очередей. Правила: селектор facility.severity и действие.

authpriv.*                                              /var/log/auth.log
*.info;mail.none;authpriv.none;cron.none                /var/log/syslog
cron.*                                                  /var/log/cron.log

Селектор читается как "facility уровня severity и выше". Запись *.info означает все facility с уровнем info и более важным, mail.none исключает почтовые сообщения. В RHEL и AlmaLinux базовый файл называется /var/log/messages, в Debian и Ubuntu - /var/log/syslog. Свои правила кладут в /etc/rsyslog.d/*.conf, файлы подключаются в алфавитном порядке, поэтому префиксы 10-, 50-, 90- задают приоритет. Перед перезапуском проверяйте синтаксис:

rsyslogd -N1

Команда разбирает конфигурацию и завершается строкой "rsyslogd: End of config validation run. Bye." Ошибки с номером строки появляются выше.

Отправка логов на удалённый сервер: rsyslog и syslog-ng

Транспорт выбирают по двум критериям: гарантия доставки и шифрование. UDP (символ @ в конфиге) не подтверждает приём, при перегрузке сети пакеты пропадают. TCP (символ @@) даёт подтверждение на уровне сегментов, а очередь с сохранением на диск (disk-assisted queue) позволяет пережить недоступность приёмника длиной в часы и сутки. Архитектуру всего конвейера, включая выбор хранилища, разбирает обзор архитектуры централизованного сбора логов.

Сервер-коллектор держите отдельно от продакшена: он принимает трафик со всех хостов и хранит данные, которые нужны при разборе инцидентов. Для этой роли подходит VPS с 2-4 vCPU и диском от 80 ГБ, например в Timeweb Cloud, где диск наращивается независимо от вычислительных ресурсов.

Настройка rsyslog: TCP, TLS и очередь на диске

Файл /etc/rsyslog.d/50-remote.conf на клиенте:

module(load="omfwd")

*.* action(type="omfwd"
    target="log.example.com"
    port="6514"
    protocol="tcp"
    tls="on"
    tls.caCert="/etc/rsyslog.d/ca.pem"
    tls.myCert="/etc/rsyslog.d/client.pem"
    tls.myPrivKey="/etc/rsyslog.d/client.key"
    tls.authmode="x509/name"
    tls.permittedpeer="log.example.com"
    queue.type="disk"
    queue.filename="remote_queue"
    queue.maxdiskspace="1g"
    queue.saveonshutdown="on"
    action.resumeRetryCount="-1"
    action.resumeInterval="30")

Параметры по смыслу:

  • target и port: адрес коллектора. Порт 6514 закреплён за syslog over TLS в RFC 5425, без шифрования используют 514.
  • protocol="tcp": подтверждение доставки на транспортном уровне.
  • tls.*: пути к сертификатам. Режим authmode="x509/name" проверяет имя в сертификате сервера, permittedpeer фиксирует допустимое значение CN или SAN.
  • queue.type="disk": сообщения буферизуются в /var/spool/rsyslog, а не в оперативной памяти. queue.maxdiskspace="1g" задаёт предел буфера.
  • queue.saveonshutdown="on": очередь сохраняется при остановке демона и читается после запуска. Без этого параметра буфер теряется при перезагрузке.
  • action.resumeRetryCount="-1": бесконечные повторные подключения с интервалом 30 секунд.

Короткая форма записи: *.* @@log.example.com:514 для TCP и *.* @log.example.com:514 для UDP. Для продакшена используйте расширенный синтаксис из примера. Перезапуск: systemctl restart rsyslog, проверка конфигурации: rsyslogd -N1.

Настройка syslog-ng: destination и network()

Файл /etc/syslog-ng/conf.d/remote.conf:

destination d_remote {
    network("log.example.com" port(6514) transport("tls")
        tls(
            ca-file("/etc/syslog-ng/ca.pem")
            cert-file("/etc/syslog-ng/client.pem")
            key-file("/etc/syslog-ng/client.key")
        )
        disk-buffer(
            mem-buf-size(64M)
            disk-buf-size(1024M)
            reliable(yes)
        )
    );
};

log {
    source(s_src);
    destination(d_remote);
};

disk-buffer() создаёт файл буфера в /var/lib/syslog-ng. Опция reliable(yes) сохраняет буфер при перезапуске демона и доступна в syslog-ng 4.2 и новее; на ветке 3.x буфер в памяти теряется при остановке. Проверка конфигурации: syslog-ng -s, перезапуск: systemctl restart syslog-ng.

Разделение логов по источникам на принимающей стороне

На коллекторе rsyslog раскладывает принятые сообщения по каталогам с именами хостов. Конфигурация /etc/rsyslog.d/10-remote.conf:

module(load="imtcp")
input(type="imtcp" port="514")

template(name="RemoteLogs" type="string"
    string="/var/log/remote/%hostname%/%programname%.log")

*.* action(type="omfile" dynaFile="RemoteLogs"
    fileCreateMode="0640" dirCreateMode="0750"
    fileOwner="root" fileGroup="adm")

dynaFile подставляет имя файла из шаблона для каждого сообщения. Значение %hostname% берётся из заголовка syslog, %programname% из тега. Если хост передаёт пустое имя или символ "/" в поле, каталог не создастся и запись уйдёт в ошибку; в таких случаях %hostname% заменяют на %fromhost-ip%. Для приёма по TLS добавьте в imtcp параметры streamDriver="gtls", streamDriverMode="1", streamDriverAuthMode="x509/name" и путь к сертификатам.

В syslog-ng раскладка выполняется через макросы:

destination d_by_host {
    file("/var/log/remote/${HOST}/${PROGRAM}.log" create-dirs(yes));
};

Фильтрация логов: отправляем только то, что нужно

Основной объём журналов даёт шум: debug-записи, регулярные задачи cron, проверки healthcheck каждые 5 секунд. Без фильтрации канал и хранилище растут линейно вместе с числом сервисов. Критерии, что действительно стоит отправлять, собраны в статье что логировать, а что нет.

Фильтры в rsyslog: по программе, facility и severity

Property-based фильтры проверяют поля сообщения. Severity кодируется числами: 0 emerg, 1 alert, 2 crit, 3 err, 4 warning, 5 notice, 6 info, 7 debug. Меньшее число означает более высокий приоритет, поэтому условие $syslogseverity <= 4 выбирает warning и всё, что важнее.

if $syslogfacility-text == 'authpriv' then {
    action(type="omfwd" target="log.example.com" port="6514"
        protocol="tcp" tls="on"
        queue.type="disk" queue.filename="auth_queue"
        queue.maxdiskspace="512m")
    stop
}

if $syslogseverity <= 4 then {
    action(type="omfwd" target="log.example.com" port="6514"
        protocol="tcp" tls="on"
        queue.type="disk" queue.filename="warn_queue")
    stop
}

Директива stop прекращает обработку сообщения последующими правилами, а порядок блоков задаёт приоритет: правила читаются сверху вниз. Фильтр по программе выглядит так: if $programname == 'nginx' then { ... }. Комбинация условий: if ($programname == 'sshd') and ($syslogseverity <= 5) then { ... }.

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

Фильтры в syslog-ng

filter f_auth { facility(authpriv); };
filter f_warn { level(warn..emerg); };
filter f_nginx { program("nginx"); };

log { source(s_src); filter(f_auth); destination(d_remote); };
log { source(s_src); filter(f_warn); destination(d_remote); };

Запись level(warn..emerg) покрывает диапазон от warning до emergency. Фильтры комбинируются логическими операторами: filter f_auth_warn { facility(authpriv) and level(warn..emerg); };. Слишком узкий фильтр скрывает события, которые нужны при разборе сбоя. Перед отправкой правил на весь парк прогоните их на одном стенде и сравните объём с полным потоком. Отдельно проверяйте, что фильтр не отсекает сообщения о старте сервисов: они помогают восстановить хронологию.

Проверка подключения и диагностика потери сообщений

Проверка занимает меньше минуты, если идти по шагам: отправить тестовое сообщение, найти его на приёмнике, убедиться, что соединение установлено.

Быстрая проверка: доходит ли сообщение

На клиенте:

logger -p local0.err -t deploy-check "test-$(date +%s)"

На коллекторе:

tail -f /var/log/remote/web-01/*.log | grep deploy-check
grep deploy-check /var/log/remote/web-01/*.log

Уровень err выбран намеренно: если фильтр отправляет только warning и выше, сообщение с уровнем info не покинет клиент, и вы решите, что сломан транспорт. Соединение проверяют через ss -tnp | grep 6514 и tcpdump -ni eth0 port 6514 -A на приёмнике. Флаг -p в ss показывает процессы и требует root. Пустой вывод tcpdump при работающем клиенте указывает на firewall или неверный адрес.

Диагностика: почему логи теряются

Семь причин покрывают большинство случаев:

  1. UDP вместо TCP. Пакеты пропадают при перегрузке очереди сокета, и потерь не видно ни в одном логе. Проверка: ss -u -a | grep 514 и повтор tcpdump с фильтром udp port 514.
  2. Очередь в памяти. Без queue.type="disk" rsyslog держит сообщения в RAM, и при рестарте или нехватке ресурсов буфер исчезает. Проверка: ls -la /var/spool/rsyslog, наличие файлов remote_queue.qi.
  3. Переполнен диск. Проверка: df -h /var/log /var/spool и journalctl --disk-usage. При заполнении раздела rsyslog останавливает запись и теряет сообщения из очереди.
  4. Фильтр отсекает нужное. Временный конфиг с *.* в отдельном файле показывает, доходит ли поток без условий.
  5. SELinux или AppArmor блокирует нестандартный порт. Проверка: ausearch -m avc -ts recent и dmesg | grep -i denied. Для порта 6514 в RHEL: semanage port -a -t syslogd_port_t -p tcp 6514.
  6. Шаблон на приёмнике даёт неверный путь, например пустой %hostname%. Проверка: тестовое сообщение с явным тегом и просмотр каталога /var/log/remote.
  7. Расхождение часов. При сдвиге времени больше чем на час сообщения попадают не в тот файл ротации или выпадают из выборки --since. Проверка: timedatectl и chronyc tracking.

Счётчики очередей показывает модуль impstats: module(load="impstats" interval="60" log.syslog="on") публикует размер очереди и число отброшенных сообщений. Для отладки правил запускают rsyslogd -dn (режим debug в foreground) и смотрят, какие фильтры срабатывают. Вывод большой, поэтому применяют на стенде, а не на продакшене.

Отдельная ловушка в imjournal: по умолчанию модуль ограничивает приём значениями Ratelimit.Interval=600 и Ratelimit.Burst=20000, то есть отбрасывает лишние записи при всплеске.

Когда нужно быстро разобрать большую выгрузку, агрегированные фрагменты удобно прогонять через LLM по API. Единый доступ к 200+ моделям (GPT, Gemini, Claude) с оплатой в рублях и без VPN даёт агрегатор AiTunnel. Перед отправкой обезличивайте данные: имена пользователей, IP и токены в URL заменяйте плейсхолдерами.

Права доступа, ротация и защита логов

Логи содержат имена пользователей, внутренние адреса, иногда токены в query string. Три задачи: закрыть чтение для посторонних, не дать журналам занять весь диск, зашифровать трафик между хостами.

Права на файлы и каталоги логов

В Debian и Ubuntu системные логи читает группа adm, в RHEL и производных файлы обычно принадлежат root:root с правами 600. Для каталога /var/log/remote рабочий вариант: владелец root, группа adm, права 750; файлы 640.

chown -R root:adm /var/log/remote
chmod 750 /var/log/remote
find /var/log/remote -type f -exec chmod 640 {} +

Права новых файлов задают прямо в действии rsyslog: fileCreateMode="0640", dirCreateMode="0750", fileOwner="root", fileGroup="adm". Проверка: ls -la /var/log/remote. Специалисту, которому нужен доступ к логам приложений, добавляют группу adm: usermod -aG adm username.

Ротация: logrotate и journald

Файл /etc/logrotate.d/remote-logs:

/var/log/remote/*/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
    postrotate
        /usr/lib/rsyslog/rsyslog-rotate
    endscript
}

Параметры: daily и rotate 14 хранят две недели истории, compress сжимает старые файлы, delaycompress оставляет вчерашний файл несжатым на случай, если rsyslog ещё пишет в него, notifempty пропускает пустые файлы. Путь к rsyslog-rotate отличается: в Debian и Ubuntu это /usr/lib/rsyslog/rsyslog-rotate, в RHEL, AlmaLinux и Rocky - /usr/libexec/rsyslog/rsyslog-rotate. Скрипт посылает демону сигнал, и тот переоткрывает файлы. Если postrotate не срабатывает, файлы продолжают расти вопреки ротации. Проверка: logrotate -d /etc/logrotate.d/remote-logs (dry run) и logrotate -f /etc/logrotate.d/remote-logs (принудительный запуск).

Для journald лимиты прописывают в /etc/systemd/journald.conf: SystemMaxUse=1G и MaxRetentionSec=2week. Ручная очистка: journalctl --vacuum-size=500M или journalctl --vacuum-time=7d. Команды удаляют данные сразу, поэтому сначала смотрят текущий объём через journalctl --disk-usage.

Шифрование передачи: TLS и RELP

Без TLS syslog идёт открытым текстом, включая содержимое сообщений. Шифрование в rsyslog обеспечивает драйвер gtls из пакета rsyslog-gnutls, порт 6514 закреплён за syslog over TLS в RFC 5425. Параметр tls.authmode="x509/name" вместе с tls.permittedpeer защищает от подмены сервера: клиент сверяет имя в сертификате. Сертификаты выпускают внутренним PKI или генерируют самоподписанные для тестового контура.

RELP (Reliable Event Logging Protocol) добавляет прикладные подтверждения доставки поверх TCP и работает в rsyslog через модули omrelp и imrelp (пакет rsyslog-relp), стандартный порт 20514. Приёмник подтверждает каждое сообщение, поэтому потери при обрыве связи видны сразу. TLS и RELP повышают нагрузку на CPU: на профиле в 10 000 сообщений в секунду включение шифрования заметно и требует теста с реальным трафиком.

Связка journald и rsyslog: как избежать дублирования и потерь

Journald и rsyslog взаимодействуют двумя способами. Параметр ForwardToSyslog=yes в journald.conf отправляет записи в сокет /run/systemd/journal/syslog, откуда их читает модуль imuxsock. Модуль imjournal читает бинарный журнал /var/log/journal напрямую и сохраняет структурированные поля. Если включены оба пути, rsyslog получает каждое сообщение дважды, и в централизованном хранилище появляются дубли.

ForwardToSyslog и imjournal: что выбрать

Схема с imuxsock проще: сообщения приходят в текстовом формате syslog, фильтры работают по facility и severity. В RHEL 8, 9 и 10 в /etc/rsyslog.conf включён imjournal с файлом состояния, а локальный сокет у imuxsock отключён параметром SysSock.Use="off". В Debian и Ubuntu по умолчанию ForwardToSyslog=yes, и текст читает imuxsock.

Когда нужны поля _SYSTEMD_UNIT, _PID и _COMM, выбирайте imjournal:

module(load="imjournal"
    StateFile="imjournal.state"
    IgnorePreviousBoot="off"
    PersistStateInterval="1000")

StateFile хранит позицию чтения, чтобы после перезапуска rsyslog не перечитывал журнал с начала. IgnorePreviousBoot="off" забирает записи прошлых загрузок, при значении on пропускает их. PersistStateInterval="1000" сохраняет позицию каждые 1000 сообщений: меньшее значение надёжнее и создаёт больше записей на диск. Поля доступны в шаблонах как $!_SYSTEMD_UNIT, $!_PID, $!_COMM, а всё дерево свойств выводится в JSON одной строкой:

template(name="JsonLine" type="string" string="$!all-json")

Отдельная ловушка: journald ограничивает поток на 10 000 сообщений за 30 секунд (RateLimitBurst и RateLimitIntervalSec в journald.conf). Активный сервис, который печатает чаще, получает в журнале пометку "Suppressed N messages", и часть событий не доходит до коллектора. Порог поднимают глобально или отключают лимит для конкретной службы через LogRateLimitIntervalSec=0 в unit-файле.

Что выбрать: один источник и один транспорт. Схема imjournal + rsyslog с очередью на диске даёт структурированные поля и надёжную отправку, а дальше данные удобно выводить в Grafana и Elasticsearch, как описано в руководстве по системному логированию. Проверка, что путь один:

grep -r "imjournal\|imuxsock\|ForwardToSyslog" /etc/rsyslog.conf /etc/rsyslog.d/ /etc/systemd/journald.conf
journalctl -u rsyslog -n 20

Если в выводе есть оба модуля при включённом ForwardToSyslog, отключите imuxsock строкой SysSock.Use="off" либо выставьте ForwardToSyslog=no. Дублирование замечают по одинаковым записям с разницей в доли секунды: они удваивают объём хранилища и мешают считать статистику.

Минимальный рабочий набор: Storage=persistent в journald, один путь journald - rsyslog, omfwd с TCP и TLS, очередь queue.type="disk" вместе с saveonshutdown, фильтр warning+ и отдельное правило для authpriv, logrotate на 14 дней, права 640 на файлы. Эти настройки закрывают типовые требования по надёжности и безопасности логов.

Поделиться:
Сохранить гайд? В закладки браузера