Вопрос или проблема
Почему 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, имеет несколько возможных причин, которые зависят от настроек и конфигураций вашей системы. Ниже представлены ключевые аспекты, которые помогут понять и устранить эту проблему.
Основные причины дублирования сообщений
-
Виртуальные механизмы ввода rsyslog: Как выяснили клиенты, rsyslog мог использовать одновременно несколько модулей ввода для записи сообщений в журнал, таких как
imuxsock
(классический syslog) иimjournal
(для работы с системным журналом). Это может привести к тому, что одно и то же сообщение будет записано несколькими способами. -
Настройки журнального демона systemd: Использование параметра
ForwardToSyslog=yes
в файле конфигурацииjournald.conf
может вызывать дополнительные записи. Это приводит к тому, что systemd отправляет сообщения как в собственный журнал, так и в syslog, создавая тем самым дубли. -
Ошибка в конфигурации rsyslog: Неправильные условия фильтрации в конфигурации rsyslog также могут привести к дублированию. Например, если фильтрация по имени входного модуля не настроена, то сообщения могут обрабатываться дважды.
Решения и исправления
Для устранения проблемы с дублированием сообщений следует обратить внимание на правильность настроек.
-
Отключение
ForwardToSyslog
: Убедитесь, что в конфигурационном файлеjournald.conf
установлен параметрForwardToSyslog=no
. Это предотвратит дублирование сообщений, отправляемых от systemd в syslog. -
Корректная фильтрация в 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") }
- Обновите конфигурацию rsyslog, чтобы при обработке сообщений, получаемых через
-
Проверка на наличие пустых сообщений: Обеспечьте правильное использование модуля
mmjsonparse
. Если вы видите пустые сообщения, убедитесь, что модуль правильно вызывался для обработки сообщений перед отправкой.
Заключение
Решение проблемы с дублированием сообщений в rsyslog требует комплексного подхода, включая адекватные настройки на стороне systemd и правильную конфигурацию rsyslog. Настоящие изменения, предлагаемые выше, существенно помогут вам оптимизировать сбор логов и избежать дальнейшего дублирования данных. Регулярная проверка логов и адекватность конфигураций также будет предотвращать возникновение подобных проблем в будущем.