Почему весь вывод моей C программы, направленный в stdout, отправляется в journald?

Вопрос или проблема

Я работаю с дистрибутивом Linux на базе Yocto. Я не являюсь экспертом в systemd и systemd-journald.
Моя C программа my_c_program запускается при загрузке с помощью скрипта my_script.sh. Ниже приведён файл my_script.sh:

my_c_program &
echo $! > /dev/shm/my_c_program.pid

Предыдущий скрипт запускается сервисом. Файл единицы сервиса называется start_c_program.service. Ниже приведён файл единицы сервиса:

[Unit]
Description=Запуск my_c_program
Requires=...
After=...
Before=...

[Service]
Type=forking
ExecStart=/usr/bin/my_script.sh
PIDFile=/dev/shm/my_c_program.pid

[Install]
WantedBy=multi-user.target

С этой конфигурацией все инструкции printf("message"), присутствующие в my_c_program, добавляют строку "message" в systemd-journald.
Я знаю, что если я изменю my_script.sh на:

my_c_program > /dev/null &
echo $! > /dev/shm/my_c_program.pid

сообщения в journald подавляются, но вопрос в следующем:
почему весь вывод моей C программы, направленный в stdout, отправляется в journald?

Спасибо


Я думал, что для отправки сообщения в journald мне нужно использовать инструкцию C syslog(), например, с кодом ниже:

#include<syslog.h>
int main(int argc, char** argv) {
    syslog(LOG_INFO, "Начало логирования");
}

Это особенность дизайна systemd и на самом деле более распространена в современном программном обеспечении.

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

Многие программы не знают, как писать в syslog, и это немного сложнее, чем просто записывать в stdout/stderr. Syslog никогда не был полностью повсеместным, и такие программы ранее могли перенаправлять свой stdout/stderr в файл логов в var log.

Когда systemd запускает вашу программу, он перенаправляет stdout и stderr в journald, заменяя файловые дескрипторы процесса перед запуском вашей программы.

Systemd соединяет стандартный вывод выполняемых процессов с своим журналом. Стандартный вывод унаследован всеми дочерними процессами, поэтому ваша C программа выводит информацию в журнал. Вы можете использовать параметр StandardOutput=, чтобы перенаправить стандартный вывод вашей программы в другое место.

Ответ или решение

Ваш вопрос о том, почему весь вывод вашего C-программы, направленный на стандартный вывод (stdout), отправляется в journald, интересен и поднимает важные аспекты работы современных систем и приложений под управлением systemd.

Основная причина заключается в том, что systemd по умолчанию перенаправляет стандартный вывод и стандартный вывод ошибок (stderr) всех сервисов, которые он управляет, в систему ведения журналов journald. Это сделано для упрощения ведения журналов и унификации подхода к обработке логов в системах, использующих systemd.

  1. Процесс управления выводом:
    Когда вы запускаете вашу программу через service unit в systemd, он автоматически перенаправляет stdout и stderr вашей программы в journald, заменяя дескрипторы файлов процесса. Это означает, что любые сообщения, которые ваша программа выводит через printf, будут захвачены и записаны журналом systemd.

  2. Современные подходы к ведению журналов:
    Современные подходы к разработке программного обеспечения предполагают, что приложения не должны самим решать, куда отправлять журналы. Вместо этого систему ведения журналов управляет этим процессом. Таким образом, программы могут просто писать свои выводы в stdout и stderr, а система, такая как systemd, решит, как и куда их записать. Это также особенно актуально для контейнеризованных приложений, работающих в Docker или Kubernetes.

  3. Настройка перенаправления вывода:
    Если вам нужно изменить это поведение, вы можете воспользоваться параметром StandardOutput в вашем unit-файле. Например:

    [Service]
    StandardOutput=null

    Это перенаправит вывод вашей программы в "черную дыру", и вы не увидите никаких сообщений в journald. Также вы можете указать различные варианты перенаправления, такие как file:/путь/к/файлу для записи вывода в файл.

  4. Использование syslog:
    Как вы упомянули, использование функции syslog() для записи сообщений в системный журнал также возможно, но это дополнительная сложность, и не все программы написаны с учетом этого. Многие приложения попросту выводят свои сообщения в стандартный вывод или стандартный вывод ошибок, полагаясь на systemd для управления логированием.

Таким образом, вывод вашего C-программы отправляется в journald именно из-за особенностей управления процессами systemd и концепции ведения журналов в современной инфраструктуре Linux. Если вы хотите изменить это поведение, рассмотрите возможность редактирования unit-файла вашего сервиса, используя доступные параметры перенаправления вывода.

Оцените материал
Добавить комментарий

Капча загружается...