Comment rediriger la sortie du service systemd vers un fichier

171

J'essaie de rediriger la sortie d'un systemdservice vers un fichier mais cela ne semble pas fonctionner:

[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

Veuillez corriger mon approche.

repas à l'heure
la source

Réponses:

234

Je pense qu'il existe un moyen plus élégant de résoudre le problème: envoyez le stdout / stderr à syslog avec un identifiant et demandez à votre gestionnaire de syslog de diviser sa sortie par nom de programme.

Utilisez les propriétés suivantes dans votre fichier d'unité de service systemd:

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

Ensuite, en supposant que votre distribution utilise rsyslog pour gérer les syslogs, créez un fichier /etc/rsyslog.d/<new_file>.confavec le contenu suivant:

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

Maintenant, rendez le fichier journal accessible en écriture par 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

Redémarrez rsyslog ( sudo systemctl restart rsyslog) et profitez-en! Votre programme stdout / stderr sera toujours disponible via journalctl ( sudo journalctl -u <your program identifier>) mais il sera également disponible dans le fichier de votre choix.

Source via archive.org

Valerio Versace
la source
8
Ne fonctionne pas pour moi sur Ubuntu 16.04. journalctl -ufonctionne toujours mais rien n'est envoyé au fichier spécifié.
Duncan Calvert
1
Cela fonctionne très bien sur Debian Stretch, mais il se plaint qu'il ~est obsolète et stopdevrait être utilisé à la place. Notez également que la deuxième ligne peut être raccourcie & stopsi les deux se succèdent.
jlh
48
Avec systemd 236 ou plus récent, vous pouvez également écrire directement dans un fichier en utilisant StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu
5
Cela fonctionne en changeant le /etc/rsyslog.d/<newfile>.confcontenu en: :programname, isequal, "<your program identifier>" /var/log/somelog.log Voici la documentation sur les filtres rsyslog: rsyslog.com/doc/v8-stable/configuration/filters.html Et voici des documents sur les propriétés comme programname: rsyslog.com/doc/master/configuration/properties .html
mbil
1
J'ai eu des problèmes avec cette configuration jusqu'à ce que je trouve qu'elle rsysloga son propre utilisateur sysloget qu'elle doit avoir un accès en écriture à l'emplacement des journaux. Alors utilisez en chownconséquence. J'espère que cela aide quelqu'un.
Imaskar
73

Si vous avez une distribution plus récente avec une version plus récente systemd( systemdversion 236 ou plus récente ), vous pouvez définir les valeurs de StandardOutputou StandardErrorsur file:YOUR_ABSPATH_FILENAME.


Longue histoire:

Dans les versions plus récentes de, systemdil existe une option relativement nouvelle ( la requête github date de 2016 et l'amélioration est fusionnée / fermée en 2017 ) où vous pouvez définir les valeurs de StandardOutputou StandardErrorsur file:YOUR_ABSPATH_FILENAME. L' file:pathoption est documentée dans la page de manuel la plus récentesystemd.exec .

Cette nouvelle fonctionnalité est relativement nouvelle et n'est donc pas disponible pour les anciennes distributions comme les centos-7 (ou les centos avant cela).

Trevor Boyd Smith
la source
10
Ne fonctionne pas dans ubuntu 1604 en 2018-03-20. La version systemd dans ubuntu 1604 est seulement 229.
homme de bronze
Merci, vous avez dit très clairement. Je ne peux tout simplement pas croire que le systemd dans ubuntu 1604 ne peut pas rediriger la sortie vers un fichier juste par config.Je dois utiliser la méthode sh pour résoudre ce problème.
homme de bronze
@bronzeman, la demande de fonctionnalité n'a été fermée qu'en 2017, tandis qu'Ubuntu 16.04 est sorti en 2016. Dans une version majeure d'Ubuntu (par exemple 16.04, 16.10, 17.04, etc.), Ubuntu maintient la compatibilité ABI dans ses packages système de base. Ainsi, ils ne mettront pas à niveau systemd (ou le noyau Linux, ou glibc, ou quoi que ce soit) à moins qu'il ne conserve le même ABI que lors de la première sortie de la version Ubuntu.
villapx
1
FWIW: J'ai cherché un peu, mais cette fonctionnalité ne semble pas avoir de dispositions pour la rotation des journaux, comme la fonction de réouverture du fichier journal, avec un devant utiliser les goûts de copytruncatein logrotate.
antak
49

Vous obtenez probablement cette erreur:

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

Depuis la systemd.exec(5)page de manuel:

StandardOutput=

Contrôle où le descripteur de fichier 1 (STDOUT) des processus exécutés est connecté. Prend un des inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consoleou socket.

La systemd.exec(5)page de manuel explique d'autres options liées à la journalisation. Voir aussi les pages de manuel systemd.service(5)et systemd.unit(5).

Ou peut-être que vous pouvez essayer des choses comme celle-ci (le tout sur une seule ligne):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 
Shuangistan
la source
7
Parmi les options, il est recommandé de se connecter au journal systemd. Vous affichez uniquement les journaux de votre processus dans le journal en utilisant journalctl -u your-unit-name.
Mark Stosberg
6
Pour spécifier un fichier, il existe une autre option de nettoyage, comme indiqué par la documentation: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
Réponse géniale, cela a résolu mon problème. Je veux juste prolonger, car actuellement si le service redémarrage écrasent les anciens journaux, doivent remplacer cette partie: 2>&1 > /var/log.logà ceci: 2>&1 >> /var/log.log. Merci
PumpkinSeed
10
Franchement, appeler le shell avec une chaîne de commande dans ExecStart ressemble à la très mauvaise façon de le faire.
David Tonhofer
1
"/ bin / sh" est une excellente solution de contournement, mais vous DEVEZ utiliser "exec", sinon le service ne redémarrera pas correctement car SIGTERM ne sera pas transmis au processus fils. Voir veithen.io/2014/11/16/sigterm-propagation.html
Rich
33

Je suggérerais d'ajouter stdoutet de stderrclasser dans le servicefichier systemd lui-même.

Référence: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Comme vous l'avez configuré, il ne devrait pas aimer:

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

Ça devrait être:

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

Cela fonctionne lorsque vous ne souhaitez pas redémarrer le service encore et encore .

Cela créera un nouveau fichier et ne s'ajoutera pas au fichier existant.

Utilisez plutôt:

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

REMARQUE: assurez-vous que vous créez déjà le répertoire. Je suppose qu'il ne prend pas en charge la création d'un répertoire.

Rajat jain
la source
5
Duplicata de cette réponse , avec moins de détails
Gert van den Berg
9
Je pense que je l'ai rendu plus direct \ facile à comprendre.
Rajat jain
1
Pour moi, l' file:itinéraire fonctionne au premier chargement du service, mais lors des redémarrages suivants, il n'écrit plus dans le fichier. J'ai essayé append:de la documentation et cela n'a pas fonctionné du tout.
rb-
3
Notez que la documentation file:indique clairement que écrit au début du fichier à chaque fois, et ne tronque pas ... plus loin, append:semble être un nouvel ajout (c'est-à-dire non présent dans la man systemd.execpage sur Ubuntu 18.04).
cole
19

Si pour une raison quelconque, vous ne pouvez pas utiliser rsyslog, cela fera: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"

Tigra
la source
Que fait l'option -e de bash?
Lampe
3

Supposons que les journaux sont déjà placés dans stdout / stderr et que l'unité systemd se connecte/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 (service de journalisation système)

# 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

Redémarrez rsyslog

systemctl restart rsyslog.service
Hieu Huynh
la source
1

Nous utilisons Centos7, application de démarrage à ressort avec systemd. J'utilisais java comme ci-dessous. et la définition de StandardOutput sur fichier ne fonctionnait pas pour moi.

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

Ci-dessous la solution de contournement fonctionnant sans définir StandardOutput. exécutant java via sh comme ci-dessous.


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

entrez la description de l'image ici

Santhosh Hirekerur
la source
-1 pour définir les paramètres jvm dans le mauvais ordre. -Xmx512M doit être défini avant -jar. On s'attend également à ce que vous vivez. Systemd n'appelle pas les services à l'aide du shell
Sami Korhonen
1
@SamiKorhonen, j'ai ajouté mes commentaires après avoir testé que cela fonctionne. Même moi, je pensais à la commande de -Xmx512M pour vous. Veuillez tester avant d'ajouter des commentaires aveugles.
Santhosh Hirekerur
0

Réponse courte:

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

Si vous ne voulez pas que les fichiers soient effacés à chaque fois que le service est exécuté, utilisez plutôt append:

StandardOutput=append:/var/log1.log
StandardError=append:/var/log2.log
Arnett Rufino
la source
2
Duplicata de cette réponse , avec moins de détails
rustyx