Как перенаправить вывод службы systemd в файл


171

Я пытаюсь перенаправить вывод systemdслужбы в файл, но он не работает:

[Unit]
Description=customprocess
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server
StandardOutput=/var/log1.log
StandardError=/var/log2.log
Restart=always

[Install]
WantedBy=multi-user.target

Пожалуйста, исправьте мой подход.

Ответы:


234

Я думаю, что есть более элегантный способ решения проблемы: отправьте stdout / stderr в syslog с идентификатором и дайте команду своему администратору syslog разделить вывод по имени программы.

Используйте следующие свойства в вашем файле systemd service unit:

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<your program identifier> # without any quote

Затем, если ваш дистрибутив использует rsyslog для управления системными журналами, создайте файл /etc/rsyslog.d/<new_file>.confсо следующим содержимым:

if $programname == '<your program identifier>' then /path/to/log/file.log
& stop

Теперь сделайте файл журнала доступным для записи с помощью syslog:

# ls -alth /var/log/syslog 
-rw-r----- 1 syslog adm 439K Mar  5 19:35 /var/log/syslog
# chown syslog:adm /path/to/log/file.log

Перезапустите rsyslog ( sudo systemctl restart rsyslog) и наслаждайтесь! Ваша программа stdout / stderr по-прежнему будет доступна через journalctl ( sudo journalctl -u <your program identifier>), но они также будут доступны в выбранном вами файле.

Источник через archive.org


8
Не работает для меня на Ubuntu 16.04. journalctl -uвсе еще работает, но в указанный файл ничего не отправляется.
— Дункан Калверт

1
Это прекрасно работает на Debian Stretch, однако он жалуется, что ~устарел и stopдолжен использоваться вместо этого. Также обратите внимание, что вторая строка может быть сокращена до & stopтого момента, когда эти два следуют друг за другом.
— JLH

48
С systemd 236 или новее вы также можете записывать напрямую в файл, используя StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
— leezu

5
Я получил эту работу, изменив /etc/rsyslog.d/<newfile>.confсодержимое на: :programname, isequal, "<your program identifier>" /var/log/somelog.log Вот документация по фильтрам rsyslog : rsyslog.com/doc/v8-stable/configuration/filters.html А вот документы по таким свойствам, как programname: rsyslog.com/doc/master/configuration/properties .html
— mbil

1
У меня были проблемы с использованием этой конфигурации, пока я не обнаружил, что у rsyslogнее есть собственный пользователь, syslogи у нее должен быть доступ на запись к местоположению журналов. Так что используйте chownсоответственно. Надеюсь, это кому-нибудь поможет.
— Имаскар

73

Если у вас есть новый дистрибутив с более новой systemd( systemdверсии 236 или более поздней версии ), вы можете установить значения StandardOutputили StandardErrorв file:YOUR_ABSPATH_FILENAME.


Длинная история:

В более новых версиях systemdесть относительно новый вариант ( запрос GitHub от 2016 иша и повышение слито / закрыто 2017 МОГЛИ ) , где вы можете установить значение StandardOutputили StandardErrorв file:YOUR_ABSPATH_FILENAME. file:pathОпция описана в самой последней systemd.execстранице человека .

Эта новая функция является относительно новой и поэтому недоступна для более старых дистрибутивов, таких как centos-7 (или любые другие centos до этого).


10
Не работает в Ubuntu 1604 в 2018-03-20. Версия systemd в Ubuntu 1604 всего 229.
— Бронзовый человек

Спасибо, вы сказали очень ясно. Я просто не могу поверить, что systemd в Ubuntu 1604 не может перенаправить вывод в файл только с помощью config. Я должен использовать sh способ решить эту проблему.
— бронзовый мужчина

@bronzeman запрос функции не был закрыт до 2017 года, в то время как Ubuntu 16.04 вышел в 2016 году. В данном основном выпуске Ubuntu (например, 16.04, 16.10, 17.04 и т. д.) Ubuntu поддерживает совместимость ABI в своих основных пакетах системы. Таким образом, они не будут обновлять systemd (или ядро ​​Linux, или glibc, или что-то еще), если только он не поддерживает тот же ABI, что и при первом выпуске версии Ubuntu.
— villapx

1
FWIW: Я немного искал, но у этой функции, похоже, нет условий для ротации журналов, таких как функция для повторного открытия файла журнала, при этом необходимо использовать подобные функции copytruncatein logrotate.
— Антак

49

Возможно, вы получите эту ошибку:

Failed to parse output specifier, ignoring: /var/log1.log

Со systemd.exec(5)страницы руководства :

StandardOutput=

Управляет подключением файлового дескриптора 1 (STDOUT) исполняемых процессов. Принимает одно из inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consoleили socket.

Страница systemd.exec(5)man объясняет другие опции, связанные с регистрацией. Смотрите также страницы man systemd.service(5)и systemd.unit(5)man.

Или, может быть, вы можете попробовать что-то вроде этого (все в одной строке):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 

7
Рекомендуется войти в журнал systemd. Вы просматриваете только журналы вашего процесса в журнале с помощью journalctl -u your-unit-name.
— Марк Стосберг

6
Чтобы указать файл, есть еще один вариант очистки, как указано в документации:The fd option connects the output stream to a single file descriptor provided by a socket unit. A custom named file descriptor can be specified as part of this option, after a ":" (e.g. "fd:foobar").
— orion

5
Потрясающий ответ, это решило мою проблему. Я просто хочу , чтобы расширить, потому что в настоящее время , если служба перезапустить перезаписывать старые журналы, придется заменить эту часть: 2>&1 > /var/log.logна это: 2>&1 >> /var/log.log. Спасибо
— PumpkinSeed

10
Честно говоря, вызов shell с командной строкой в ​​ExecStart звучит как действительно неправильный способ сделать это.
— Дэвид Тонхофер

1
«/ bin / sh» - отличный обходной путь, но вы ДОЛЖНЫ использовать «exec», иначе служба не будет перезапущена должным образом, так как SIGTERM не будет передан дочернему процессу. См. Veithen.io/2014/11/16/sigterm-propagation.html
— Rich

33

Я бы предложил добавить stdoutи stderrфайл в serviceсамом файле systemd .

Ссылка: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Как вы настроили это не должно нравиться:

StandardOutput=/home/user/log1.log
StandardError=/home/user/log2.log

Так должно быть:

StandardOutput=file:/home/user/log1.log
StandardError=file:/home/user/log2.log

Это работает, когда вы не хотите перезапускать сервис снова и снова .

Это создаст новый файл и не добавится к существующему файлу.

Используйте вместо:

StandardOutput=append:/home/user/log1.log
StandardError=append:/home/user/log2.log

ПРИМЕЧАНИЕ. Убедитесь, что вы уже создали каталог. Я думаю, что это не поддерживает создание каталога.


5
Дубликат этого ответа , с меньшим количеством деталей
— Герт ван ден Берг

9
Я думаю, я сделал это более прямым \ легким для понимания.
— Раджат Джайн

1
Для меня file:маршрут работает при первой загрузке сервиса, но при последующих перезапусках он больше не записывает в файл. Я пытался append:из документов, и это не сработало вообще.
— рб-

3
Обратите внимание, что документы ясно дают понять, что file:записывает в начало файла каждый раз и не усекает ... далее, append:кажется, это новое дополнение (то есть, отсутствует на man systemd.execстранице в Ubuntu 18.04).
— Коул

19

Если по какой-то причине нельзя использовать rsyslog, это будет делать: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"


Что делает опция -e в bash?
— Лампа

3

Предположим, что логи уже помещены в stdout / stderr , и в них есть вход системного модуля/var/log/syslog

journalctl -u unitxxx.service

Jun 30 13:51:46 host unitxxx[1437]: time="2018-06-30T11:51:46Z" level=info msg="127.0.0.1
Jun 30 15:02:15 host unitxxx[1437]: time="2018-06-30T13:02:15Z" level=info msg="127.0.0.1
Jun 30 15:33:02 host unitxxx[1437]: time="2018-06-30T13:33:02Z" level=info msg="127.0.0.1
Jun 30 15:56:31 host unitxxx[1437]: time="2018-06-30T13:56:31Z" level=info msg="127.0.0.1

Config rsyslog (служба ведения журнала системы)

# Create directory for log file
mkdir /var/log/unitxxx

# Then add config file /etc/rsyslog.d/unitxxx.conf

if $programname == 'unitxxx' then /var/log/unitxxx/unitxxx.log
& stop

Перезапустите rsyslog

systemctl restart rsyslog.service

1

Мы используем Centos7, приложение весенней загрузки с systemd. Я работал на Java, как показано ниже. и установка StandardOutput для файла не работает для меня.

ExecStart=/bin/java -jar xxx.jar  -Xmx512-Xms32M

Ниже обходное решение работает без настройки StandardOutput. запустить Java через Sh, как показано ниже.


ExecStart=/bin/sh -c 'exec /bin/java -jar xxx.jar -Xmx512M -Xms32M >> /data/logs/xxx.log 2>&1'

введите описание изображения здесь


-1 для определения параметров jvm в неправильном порядке. -Xmx512M должен быть определен до -jar. Также ожидается то, что вы испытываете. Systemd не вызывает сервисы, использующие оболочку
— Сами Корхонен

1
@SamiKorhonen, я добавил свои комментарии после тестирования, это работает. Даже я думал о том, что порядок -Xmx512M смехотворен для вас. Пожалуйста, проверьте, прежде чем добавлять слепые комментарии.
— Сантош Хирекерур

0

Короткий ответ:

StandardOutput=file:/var/log1.log
StandardError=file:/var/log2.log

Если вы не хотите, чтобы файлы очищались при каждом запуске службы, используйте вместо этого команду append:

StandardOutput=append:/var/log1.log
StandardError=append:/var/log2.log

2
Дубликат этого ответа , с меньшим количеством деталей
— rustyx
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.