So leiten Sie die Ausgabe des systemd-Dienstes in eine Datei um

168

Ich versuche, die Ausgabe eines systemdDienstes in eine Datei umzuleiten, aber es scheint nicht zu funktionieren:

[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

Bitte korrigieren Sie meinen Ansatz.

Essensstunde
quelle

Antworten:

232

Ich denke, es gibt einen eleganteren Weg, um das Problem zu lösen: Senden Sie stdout / stderr mit einer Kennung an syslog und weisen Sie Ihren Syslog-Manager an, seine Ausgabe nach Programmnamen aufzuteilen.

Verwenden Sie die folgenden Eigenschaften in Ihrer systemd Service Unit-Datei:

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

Angenommen, Ihre Distribution verwendet rsyslog zum Verwalten von Syslogs, erstellen Sie eine Datei /etc/rsyslog.d/<new_file>.confmit dem folgenden Inhalt:

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

Machen Sie nun die Protokolldatei von syslog beschreibbar:

# 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

Starten Sie rsyslog ( sudo systemctl restart rsyslog) neu und genießen Sie! Ihr Programm stdout / stderr ist weiterhin über journalctl ( sudo journalctl -u <your program identifier>) verfügbar , sie sind jedoch auch in der Datei Ihrer Wahl verfügbar.

Quelle über archive.org

Valerio Versace
quelle
8
Funktioniert nicht für mich unter Ubuntu 16.04. journalctl -ufunktioniert immer noch, aber es wird nichts an die angegebene Datei gesendet.
Duncan Calvert
1
Dies funktioniert gut auf Debian Stretch, beschwert sich jedoch, dass ~es veraltet ist und stopstattdessen verwendet werden sollte. Beachten Sie auch, dass die zweite Zeile gekürzt werden kann, & stopwenn die beiden nacheinander kommen.
6.
47
Mit systemd 236 oder neuer können Sie auch direkt in eine Datei schreiben, indem Sie StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu
5
Ich habe dies funktioniert, indem ich den /etc/rsyslog.d/<newfile>.confInhalt :programname, isequal, "<your program identifier>" /var/log/somelog.log geändert habe in: Hier ist die Dokumentation zu den rsyslog-Filtern: rsyslog.com/doc/v8-stable/configuration/filters.html Und hier sind Dokumente zu den Eigenschaften wie programname: rsyslog.com/doc/master/configuration/properties .html
mbil
1
Ich hatte Probleme bei der Verwendung dieser Konfiguration, bis ich feststellte, dass rsyslogsie einen eigenen Benutzer hat syslogund Schreibzugriff auf den Speicherort der Protokolle haben muss. Also chownentsprechend verwenden. Hoffe das hilft jemandem.
Imaskar
72

Wenn Sie eine neuere Distribution mit einer neueren systemd( systemdVersion 236 oder neuer ) haben, können Sie die Werte von StandardOutputoder StandardErrorauf einstellen file:YOUR_ABSPATH_FILENAME.


Lange Geschichte:

In neueren Versionen von systemdgibt es eine relativ neue Option ( die Github-Anforderung stammt von 2016 ish und die Erweiterung wird 2017 ish zusammengeführt / geschlossen ), mit der Sie die Werte von StandardOutputoder StandardErrorauf festlegen können file:YOUR_ABSPATH_FILENAME. Die file:pathOption ist in der neuesten systemd.execManpage dokumentiert .

Diese neue Funktion ist relativ neu und daher für ältere Distributionen wie Centos-7 (oder Centos davor) nicht verfügbar.

Trevor Boyd Smith
quelle
10
Funktioniert nicht in Ubuntu 1604 am 20.03.2018. Die systemd Version in Ubuntu 1604 ist nur 229.
Bronze Mann
Danke, du hast ganz klar gesagt. Ich kann einfach nicht glauben, dass das System in Ubuntu 1604 die Ausgabe nicht einfach per Konfiguration in eine Datei umleiten kann. Ich muss den sh-Weg verwenden, um dieses Problem zu lösen.
Bronzemann
@bronzeman Die Feature-Anfrage wurde erst 2017 geschlossen, während Ubuntu 16.04 im Jahr 2016 herauskam. In einer bestimmten Hauptversion von Ubuntu (z. B. 16.04, 16.10, 17.04 usw.) behält Ubuntu die ABI-Kompatibilität in seinen Kernsystempaketen bei. Sie werden also systemd (oder den Linux-Kernel oder glibc oder irgendetwas) nicht aktualisieren, es sei denn, es behält den gleichen ABI bei wie bei der Erstveröffentlichung der Ubuntu-Version.
Villapx
1
FWIW: Ich habe ein bisschen gesucht, aber diese Funktion scheint keine Bestimmungen für die Protokollrotation zu enthalten, z. B. die Funktion zum erneuten Öffnen der Protokolldatei, wobei eine Funktion wie copytruncatein verwendet werden muss logrotate.
Antak
47

Möglicherweise erhalten Sie diesen Fehler:

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

Von der systemd.exec(5)Manpage:

StandardOutput=

Steuert, mit welchem ​​Dateideskriptor 1 (STDOUT) der ausgeführten Prozesse verbunden ist. Nimmt man von inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consoleoder socket.

In der systemd.exec(5)Manpage werden weitere Optionen zur Protokollierung erläutert. Siehe auch die systemd.service(5)und systemd.unit(5)Manpages.

Oder vielleicht können Sie solche Dinge ausprobieren (alles in einer Zeile):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 
Shuangistan
quelle
7
Unter den Optionen wird empfohlen, sich im systemd-Journal anzumelden. Sie können mit nur die Protokolle für Ihren Prozess im Journal anzeigen journalctl -u your-unit-name.
Mark Stosberg
6
Um eine Datei anzugeben, gibt es eine andere Reinigungsoption, wie in der Dokumentation angegeben: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
Ehrfürchtige Antwort, es hat mein Problem gelöst. Ich möchte nur erweitern, da derzeit, wenn der Neustart des Dienstes die alten Protokolle überschreibt, dieser Teil ersetzt werden muss: 2>&1 > /var/log.logzu diesem : 2>&1 >> /var/log.log. Vielen Dank
PumpkinSeed
10
Ehrlich gesagt klingt das Aufrufen einer Shell mit einer Befehlszeichenfolge in ExecStart wie die wirklich falsche Methode.
David Tonhofer
1
"/ bin / sh" ist eine großartige Problemumgehung, aber Sie MÜSSEN "exec" verwenden, da sonst der Dienst nicht ordnungsgemäß neu gestartet wird, da SIGTERM nicht an den untergeordneten Prozess übergeben wird. Siehe veithen.io/2014/11/16/sigterm-propagation.html
Rich
33

Ich würde vorschlagen, die systemd- Datei selbst hinzuzufügen stdoutund stderrabzulegen service.

Verweis: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Wie Sie konfiguriert haben, sollte es nicht gefallen:

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

Es sollte sein:

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

Dies funktioniert, wenn Sie den Dienst nicht immer wieder neu starten möchten .

Dadurch wird eine neue Datei erstellt und nicht an die vorhandene Datei angehängt.

Verwenden Sie stattdessen:

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

HINWEIS: Stellen Sie sicher, dass Sie das Verzeichnis bereits erstellt haben. Ich denke, es wird nicht unterstützt, ein Verzeichnis zu erstellen.

Rajat Jain
quelle
5
Duplikat dieser Antwort mit weniger Details
Gert van den Berg
9
Ich denke, ich habe es direkter und verständlicher gemacht.
Rajat Jain
1
Für mich file:funktioniert die Route beim ersten Laden des Dienstes, aber beim anschließenden Neustart wird sie nicht mehr in die Datei geschrieben. Ich habe es append:aus den Dokumenten versucht und das hat überhaupt nicht funktioniert.
rb-
3
Beachten Sie, dass in den Dokumenten klargestellt wird, dass file:jedes Mal am Anfang der Datei geschrieben wird und nicht abgeschnitten wird. Dies append:scheint eine neue Ergänzung zu sein (dh nicht auf der man systemd.execSeite unter Ubuntu 18.04 vorhanden).
Cole
19

Wenn rsyslog aus irgendeinem Grund nicht verwendet werden kann, reicht dies aus: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"

Tigra
quelle
Was macht die Option -e von Bash?
Lampe
3

Angenommen, die Protokolle sind bereits in stdout / stderr abgelegt und die Systemd-Einheit hat sich angemeldet/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 (System Logging Service)

# 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

Starten Sie rsyslog neu

systemctl restart rsyslog.service
Hieu Huynh
quelle
1

Wir verwenden Centos7, eine Spring Boot-Anwendung mit systemd. Ich habe Java wie unten ausgeführt. und das Setzen von StandardOutput auf Datei funktionierte bei mir nicht.

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

Die folgende Problemumgehungslösung funktioniert ohne Festlegen von StandardOutput. Java durch sh wie unten laufen lassen.


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

Geben Sie hier die Bildbeschreibung ein

Santhosh Hirekerur
quelle
-1 zum Definieren von JVM-Parametern in falscher Reihenfolge. -Xmx512M muss vor -jar definiert werden. Auch was Sie erleben, wird erwartet. Systemd ruft keine Dienste mit Shell auf
Sami Korhonen
1
@SamiKorhonen, ich habe meine Kommentare hinzugefügt, nachdem ich getestet habe, dass dies funktioniert. Sogar ich habe über die Reihenfolge von -Xmx512M nachgedacht. Bitte testen Sie, bevor Sie blinde Kommentare hinzufügen.
Santhosh Hirekerur
0

Kurze Antwort:

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

Wenn Sie nicht möchten, dass die Dateien bei jeder Ausführung des Dienstes gelöscht werden, verwenden Sie stattdessen Anhängen:

StandardOutput=append:/var/log1.log
StandardError=append:/var/log2.log
Arnett Rufino
quelle
2
Duplikat dieser Antwort mit weniger Details
Rustyx