Как перенаправить вывод службы 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

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

meallhour
источник

Ответы:

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' 
Shuangistan
источник
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"

Tigra
источник
Что делает опция -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'

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

Santhosh Hirekerur
источник
-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