Пример: «Модное приложение»

Пример: «Модное приложение»

У нас есть много производственных приложений (собственных и сторонних), которые оставляют ведение журнала на усмотрение процесса, запускающего приложение, и просто ведут журналы stdoutв INFOи stderrдля ERRORжурналов (т. е. всего 2 приоритета журналов: INFO|ERROR).

С помощью служебного модуля systemd для приложения это можно настроить следующим образом:

StandardOutput=journal
StandardError=journal

Это позволяет разработчикам управлять всем через модули systemd и журнал, чтобы обеспечить централизованный сбор журналов, мониторинг всего остального... и им не нужно беспокоиться о поиске и анализе различных журналов в разных форматах/местоположениях для каждого развертываемого ими приложения.

Журнал systemd имеет систему приоритетов сообщений, совместимую с 7-уровневой системой приоритетов сообщений syslog. INFOis level 6и ERRORis level 3. Более подробную информацию см. в ссылках.

Проблема в том, что... systemd/journal, по-видимому, не различает сообщения, записанные в журнал из stdout и stderr. Сообщения как stdout, так и stderr записываются в журнал с приоритетом по умолчанию 6 ( INFO).

Пример: «Модное приложение»

/opt/log-test.sh

#!/bin/bash

echo "This is ERROR" 1>&2
echo "This is INFO"

exit 0

/etc/systemd/system/log-test.service

[Unit]
Description=log test for journal

[Service]
Type=simple

ExecStart=/opt/log-test.sh

StandardOutput=journal
StandardError=journal
SyslogIdentifier=log-test

запустите его и проверьте журнал

$ systemctl start log-test
$ journalctl -u log-test
-- Logs begin at Thu 2022-04-07 08:17:16 UTC, end at Thu 2022-04-07 16:35:02 UTC. --
Apr 07 16:34:58 host.example.com systemd[1]: Started log test for journal.
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is ERROR
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is INFO
$ journalctl -u log-test -p 6   # syslog info priority
-- Logs begin at Thu 2022-04-07 08:17:16 UTC, end at Thu 2022-04-07 16:35:08 UTC. --
Apr 07 16:34:58 host.example.com systemd[1]: Started log test for journal.
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is ERROR
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is INFO
$ journalctl -u log-test -p 3   # syslog error priority
-- No entries --
$

Вы можете видеть, что сообщениям stderr и stdout присваивается приоритет 6( INFO) при записи в журнал.

Это проблема, поскольку у нас нет простого способа дифференцировать вывод на stdout и stderr при использовании stdio->journalв качестве основного средства ведения журнала.

Это былообсуждалось ранееирешениявозможны, ноне реализована. Я надеюсь, что команда systemd в конечном итоге реализует это, но пока мне нужно решение.

Нашел ли кто-нибудь разумное решение, чтобы сообщения, записанные в stdout и stderr, имели разные приоритеты в журнале?без изменения того, как приложение ведет журнал?

Я не хочу, чтобы все приложения, которые мы развертываем (не все написаны нами), были вынуждены реализовывать интеграцию журналов или системных журналов для получения приоритета журнала, когда нам на самом деле нужны только два уровня: INFO(stdout) и ERROR(stderr).

Большая часть того, что мы развертываем, не контейнеризирована, поэтому полагаться на возможности контейнеризации также не является для нас решением.

Наличие по умолчанию разных приоритетов для stderr и stdout, направляемых в журнал/syslog, имеет решающее значение для упрощения мониторинга ошибок распределенного журнала (при условии соблюдения хорошей гигиены разработчиками и записи в stderr только тех вещей, которые требуют внимания).

Использованная литература:

решение1

Если вам нужно использовать stdout/ stderr, вы можете использоватьsd-daemon префикс ведения журнала.

Добавьте к нему stderr, <3>чтобы отправить ERRORприоритетный journaldжурнал.

Используя ваш log-test.shи log-test.service:

#!/bin/bash

>&2 echo "<3>This is ERROR"
echo "This is INFO"

exit 0

И journalctlвывод:

$ journalctl -u log-test -p 3
May 02 01:22:58 host.example.com log-test.sh[29909]: This is ERROR

Если у вас fancy-appесть API для записи syslog, вы можете использовать его для записи в UNIX-датаграмму /dev/log(обычно доступную для записи по умолчанию и регистрируемую в journald) вместо stdout/ stderr. Используйте тег syslog для идентификации вашего fancy-app, приоритета syslog errorили infoв зависимости от ваших потребностей, а также любого средства syslog.

Например, в Bash мы можем использоватьlogger:

# emit INFO message to journalctl
$ logger -t fancy-app -u /dev/log -p user.info "This is INFO"

# emit ERROR message to journalctl
$ logger -t fancy-app -u /dev/log -p user.error "This is ERROR"

# show journald messages for fancy-app
$ journalctl -t fancy-app
May 02 01:23:38 host.example.com fancy-app[27302]: This is INFO
May 02 01:23:39 host.example.com fancy-app[27303]: This is ERROR

# show journald ERROR messages for fancy-app
$ journalctl -t fancy-app -p 3
May 02 01:23:39 host.example.com fancy-app[27303]: This is ERROR

Обратите внимание, что в большинстве дистрибутивов journaldзаписи обычно перенаправляются локальному демону syslog ( syslog-ng, rsyslog, ...), поэтому, вероятно, проверьте фильтры syslog или, возможно, используйте local0... local7средства.

У нас есть много производственных приложений (собственных и сторонних), которые оставляют ведение журнала на усмотрение контейнера и просто выводят журналы INFO на stdout и ERROR на stderr (т. е. всего 2 приоритета журнала: INFO|ERROR).

Большинство контейнерных движков должны уметь логировать в syslog. Не зная вашего контейнерного движка, я буду использовать Docker в качестве примера.

У Докера естьдрайвер ведения журнала syslogкоторый может быть использован для отправки сообщений журнала с использованием формата syslog на любую цель syslog. Вы должны иметь возможность войти в систему journaldс помощью чего-то вроде:

docker run \
    --log-driver syslog \
    --log-opt syslog-address=unix:///dev/log \
    --log-opt syslog-facility=user \
    --log-opt tag=fancy-app \
    fancy-app:latest

У Докера также естьдрайвер журналирования journaldдоступно. Например:

docker run \
    --log-driver journald \
    --log-opt tag=fancy-app \
    fancy-app:latest

Оба драйвера регистрации (системный журналижурналd) поддерживает разделение между stdoutи stderr; т. е. stdoutсообщения будут регистрироваться с INFOприоритетом, а stderrсообщения будут регистрироваться с ERRORприоритетом.

Оставив в стороне философию и флеймовые войны, почему бы не вести журнал в реальном syslog? Это проще, хранится в текстовом формате и, как правило, поддерживается программным обеспечением для управления журналами (см.Грейлог,Logstash,Papertrail).

Связанный контент