Почему rsyslog записывает дублирующие сообщения из журнала systemd?

Вопрос или проблема

Почему rsyslog может записывать дублирующиеся сообщения из журнала systemd?

Я в курсе известных проблем, связанных с порчей журнала systemd (см. например предупреждение в разделе “Цель” здесь: https://www.rsyslog.com/doc/configuration/modules/imjournal.html), но я не думаю, что это проблема, с которой я сталкиваюсь. Я использую Ubuntu 24.04, rsyslog 8.2312.0-3ubuntu9 и systemd 255.4-1ubuntu8.4.

У меня есть несколько хостов, на которых работает приложение под названием “foobar” в качестве службы systemd и ведется запись в журнал systemd. Я также запускаю rsyslog как службу systemd, и он настроен на пересылку журналов foobar в формате JSON из журнала systemd на центральный сервер журналов. Конфигурация rsyslog на каждом хосте выглядит следующим образом:

module(load="imjournal" StateFile="journalState" IgnorePreviousMessages="on")
module(load="mmjsonparse")
    
template(name="foobarJSON" type="string" string="%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n" )

if $syslogfacility-text == "user" and $programname == "foobar" then {
    user.* action(type="omfwd" target="central-logs.server" port="514" protocol="tcp" template="foobarJSON")
}

Я также запускаю rsyslog как службу systemd на центральном сервере журналов и записываю журналы foobar с каждого сервера в локальные файлы внутри отдельного подпапки для каждого хоста. Конфигурация rsyslog на этом хосте выглядит следующим образом:

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

template(name="foobarHostLogs" type="string" string="/var/logs/%PROGRAMNAME%/%HOSTNAME%/%$year%/%$month%/%$day%.log")

module(load="builtin:omfile" DirCreateMode="0755")

if $fromhost-ip != '127.0.0.1' then {
    action(type="omfile" dynaFile="foobarHostLogs")

    & stop
}

Запуская journalctl -u foobar на любом из хостов foobar, я не вижу никаких дублирующихся сообщений. Однако, когда я смотрю в журналы на центральном сервере журналов, я вижу, что каждое сообщение дублируется: есть как минимум одно сообщение, содержащее только поле “msg” из журнала systemd (хотя иногда я вижу две одинаковые строки, содержащие только “msg”), сразу за которым следует строка с точно таким же временным штампом и значением “msg”, а также всеми другими метаданными из журнала systemd.

Например (я убрал несколько лишних полей из второй строки ниже, но, надеюсь, вы понимаете суть):

2024-09-15T00:00:00+00:00 host-a foobar[123456]: @cee: { "msg": "Hello, world!" }
2024-09-15T00:00:00+00:00 host-a foobar[123456]: @cee: { "_TRANSPORT": "journal", "_PID": "123456", "_UID": "1000", "_GID": "1000", "_COMM": "foobar", "_EXE": "\/usr\/local\/bin\/foobar", "_CMDLINE": ".\/foobar", "_CAP_EFFECTIVE": "0", "_SELINUX_CONTEXT": "unconfined\n", "MESSAGE": "Hello, world!", "msg": "Hello, world!" }

Похоже, что у вас могут быть настроены оба метода пересылки syslog на клиентских хостах – помимо чтения журналов через imjournal (который предоставляет все метаданные), он, вероятно, также получает те же журналы через imuxsock в /run/systemd (наследственный метод пересылки без метаданных). Убедитесь, что ForwardToSyslog= отключено в вашем journald.conf.

Хорошо, мне удалось разобраться. @u1686_grawity был прав, что корень проблемы заключался в том, что rsyslog считывал сообщения из журнала systemd, используя как imuxsock, так и imjournal, но простого отключения ForwardtoSyslog для journald было недостаточно, чтобы остановить дубликаты.

Вместо этого мне нужно было настроить rsyslog так, чтобы он пересылал сообщение, полученное из imjournal, только на центральный сервер журналов, добавив условие $inputname == "imjournal" к исходному if-выражению, т.е.:

module(load="imjournal" StateFile="journalState" IgnorePreviousMessages="on")
module(load="mmjsonparse")
    
template(name="foobarJSON" type="string" string="%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n" )

if $inputname == "imjournal" and $syslogfacility-text == "user" and $programname == "foobar" then {
    action(type="mmjsonparse")
    user.* action(type="omfwd" target="central-logs.server" port="514" protocol="tcp" template="foobarJSON")
}

Кроме того, я понял, почему я получал эти пустые сообщения: я забыл фактически вызвать действие mmjsonparse, чтобы разобрать структурированное сообщение журнала и получить все отдельные поля из сообщения journald, поэтому я добавил эту строку в свой рабочий пример конфигурации выше.

Ответ или решение

Почему rsyslog записывает дублирующиеся сообщения из системного журнала systemd?

Вопрос о том, почему rsyslog может записывать дублирующиеся сообщения из системного журнала systemd, имеет несколько возможных причин, которые зависят от настроек и конфигураций вашей системы. Ниже представлены ключевые аспекты, которые помогут понять и устранить эту проблему.

Основные причины дублирования сообщений

  1. Виртуальные механизмы ввода rsyslog: Как выяснили клиенты, rsyslog мог использовать одновременно несколько модулей ввода для записи сообщений в журнал, таких как imuxsock (классический syslog) и imjournal (для работы с системным журналом). Это может привести к тому, что одно и то же сообщение будет записано несколькими способами.

  2. Настройки журнального демона systemd: Использование параметра ForwardToSyslog=yes в файле конфигурации journald.conf может вызывать дополнительные записи. Это приводит к тому, что systemd отправляет сообщения как в собственный журнал, так и в syslog, создавая тем самым дубли.

  3. Ошибка в конфигурации rsyslog: Неправильные условия фильтрации в конфигурации rsyslog также могут привести к дублированию. Например, если фильтрация по имени входного модуля не настроена, то сообщения могут обрабатываться дважды.

Решения и исправления

Для устранения проблемы с дублированием сообщений следует обратить внимание на правильность настроек.

  1. Отключение ForwardToSyslog: Убедитесь, что в конфигурационном файле journald.conf установлен параметр ForwardToSyslog=no. Это предотвратит дублирование сообщений, отправляемых от systemd в syslog.

  2. Корректная фильтрация в rsyslog:

    • Обновите конфигурацию rsyslog, чтобы при обработке сообщений, получаемых через imjournal, использовать условие $inputname == "imjournal". Это остановит обработку сообщений, приходящих через другие механизмы, такие как imuxsock.

    Пример обновленной конфигурации:

    module(load="imjournal" StateFile="journalState" IgnorePreviousMessages="on")
    module(load="mmjsonparse")
    
    template(name="foobarJSON" type="string" string="%TIMESTAMP% %HOSTNAME% %syslogtag% @cee: %$!all-json%\n")
    
    if $inputname == "imjournal" and $syslogfacility-text == "user" and $programname == "foobar" then {
       action(type="mmjsonparse")
       user.* action(type="omfwd" target="central-logs.server" port="514" protocol="tcp" template="foobarJSON")
    }
  3. Проверка на наличие пустых сообщений: Обеспечьте правильное использование модуля mmjsonparse. Если вы видите пустые сообщения, убедитесь, что модуль правильно вызывался для обработки сообщений перед отправкой.

Заключение

Решение проблемы с дублированием сообщений в rsyslog требует комплексного подхода, включая адекватные настройки на стороне systemd и правильную конфигурацию rsyslog. Настоящие изменения, предлагаемые выше, существенно помогут вам оптимизировать сбор логов и избежать дальнейшего дублирования данных. Регулярная проверка логов и адекватность конфигураций также будет предотвращать возникновение подобных проблем в будущем.

Оцените материал
Добавить комментарий

Капча загружается...