Получение вывода в журнал в службе, написанной на C

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

У меня есть небольшой сервис, написанный на 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 служба, записывал вывод в журнал, вам нужно убедиться, что он правильно настраивает стандартный вывод, а также что ваши сообщения выводятся корректно. Вот пошаговое руководство по решению вашей проблемы:

  1. Проверьте конфигурацию unit-файла systemd.
    Убедитесь, что ваш unit-файл службы (например, /etc/systemd/system/ваш_сервис.service) имеет следующие строки:

    [Service]
    ExecStart=/путь/к/вашему/бинарному_файлу
    StandardOutput=journal
    StandardError=journal

    По умолчанию StandardOutput и StandardError должны проходить в журнал, но рекомендуется явное указание для уверенности.

  2. Проверьте настройку systemd.
    Выполните следующую команду, чтобы проверить текущее значение стандартного вывода для вашей службы:

    systemctl show -p StandardOutput ваш_сервис

    Убедитесь, что значение StandardOutput установлено в journal.

  3. Флешинг вывода.
    В вашем коде, если вы используете printf, убедитесь, что вы добавляете символ новой строки \n в конце строки или вызываете fflush(stdout);. Это важно, так как стандартный вывод может быть буферизован, и вывод может не появляться в журнале, если буфер не сброшен.

    Пример кода:

    printf("hey, this should appear in the journal\n");
    fflush(stdout); // Сбрасываем буфер
  4. Запуск и проверка службы.
    После внесения изменений в unit-файл, перезапустите службу, чтобы изменения вступили в силу:

    sudo systemctl daemon-reload
    sudo systemctl restart ваш_сервис
  5. Проверка журнала.
    Проверьте вывод вашей службы в журнале с помощью:

    journalctl -u ваш_сервис

    Вы должны увидеть сообщения, которые выводит ваш сервис.

  6. Использование 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.

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

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