Вопрос или проблема
У меня есть небольшой сервис, написанный на C на Debian.
Этот сервис автоматически запускается с Linux и выполняет некоторые операции с файлами и другие задачи, как и ожидается.
Сервис выводит некоторые информационные сообщения, а также сообщения об ошибках в стандартный вывод. Это видно в консольном окне, когда я запускаю бинарник из консоли, а не как сервис.
Единственное, что мне пока не удалось сделать, это записать его вывод в журнал, когда бинарник запускается как сервис.
Я просмотрел все найденные результаты поиска, я запрашиваю журнал от имени root и вижу системные сообщения о запуске/остановке сервиса, но ничего из того, что выводит бинарник сервиса.
Я просто вывожу с помощью printf("hey this should appear in the journal");
– но в журнале ничего не видно.
Согласно тому, что объясняется везде, весь вывод сервиса должен автоматически перенаправляться в журнал, верно?
Что я мог упустить, чтобы это не происходило?
Правка
Я нашел специальные функции для ведения логов, но на самом деле мне нравится идея автоматически получать стандартный вывод либо в консоль, либо в журнал, в зависимости от того, как я запускаю бинарник.
Я попробовал сервис на bash и обнаружил, что он пишет сообщения echo
в журнал, как и ожидалось.
Когда запускается с использованием systemd, стандартный вывод юнита идет туда, что указано в настройках конфигурации StandardOutput=
юнита. По умолчанию это значение DefaultStandardOutput=
системной конфигурации, и оно по умолчанию равно journal
. Таким образом, если ваша система использует настройки по умолчанию, стандартный вывод юнитов должен идти в журнал.
Для любого данного юнита вы можете проверить эту настройку, запустив
systemctl show -P StandardOutput yourunit
(заменив yourunit
на соответствующий).
Одно из вещей, которые следует проверить, заключается в том, сбрасывает ли ваша программа свой вывод: при использовании printf
вам нужно включить символ новой строки (\n
) или явно вызвать fflush
.
В общем, сообщения журнала следует записывать с помощью syslog
, а не отправлять в стандартный вывод; см. Правильный способ написать код на C, который вставляет сообщение в /var/log/messages? для получения подробностей.
Ответ или решение
Чтобы ваш сервис на C, запущенный как systemd служба, записывал вывод в журнал, вам нужно убедиться, что он правильно настраивает стандартный вывод, а также что ваши сообщения выводятся корректно. Вот пошаговое руководство по решению вашей проблемы:
-
Проверьте конфигурацию unit-файла systemd.
Убедитесь, что ваш unit-файл службы (например,/etc/systemd/system/ваш_сервис.service
) имеет следующие строки:[Service] ExecStart=/путь/к/вашему/бинарному_файлу StandardOutput=journal StandardError=journal
По умолчанию
StandardOutput
иStandardError
должны проходить в журнал, но рекомендуется явное указание для уверенности. -
Проверьте настройку systemd.
Выполните следующую команду, чтобы проверить текущее значение стандартного вывода для вашей службы:systemctl show -p StandardOutput ваш_сервис
Убедитесь, что значение
StandardOutput
установлено вjournal
. -
Флешинг вывода.
В вашем коде, если вы используетеprintf
, убедитесь, что вы добавляете символ новой строки\n
в конце строки или вызываетеfflush(stdout);
. Это важно, так как стандартный вывод может быть буферизован, и вывод может не появляться в журнале, если буфер не сброшен.Пример кода:
printf("hey, this should appear in the journal\n"); fflush(stdout); // Сбрасываем буфер
-
Запуск и проверка службы.
После внесения изменений в unit-файл, перезапустите службу, чтобы изменения вступили в силу:sudo systemctl daemon-reload sudo systemctl restart ваш_сервис
-
Проверка журнала.
Проверьте вывод вашей службы в журнале с помощью:journalctl -u ваш_сервис
Вы должны увидеть сообщения, которые выводит ваш сервис.
-
Использование syslog (необязательно).
Хотя использование стандартного вывода должно работать, рекомендуется использовать системные функции для логирования, такие какsyslog()
, в производственных системах. Это обеспечит лучшую совместимость и возможность настройки уровня логирования.
Пример использования syslog
:
#include <stdio.h>
#include <syslog.h>
void log_message(const char *message) {
openlog("ваш_сервис", LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_INFO, "%s", message);
closelog();
}
int main() {
log_message("hey, this should appear in the journal");
return 0;
}
Следуя этим шагам, вы должны увидеть записи вашего сервиса в журнале systemd.