Вопрос или проблема
Я работаю с дистрибутивом 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.
-
Процесс управления выводом:
Когда вы запускаете вашу программу через service unit в systemd, он автоматически перенаправляет stdout и stderr вашей программы в journald, заменяя дескрипторы файлов процесса. Это означает, что любые сообщения, которые ваша программа выводит черезprintf
, будут захвачены и записаны журналом systemd. -
Современные подходы к ведению журналов:
Современные подходы к разработке программного обеспечения предполагают, что приложения не должны самим решать, куда отправлять журналы. Вместо этого систему ведения журналов управляет этим процессом. Таким образом, программы могут просто писать свои выводы в stdout и stderr, а система, такая как systemd, решит, как и куда их записать. Это также особенно актуально для контейнеризованных приложений, работающих в Docker или Kubernetes. -
Настройка перенаправления вывода:
Если вам нужно изменить это поведение, вы можете воспользоваться параметромStandardOutput
в вашем unit-файле. Например:[Service] StandardOutput=null
Это перенаправит вывод вашей программы в "черную дыру", и вы не увидите никаких сообщений в journald. Также вы можете указать различные варианты перенаправления, такие как
file:/путь/к/файлу
для записи вывода в файл. -
Использование syslog:
Как вы упомянули, использование функцииsyslog()
для записи сообщений в системный журнал также возможно, но это дополнительная сложность, и не все программы написаны с учетом этого. Многие приложения попросту выводят свои сообщения в стандартный вывод или стандартный вывод ошибок, полагаясь на systemd для управления логированием.
Таким образом, вывод вашего C-программы отправляется в journald именно из-за особенностей управления процессами systemd и концепции ведения журналов в современной инфраструктуре Linux. Если вы хотите изменить это поведение, рассмотрите возможность редактирования unit-файла вашего сервиса, используя доступные параметры перенаправления вывода.