Як перенаправити вихід системної служби у файл


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 розділити його вихід на ім'я програми.

Використовуйте такі властивості у файлі системного сервісного блоку:

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

Тоді, припускаючи, що ваш дистрибутив використовує rsyslog для управління syslogs, створіть файл /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 стретч, однак він скаржиться на те, що ~застарів і його stopслід використовувати замість цього. Також зауважте, що другий рядок можна скоротити, & stopякщо два йдуть один за одним.
jlh

47
З systemd 236 або новішою версією ви також можете писати безпосередньо у файл, використовуючи StandardOutput = файл: / 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 ish ), де можна встановити значення StandardOutputабо StandardErrorдо file:YOUR_ABSPATH_FILENAME. Цей file:pathпараметр задокументований на останній systemd.execсторінці людини .

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


10
Не працює в ubuntu 1604 у 2018-03-20. Версія для системи в ubuntu 1604 становить лише 229.
бронзова людина

Спасибі, ви сказали дуже чітко. Я просто не можу повірити, що systemd в ubuntu 1604 не може перенаправити висновок у файл просто на config.Я повинен використовувати шлях, щоб вирішити цю проблему.
бронзовий чоловік

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

1
FWIW: Я трохи шукав, але, схоже, ця функція не має таких положень для обертання журналу, як функція повторного відкриття файлу журналу, при цьому один повинен використовувати лайки copytruncateв 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.

The systemd.exec(5) 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
Відверто кажучи, виклик оболонки з командним рядком в 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
Я думаю, я зробив це більш прямим \ легким для розуміння.
Rajat jain

1
Для мене file:маршрут працює при першому завантаженні служби, але при наступних перезавантаженнях він більше не записує у файл. Я спробував append:у документах, і це зовсім не спрацювало.
rb-

3
Зауважте, що документи чітко пояснюють, що file:записується до початку файлу кожного разу, і не врізається ... далі, append:здається, це нове доповнення (тобто немає на man systemd.execсторінці в Ubuntu 18.04).
cole

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

Налаштування 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, додаток для весняного завантаження з системою. Я біг 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 вам усміхнеться. Перевірте, перш ніж додавати сліпі коментарі.
Santhosh Hirekerur

0

Коротка відповідь:

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

Якщо ви не хочете, щоб файли очищалися щоразу, коли служба запускається, скористайтеся додатком:

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

2
Дублікат цієї відповіді , з меншими деталями
іржа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.