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


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.