GitHub

Tensho

Заметки непутевого программиста

Linux System Logs

06/10/2020

В Linux логируется почти все – от событий ядра до пользовательских действий. В стандартной папке /var/log находятся логи операционной системы, сервисов, утилит и приложений. Для примера вот как выглядит папка на моем AWS workspace (Amazon Linux 2/CentOS):

$ ls -1a /var/log
.
..
amazon
audit
boot.log
btmp
btmp-20200910
chrony
cloud-init.log
cloud-init-output.log
cron
cron-20200405
cron-20200910
dmesg
dmesg.old
falconctl.log
falcon-sensor.log
falcon-sensor.log-20200911
grubby
grubby_prune_debug
journal
lastlog
maillog
maillog-20200405
maillog-20200910
messages
messages-20200405
messages-20200910
pcoip-agent
samba
secure
secure-20200405
secure-20200910
skylight
spooler
spooler-20200405
spooler-20200910
tallylog
wtmp
Xorg.100.log
Xorg.100.log.old
yum.log

Тут можно найти лог-файлы cloud-init сервиса (/var/log/cloud-init.log), cron сервиса (/var/log/cron), yum утилиты (/var/log/yum.log) и многих других. Некоторые сервисы и приложения придерживаются конвенции писать логи в /var/log папку, а некоторые нет. Например, SumoLogic коллектор пишет логи по месту установки в /opt/SumoCollector/logs по умолчанию. Однако, есть лог-файлы относящиеся непосредственно к активностям самой операционной системы:

Идеологически во всех дистрибутивах Linux логирование различных системных модулей и сервисов является централизованным. Обычно это отдельно поднятый демон, который слушает на каком-то порту входящие лог-сообщения согласно определенному протоколу и записывает их в вышеупомянутые файлы. Одним из древнейших таких протоколов является Syslog.

Syslog

Syslog

Syslog является стандартом логирования системных событий. Любой софт на вашей системе может дернуть syslog(3) (libc) и отправить сообщение syslogd сервису, а точнее его конкретной имплементации – rsyslogd или syslog-ng . Например, в Ruby это можно сделать с помощью вызова Syslog::log метода:

require 'syslog'
Syslog.open("huston", Syslog::LOG_PID, Syslog::LOG_LOCAL0)
Syslog.log(Syslog::LOG_CRIT, "we have a problem")

В любой оболочке есть команда logger, которая тоже позволяет отправить системное сообщение:

$ logger -p local0.crit we have a problem

Соответственно увидеть его можно прочитав /var/log/messages файл:

$ sudo grep "we have a problem" /var/log/messages
Oct 06 09:00:00 a-2sw1oqjfy7pwo workspaces\alice: we have a problem

Cогласно RFC 5424 протокол Syslog сообщение содержит следующие поля (заголовки):

По умолчанию Syslog слушает на локальном Unix сокете (imuxsock), но можно легким движением руки раскомментировать соответствующие модули в /etc/rsyslog.conf конфигурационном файле, которые позволят слушать входящие сообщения на TCP/UDP сокетах (imtcp/imudp).

$ head -n 20 /etc/rsyslog.conf
# rsyslog configuration file

# For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html
# If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html

#### MODULES ####

# The imjournal module bellow is now used as a message source instead of imuxsock.
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imjournal # provides access to the systemd journal
#$ModLoad imklog # reads kernel messages (the same are read from journald)
#$ModLoad immark  # provides --MARK-- message capability

# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514

# Provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514

Все это просто и понятно, но мы то с вами знаем, что многие современные Linux дистрибутивы перешли на другую логирующую систему.

Journal

Journal

Современные CentOS, Ubuntu и другие распространенные серверные Linux дистрибутивы поставляются вместе с подсистемой инициализации и управления службами Systemd. Systemd имплементирует собственный сервис логирования Journald, который может заменять или дополнять Syslog. Journald сервис принимает сообщения из множества разных источников помимо системного вызова syslog(3) – буфера ядра (kmsg aka syslog(2)), sd_journal_print(3), STDOUT/STDERR systemd модулей (units).

Journal Sources

В отличии от ограниченного набора Syslog полей, Journal предусматривает их расширенные метаданные, структурированние и индексирование, что позволяет осуществлять более гибкий и быстрый поиск.

Давайте попробуем отправить что-то в journald с помощью journald-native Ruby гема:

$ gem install journald-native
require 'journald/native'
Journald::Native.send "MESSAGE=we have a problem", "PRIORITY=#{Journald::LOG_CRIT}"

и прочитать из него с помощью journalctl:

$ journalctl -q | grep "we have a problem"
Oct 06 10:00:00 a-2sw1oqjfy7pwo workspaces\alice[28963]: we have a problem

Любопытно, что это же сообщение можно найти не только в журнале, но и в аутентичном /var/log/messages:

$ sudo grep "we have a problem" /var/log/messages
Oct 06 10:00:00 a-2sw1oqjfy7pwo workspaces\alice: we have a problem

Но как лог-записи из Journal попадают в Syslog? Обратите внимание на упомянутый конфигурационный файл для rsyslog выше, где подключен еще один модуль – imjournal:

$ModLoad imjournal # provides access to the systemd journal

С этим включенным модулем rsyslog периодически реплицирует Journal лог-записи журнала в Syslog файл. При этом структурированные поля приводятся к удовлеворимому Syslog формату. Если этого не треубется и работа идет только со стандартными Syslog полями, то лучше использовать режим локального сокета (imuxsock) по умолчанию для увеличения производительности. Однако, на практике заранее не известно, будут ли писать приложения структурированные логи или нет. Думаю поэтому этот модуль включен из коробки.

Journal хранит свою базу данных в сжатом формате и стандартными Linux утилитами ее не прочитать, кроме как с помощью journalctl:

$ tree /var/log/journal
/var/log/journal
└── be1d75b91fbc4a9bb1721c95179d55da
    ├── system@93fd5ed132c24d49892e6c357e377949-0000000000000001-0005a25fd7171e09.journal
    ├── system.journal
    ├── user-67163.journal
    └── user-67198.journal
$ sudo head -n 1 /var/log/journal/be1d75b91fbc4a9bb1721c95179d55da/system.journal
  LPKSHHRHa.� p�f���SD�G�Gp��p���M��M���"��"x��x��Xo<Xo<8�+8�+XTXT��d��d������...

Еще одним любопытным фактом является то, что Journal поддерживает именованные области (namespaces) для логической изоляции группы логов и увеличения производительности. По умолчанию все логи обрабатываются одним journald сервисом в рамках одной именованной области – default. Но можно определить некоторые логи в собственную именованную область.

Journal Namespaces

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

P.S. Я тут упоролся по PlantUML в последнее время. С ним делать простенькие диаграммы в разы быстрее, чем в специализированном графическом пакете вроде OmniGraffle. Попробуйте потыкать его палочкой на досуге.