====== Журналы / логи ======
===== journalctl =====
Управление сервисами в т.ч. и логами в системе, происходит системой инициализации **systemd**.\\
Хранит журналы в бинарном виде. Находится выше по иерархии чем **syslogd** и принимает события от него в т.ч.
* **-f** - выводить новые сообщения в реальном времени.
* **-e, --pager-end** - только последние сообщения.
* **-n** - кол-во строк.
* **-x, --catalog (--list-catalog)** - добавляет пояснения (максимальный уровень подсказок).
* **-u, --unit** - выбранный сервис.
* **-k, --dmesg** - сообщения только ядра (аналог **dmesg**).
* **--system** - только системные сообщения.
* **-b (--list-boots)** - логи последней загрузки (список доступных загрузок).
* **-o** - формат вывода логов (json-pretty, verbose, cat и т.д.).
* **-p** - приоритет.
==== Управление файлами ====
Задается максимальное доступное место на диске, по достижении, сообщения удаляются с конца.\\
Задается в параметрах **SystemMaxUse=** и **RuntimeMaxUse=** в файле **/etc/systemd/journal.conf**.
:!: Последняя загрузка системы/перезапуск
Перезагрузка считается инициированной входом в нее псевдопользователя "reboot"\\
# Врмя последней загрузки
who -b
# История логинов
last [имя пользователя]
# Так к вопросу о перезагрузке
last -x | head | tac
или
last reboot
# (подвопросом) Список зарегистрированных загрузок системы
journalctl --list-boots
# более подробная инфа
journalctl -b {num} -n
===== Rsyslog =====
[[https://www.rsyslog.com/|Оф сайт]]\\
[[https://rsyslog.readthedocs.io/en/latest/configuration/modules/index.html|Тут тоже неплохая дока]]
[[https://www.k-max.name/linux/rsyslog-na-debian-nastrojka-servera/|Rsyslog на Debian, настройка сервера сбора логов]]\\
[[https://selivan.github.io/2017/02/07/rsyslog-log-forward-save-filename-handle-multi-line-failover.html|Конфигурация Rsyslog]]\\
[[http://devel.aanet.ru/rsyslog-v5/property_replacer.html|Заменитель свойств]]\\
Замена старой **syslog**, принимает и обрабатывает лог-записи, есть несколько вариантов входа, в основном псевдоустройство **/dev/log**, так же может брать из файлов, сети и т.д., регулируется подключаемыми модулями\\
Конфигурация в файле **/etc/rsyslog.conf**, либо "/etc/rsyslog.d/50-default.conf", так же подтягиваются файлы *.conf из папки **/etc/rsyslog.d**, для пользовательской конфигурации.\\
При сетевой передаче рекомендуется использовать протокол **Relp**, специальный для этой утилиты, более надежный в сравнении с **tcp**.\\
Формат **RainerScript** позволяет задавать С-подобные правила обработки сообщений. **Со старыми директивами** могут быть проблемы, поэтому **не следует использовать его с устаревшими директивами**\\
Обработка происходит в блоках **RuleSet**, все что не входит в эти блоки, входит в блок по умолчанию.\\
Так же, поступающие сообщения **парсятся**, так же есть парсер по умолчанию, извлекает **части сообщения**, типа $msg, $rawmsg, $fromhost, $syslogtag, $programname и т.д.\\
Для остановки процесса после обработки команда **stop**\\
Некоторые модули для использования в действиях ()
* omfile - вывод файла
* omfwd - сетевая переадресация по udp или tcp
* omrelp - сетевая переадресация по протоколу RELP
* onmysql , ompgsql , omoracle — вывод в базу данных
:!: Примеры
Запишите все сообщения средств auth и authpriv в файл /var/log/auth.logи продолжите обработку этих сообщений:
# legacy
auth,authpriv.* /var/log/auth.log
# modern
if ( $syslogfacility-text == "auth" or $syslogfacility-text == "authpriv" ) then {
action(type="omfile" file="/var/log/auth.log")
}
Записать все сообщения с именем программы, начинающимся с «haproxy» в файл /var/log/haproxy.log, не сбрасывать буфер после каждого сообщения и прекратить дальнейшую обработку:
# legacy (note the minus sign in front of filename - it disables buffer flush)
:programname, startswith, "haproxy", -/var/log/haproxy.log
& ~
# modern
if ( $programname startswith "haproxy" ) then {
action(type="omfile" file="/var/log/haproxy.log" flushOnTXEnd="off")
stop
}
# we can mix legacy and modern
if $programname startswith "haproxy" then -/var/log/haproxy.log
&~
Простой вариант условия
if $syslogtag == 'example' then /var/log/test/out.log
# Либо легаси подход
:programname, contains, "MyProgram" /var/log/MyProgram.log
Для вывода сообщений можно использовать **шаблон**, задается директивой ([[http://devel.aanet.ru/rsyslog-v5/rsyslog_conf_templates.html|Тут есть описание]])
* Старый формат - $template DynFile,"/var/log/system-%HOSTNAME%.log"
* Новый формат - template(name="myMsg" type="string" string="\n%msg%\n") - **Не работает внутри If'a**
:!: Имена файлов
Вариант чтения всех файлов по маске и сохранения оригинального имени на выходе
input(type="imfile" File="/srv/myapp/logs/*.log" Tag="myapp__" Ruleset="myapp_logs" addMetadata="on")
ruleset(name="myapp_logs") {
set $.suffix=re_extract($!metadata!filename, "(.*)/([^/]*)", 0, 2, "all.log");
# Либо можно функцией field()
#set $.originfilename=field($!metadata!filename, 47, 7);
call sendToLogserver
}
Динамические имена файлов на выходе
# Легаси подход
$template DynFile, "/var/log/test/test-%syslogtag%.log"
*.* ?DynFile;myTemlpate
# Новый подход
template (name="DynFile" type="string" string="/var/log/test/test-%syslogtag%.log")
action(type = "omfile" dynaFile="DynFile" template="myTemlpate")
:!: Еще пример
Сервер
$MaxMessageSize 64k
module(load = "imfile" mode="inotify")
module(load = "omrelp")
# Вход из файлов, отмечаем его тегами
input(type="imfile" File="/fold/BIN/Import/*/log/*.log" Tag="SendImport")
input(type="imfile" File="/fold/BIN/ErrImport/*/log/*.log" Tag="SendErrImport")
# Из метаданных файла берем имя файла и название папки оно же название импорта
set $.filename=field($!metadata!filename, 47, 7);
set $.importname=field($!metadata!filename, 47, 5);
# Формат выходного сообщения. К sysтегу добавляем имя импорта и имя папки
template(name="outFormatMessage" type="string" string="<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag%%$.importname%__%$.filen$
# Отправляем по сети
if ($syslogtag == 'SendImport') then {
action(type="omrelp" Target="10.0.0.0" Port="20514" Template="outFormatMessage")
stop
}
if ($syslogtag == 'SendErrImport') then {
action(type="omrelp" Target="10.0.0.0" Port="20515" Template="outFormatMessage")
stop
}
Клиент
$MaxMessageSize 64k
module(load="imrelp")
input(type="imrelp" port="20514" ruleset="MImport")
input(type="imrelp" port="20515" ruleset="MErrImport")
# Формат выходного сообщения
template(name="outFormatMessage" type="string" string="%msg%\n")
# Динамическое имя файла
template(name="ImportFileName" type="string" string="/fold/ImportLogs/Import/%$.ffilename%")
template(name="ErrImportFileName" type="string" string="/fold/ImportLogs/ErrImport/%$.ffilename%")
ruleset(name="MImport") {
# Извлекаем из переданных данных имя файла и сервиса
set $.ffilename = replace($programname, "__", "/");
set $.ffilename = replace($.ffilename, "SendImport", "");
# Сохраняем в файл
action(type ="omfile" dynaFile="ImportFileName" template="outFormatMessage"
fileOwner="AppServer" fileGroup="AppServer" dirOwner="AppServer" dirGroup="AppServer"
dirCreateMode="0775" FileCreateMode="0664")
}
ruleset(name="MErrImport") {
# Извлекаем из переданных данных имя файла и сервиса
set $.ffilename = replace($programname, "__", "/");
set $.ffilename = replace($.ffilename, "SendErrImport", "");
# Сохраняем в файл
action(type ="omfile" dynaFile="ErrImportFileName" template="outFormatMessage"
fileOwner="AppServer" fileGroup="AppServer" dirOwner="AppServer" dirGroup="AppServer"
dirCreateMode="0775" FileCreateMode="0664")
}
===== Ротация файлов. Logrotate =====
[[https://www.opennet.ru/man.shtml?topic=logrotate&category=8&russian=0|Есть описание параметров]]\\
[[https://mnorin.com/logrotate-nastrojka-rotatsii-logov.html|Гораздо более полный перечень параметров]]\\
Утилита **Logrotate**, основная конфигурация **/etc/logrotate.conf**, в папке **/etc/logrotate.d/** отдельные конфиги\\
Сама утилита запускается раз в день, в планировщике есть файл- **/etc/cron.daily/logrotate**\\
Без порядковых номеров ротация перестает работать\\
Основной конфиг запускается раз в день, поэтому **часовой интервал игнорируется**, для часа можно поместить в **/etc/cron.hourly/**, для меньшего интервала нужно создать отдельный конфиг (в другом месте для того чтобы не пересекаться с ежедневным), смысл в том чтобы запускать ее через крон самостоятельно, для этого настроим задачу:\\
# Создали файл конфига
nano /home/sammy/logrotate.conf
# Запускаем вручную (-d для тестирования)
logrotate /home/sammy/logrotate.conf [--verbose --force]
# Добавляем в крон
"15 * * * * /usr/sbin/logrotate /home/sammy/logrotate.conf"
Ротировать можно как регулярно (**по времени**) так и **по размеру** файла\\
Можно выполнять скрипты до и после ротации\\
Параметры:\\
* **hourly/daily/weekly/monthly** - периоды
* **rotate 3** - хранить 3 последних файла
* **size** - планка размера для ротирования (size 100, size 100k, и size 100M)
* **compress** - сжимать
* **delaycompress** - кроме последнего и предпоследнего
* **dateext** - к имени архивного файла добавляется дата ротации в формате (%Y%m%d) вместо номера
* **copytruncate** - ротируется копия, оригинал урезается
* **create** - ротируется оригинал, рабочий создается новый
:!: Образец конфига
/var/log/messages # файл для работы, можно указать маску
{
daily
rotate 3 # хранить 3 последних файла
compress # сжимать
delaycompress # кроме последнего и предпоследнего
dateext # к имени архивного файла добавляется дата ротации в формате (%Y%m%d) вместо номера
}
Если переименовываем файл после ротации. **Его нужно перемещать** создавать копию, без номеров ротация перестает работать\\
/usr/zxbcps/files/zx.tar
{
rotate 3
sharedscripts # Для того чтобы скрипт выполнялся один раз
postrotate
mv /usr/zxbcps/files/zx.tar.1 /usr/zxbcps/files/zzx_$(date +%Y-%m-%d_%H:%M).tar
endscript
}