Вопрос или проблема
У меня есть небольшой сервис, написанный на C под Debian.
Этот сервис автоматически запускается с Linux и выполняет некоторые операции с файлами и другие ожидаемые задачи.
Сервис выводит некоторые информационные сообщения и также сообщения об ошибках в стандартный вывод. Это видно в консольном окне, когда я запускаю бинарный файл из консоли, а не как сервис.
Единственное, что мне пока не удалось сделать, это записать его вывод в журнал, когда бинарный файл запускается как сервис.
Я прошелся по всем найденным материалам, я выполняю запрос журнала от имени root и вижу системные сообщения о начале/остановке сервиса, но ничего из того, что печатает бинарник сервиса.
Я просто вывожу с помощью printf("привет, это должно появиться в журнале");
– но в журнале ничего не видно.
Согласно тому, что объясняется повсюду, весь вывод сервиса должен автоматически направляться в журнал, верно?
Что я могу пропустить, чтобы это не произошло?
Правка
Я нашел специальные функции для ведения журнала, но мне на самом деле нравится идея получать стандартный вывод автоматически, либо в консоли, либо в журнале, в зависимости от того, как я запускаю бинарный файл.
Я пробовал сервис на bash-скрипте и заметил, что он записывает сообщения echo
в журнал, как и ожидалось.
При запуске с использованием systemd стандартный вывод юнита направляется туда, куда указывает настройка StandardOutput=
. По умолчанию это значение, заданное в системной конфигурации DefaultStandardOutput=
, а это по умолчанию равно journal
. Поэтому, если ваша система использует настройки по умолчанию, стандартный вывод юнитов должен идти в журнал.
Для любого данного юнита вы можете проверить эту настройку, выполнив
systemctl show -P StandardOutput вашюнит
(заменив вашюнит
на соответствующее значение).
Одно из вещей, которые стоит проверить, – это очищает ли ваша программа свой вывод: с помощью printf
вам нужно включить символ новой строки (\n
) или явно вызвать fflush
.
В общем случае сообщения журнала должны записываться с использованием syslog
, а не отправляться в стандартный вывод; см. Правильный способ написания кода на C, который вставляет сообщение в /var/log/messages? для подробностей.
Ответ или решение
Чтобы вывод вашего сервиса на языке C отображался в системном журнале, когда запущен как служба в системе, вам нужно учесть несколько моментов.
1. Конфигурация сервиса systemd:
Когда служба запускается через systemd, стандартный вывод (stdout) и стандартный поток ошибок (stderr) должны перенаправляться в журнал по умолчанию. Для этого в файле конфигурации службы (юнит-файле) проверьте настройки StandardOutput
и StandardError
. Обычные настройки по умолчанию направляют вывод в журнал. Вы можете использовать следующую команду для проверки текущих настроек вашего юнит-файла:
systemctl show -P StandardOutput имя_вашей_службы
systemctl show -P StandardError имя_вашей_службы
Если настройки не равны journal
, вы можете задать их явно в своем юнит-файле:
[Service]
ExecStart=/path/to/your/executable
StandardOutput=journal
StandardError=journal
Не забудьте перезагрузить конфигурации systemd:
sudo systemctl daemon-reload
2. Поток вывода:
Когда вы используете printf
, убедитесь, что вывод буферизуется должным образом. Как правило, при отсутствии новой строки (\n
) или явного вызова fflush(stdout)
, данные могут не поступать в журнал. Например:
printf("Привет, это сообщение должно появиться в журнале.\n");
Либо:
printf("Привет, это сообщение должно появиться в журнале.");
fflush(stdout);
Это гарантирует, что данные попадают в поток вывода вовремя.
3. Альтернативный подход: использование syslog:
Если вы хотите более надежный и стандартный способ ведения логов, рассмотрите возможность использования библиотеки syslog
. Это позволит вашему приложению записывать сообщения непосредственно в системный журнал (например, /var/log/syslog
). Пример использования:
#include <syslog.h>
int main() {
// Открыть syslog
openlog("Имя программы", LOG_PID|LOG_CONS, LOG_USER);
// Запись сообщения в syslog
syslog(LOG_INFO, "Привет, это сообщение в syslog.");
// Закрытие syslog
closelog();
return 0;
}
4. Проверка логов:
После внесения изменений можно проверить логи с помощью:
journalctl -u имя_вашей_службы
Таким образом, следуя этим шагам, вы сможете отправлять вывод вашего сервиса на языке C в системный журнал, как при его запуске как службы, так и из консоли.