# Журнали NetPulse звичайними файлами в /var/log/netpulse/. # # Ставиться в /etc/rsyslog.d/30-netpulse.conf # Разом із deploy/logrotate-netpulse і накладкою # deploy/docker-compose.journald.yml. # # ЧОМУ ЧИТАЄМО ЖУРНАЛ, А НЕ ПЕРЕХОПЛЮЄМО ПОТІК # # Очевидний шлях — драйвер `syslog` у докера: він шле рядки просто в # rsyslog. Але тоді докер їх у себе НЕ КЛАДЕ, і `docker logs` замовкає # назавжди. Людина, яка про це не знає, робить із мовчання висновок # «служба нічого не пише» — а це найгірший різновид помилки, бо він # виглядає як факт. # # Тому драйвер лишається journald, а rsyslog читає вже записане # (imjournal). Обидва шляхи працюють одночасно: `docker logs`, journalctl # і файли показують те саме. # # Ціна: рядок лежить у двох місцях — у журналі systemd і у файлі. На # стелі 1 ГБ у journald і ротації нижче це десятки мегабайтів, тобто # дешевше за годину пошуку причини без журналу. module(load="imjournal" StateFile="imjournal-netpulse.state" Ratelimit.Interval="0") # Розбираємо ТЕГ, а не метадані журналу. # # Перша спроба матчила $!CONTAINER_NAME — поле, яке journald справді # кладе (journalctl його бачить), але до правил rsyslog воно доходить # не завжди: залежить від того, чи прийшов рядок через imjournal, чи # через imuxsock, куди journald форвардить syslog. Каталог у нас # створився, правило не спрацювало жодного разу, і зовні це виглядало # як «rsyslog не працює» — хоча він працював, просто умова не збігалась. # # Тег `netpulse/<ім'я>` ми задаємо самі в накладці journald, і він # приїжджає звичайним syslog-тегом обома шляхами. Тобто умова тепер # спирається на те, що ми контролюємо, а не на те, що може не доїхати. # # `:10:$` бере тегу з десятого символу до кінця — рівно те, що після # `netpulse/`. template(name="netpulseLogFile" type="string" string="/var/log/netpulse/%programname%.log") # Формат: час у ISO, ім'я служби, саме повідомлення. # # %msg% без опцій навмисно. Спершу стояло # `%msg:::sp-if-no-1st-sp,drop-last-lf%` — і воно давало ПОРОЖНІЙ текст: # файли з'являлись, рядки в них були, але після імені служби не було # нічого. Тобто журнал виглядав робочим і не містив жодного слова — # найгірший різновид поломки. Пробіл між назвою й текстом ставимо # самі: journald його не лишає, і без нього рядок злипається в # «netpulse-api-1{"time":...» — читабельно для jq, але не для ока. # # Повідомлення в NetPulse — уже JSON від slog, тож обгортати його ще # однією структурою не треба: `jq` має отримати рядок, який він уміє # прочитати. Час і служба стоять ПЕРЕД ним, щоб `tail` лишався # читабельним для людини, а `cut -d" " -f3-` віддавав чистий JSON. template(name="netpulseLine" type="string" string="%timereported:::date-rfc3339% %programname% %msg%\n") # Умова — на ІМЕНІ КОНТЕЙНЕРА, яке докер кладе тегом (див. накладку # deploy/docker-compose.journald.yml). Метадані журналу ($!CONTAINER_NAME) # для цього не годяться: до правил rsyslog вони доходять не завжди, і # перша спроба на них мовчки не спрацювала. if ($programname startswith "netpulse-") then { action(type="omfile" dynaFile="netpulseLogFile" template="netpulseLine" dirCreateMode="0750" fileCreateMode="0640" dynaFileCacheSize="20") # stop, щоб ті самі рядки не поїхали ще й у /var/log/syslog: там # вони перемішаються з усім іншим на машині, а користі не додадуть. stop }