Jak przekierować dane wyjściowe usługi systemd do pliku


171

Próbuję przekierować dane wyjściowe systemdusługi do pliku, ale wydaje się, że nie działa:

[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

Proszę, popraw moje podejście.

Odpowiedzi:


234

Myślę, że istnieje bardziej elegancki sposób rozwiązania problemu: wyślij stdout / stderr do syslog z identyfikatorem i poinstruuj swojego menedżera syslog, aby podzielił dane wyjściowe według nazwy programu.

Użyj następujących właściwości w pliku systemowym jednostki usługowej:

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

Następnie, zakładając, że twoja dystrybucja używa rsyslog do zarządzania syslogami, utwórz plik /etc/rsyslog.d/<new_file>.confo następującej treści:

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

Teraz spraw, aby plik dziennika był zapisywalny przez 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

Uruchom ponownie rsyslog ( sudo systemctl restart rsyslog) i baw się! Twój program stdout / stderr będzie nadal dostępny przez journalctl ( sudo journalctl -u <your program identifier>), ale będą one również dostępne w wybranym przez Ciebie pliku.

Źródło: archive.org


8
Nie działa dla mnie na Ubuntu 16.04. journalctl -unadal działa, ale nic nie jest wysyłane do określonego pliku.
Duncan Calvert

1
Działa to świetnie na Debianie stretch, jednak narzeka, że ~jest przestarzałe i stoppowinno być używane zamiast tego. Zwróć również uwagę, że druga linia może zostać skrócona, & stopjeśli obie następują po sobie.
jlh

47
Z systemd 236 lub nowszym możesz również pisać bezpośrednio do pliku przy użyciu StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu

5
Mam to działające, zmieniając /etc/rsyslog.d/<newfile>.confzawartość na: :programname, isequal, "<your program identifier>" /var/log/somelog.log Oto dokumentacja dotycząca filtrów rsyslog : rsyslog.com/doc/v8-stable/configuration/filters.html A tutaj dokumenty dotyczące właściwości, takie jak programname: rsyslog.com/doc/master/configuration/properties .html
mbil

1
Miałem problem z użyciem tej konfiguracji, dopóki nie stwierdziłem, że rsyslogma ona własnego użytkownika syslogi musi mieć dostęp do zapisu w lokalizacji logów. Więc używaj chownodpowiednio. Mam nadzieję, że to komuś pomoże.
Imaskar

73

Jeśli masz nowszą dystrybucję z nowszą systemd( systemdwersja 236 lub nowsza ), możesz ustawić wartości StandardOutputlub StandardErrorna file:YOUR_ABSPATH_FILENAME.


Długa historia:

W nowszych wersjach systemdjest stosunkowo nowa opcja ( żądanie github pochodzi z 2016 ish, a ulepszenie jest połączone / zamknięte 2017 ish ), w której można ustawić wartości StandardOutputlub StandardErrordo file:YOUR_ABSPATH_FILENAME. file:pathOpcja jest udokumentowane w najnowszej systemd.execmanualu .

Ta nowa funkcja jest stosunkowo nowa, więc nie jest dostępna dla starszych dystrybucji, takich jak centos-7 (ani wcześniejszych centów).


10
Nie działa w ubuntu 1604 w 2018-03-20. Wersja systemd w ubuntu 1604 to tylko 229.
człowiek z brązu

Dzięki, powiedziałeś bardzo jasno. Po prostu nie mogę uwierzyć, że systemd w ubuntu 1604 nie może przekierować wyjścia do pliku tylko przez config.Muszę użyć sposobu sh, aby rozwiązać ten problem.
brąz mężczyzna

@bronzeman żądanie funkcji zostało zamknięte dopiero w 2017 r., a Ubuntu 16.04 wyszło w 2016 r. W danej głównej wersji Ubuntu (np. 16.04, 16.10, 17.04 itd.) Ubuntu zachowuje zgodność ABI w swoich podstawowych pakietach systemowych. Więc nie zaktualizują systemd (lub jądra Linuksa, glibc, czy czegokolwiek), chyba że zachowa ten sam ABI, co w momencie wydania pierwszej wersji Ubuntu.
villapx

1
FWIW: Trochę szukałem, ale wydaje się, że ta funkcja nie zawiera przepisów dotyczących rotacji dziennika, takich jak funkcja ponownego otwierania pliku dziennika, z koniecznością użycia takich jak copytruncatein logrotate.
antak

49

Prawdopodobnie pojawi się ten błąd:

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

Ze strony podręcznika systemd.exec(5):

StandardOutput=

Określa, gdzie jest podłączony deskryptor pliku 1 (STDOUT) wykonywanych procesów. Przyjmuje jedną inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consolelub socket.

systemd.exec(5)Strona podręcznika opisuje inne opcje związane z wyrębu. Zobacz także strony man systemd.service(5)i systemd.unit(5).

A może możesz wypróbować takie rzeczy (wszystko w jednej linii):

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

7
Wśród opcji zalecane jest zalogowanie się do dziennika systemowego. Możesz przeglądać tylko dzienniki procesu w dzienniku za pomocą journalctl -u your-unit-name.
Mark Stosberg,

6
Aby określić plik, istnieje inna opcja czyszczenia, jak wskazuje dokumentacja: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
Świetna odpowiedź, rozwiązała mój problem. Chcę tylko przedłużyć, ponieważ obecnie, jeśli usługa restart nadpisać stare dzienniki, trzeba wymienić tę część: 2>&1 > /var/log.logdo tego: 2>&1 >> /var/log.log. Dziękuję
PumpkinSeed

10
Szczerze mówiąc, wywołanie powłoki za pomocą ciągu poleceń w ExecStart brzmi jak naprawdę zły sposób, aby to zrobić.
David Tonhofer,

1
"/ bin / sh" to świetne obejście, ale MUSISZ użyć "exec", w przeciwnym razie usługa nie uruchomi się poprawnie, ponieważ SIGTERM nie zostanie przekazany do procesu potomnego. Zobacz veithen.io/2014/11/16/sigterm-propagation.html
Rich

33

Sugerowałbym dodanie stdouti stderrzapisanie w samym servicepliku systemd .

Odsyłacze: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Jak skonfigurowałeś, nie powinno to lubić:

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

Powinno być:

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

Działa to, gdy nie chcesz ponownie uruchamiać usługi ponownie .

Spowoduje to utworzenie nowego pliku i nie zostanie dołączone do istniejącego pliku.

Użyj zamiast:

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

UWAGA: Upewnij się, że utworzyłeś już katalog. Myślę, że to nie obsługuje tworzenia katalogu.


5
Duplikat tej odpowiedzi , z mniejszą ilością szczegółów
Gert van den Berg

9
Myślę, że uczyniłem to bardziej bezpośrednim \ łatwiejszym do zrozumienia.
Rajat jain

1
U mnie file:trasa działa przy pierwszym załadowaniu usługi, ale przy kolejnych restartach nie zapisuje już do pliku. Próbowałem append:z doktorów i to w ogóle nie działało.
rb-

3
Zauważ, że dokumentacja wyjaśnia, że file:za każdym razem zapisuje na początku pliku i nie obcina ... dalej, append:wydaje się być nowym dodatkiem (tj. man systemd.execNieobecnym na stronie w Ubuntu 18.04).
Cole

19

Jeśli z jakiegoś powodu nie możesz użyć rsyslog, wystarczy: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"


Co robi opcja -e w bash?
Lampa

3

Załóżmy, że dzienniki są już umieszczone na stdout / stderr i muszą zalogować się do jednostki systemowej/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 (usługa rejestrowania systemu)

# 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

Uruchom ponownie rsyslog

systemctl restart rsyslog.service

1

Używamy Centos7, aplikacji Spring Boot z systememd. Uruchomiłem java jak poniżej. i ustawienie StandardOutput na plik nie działało.

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

Poniżej rozwiązanie obejścia działające bez ustawiania StandardOutput. uruchamianie javy przez sh, jak poniżej.


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

wprowadź opis obrazu tutaj


-1 do definiowania parametrów jvm w złej kolejności. -Xmx512M należy zdefiniować przed -jar. Oczekuje się również tego, czego doświadczasz. Systemd nie wywołuje usług przy użyciu powłoki
Sami Korhonen

1
@SamiKorhonen, dodałem swoje komentarze po przetestowaniu, że działa. Nawet ja myślałem o zamówieniu -Xmx512M jest do ciebie podobny. Prosimy o przetestowanie przed dodaniem ślepych komentarzy.
Santhosh Hirekerur,

0

Krótka odpowiedź:

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

Jeśli nie chcesz, aby pliki były czyszczone za każdym razem, gdy usługa jest uruchamiana, użyj zamiast tego append:

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

2
Duplikat tej odpowiedzi , z mniejszą
ilością
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.