Comment puis-je enregistrer la sortie standard d'un processus démarré par start-stop-daemon?

120

J'utilise un script init pour exécuter un processus simple, qui démarre avec:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS

Le processus appelé $ DAEMON imprime généralement les informations du journal sur sa sortie standard. Pour autant que je sache, ces données ne sont stockées nulle part.

Je voudrais écrire ou ajouter le stdout de $ DAEMON à un fichier quelque part.

La seule solution que je connaisse est de dire à start-stop-daemon d'appeler directement un shellscript au lieu de $ DAEMON; le script appelle ensuite $ DAEMON et écrit dans le fichier journal. Mais cela nécessite un script supplémentaire qui, comme la modification du démon lui-même, semble être la mauvaise façon de résoudre une tâche aussi courante.

joeytwiddle
la source

Réponses:

127

Pour développer la réponse d'Ypocat, car elle ne me laisse pas commenter:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
 --make-pidfile --pidfile $PIDFILE --background       \
 --startas /bin/bash -- -c "exec $DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1"

Utiliser execpour exécuter le démon permet à stop d'arrêter correctement le processus enfant au lieu du seul parent bash.

Utiliser --startasau lieu de --execgarantit que le processus sera correctement détecté par son pid et ne démarrera pas par erreur plusieurs instances du démon si start est appelé plusieurs fois. Sinon, start-stop-daemon recherchera un processus / bin / bash et ignorera le processus enfant réel exécutant le démon.

stormbeta
la source
2
C'est une bien meilleure solution que celle de @ypocat principalement parce que fermer à nouveau le démon en le remplaçant --startpar --stopfonctionne réellement.
aef
J'ai essayé d'exécuter cette commande à partir de rc.local au lieu de init.d ... Je ne semble pas obtenir les mêmes résultats. Cependant, lorsque vous l'exécutez à partir d'un shell via SSH, cela fonctionne comme un charme!
nemo
1
À quoi start-stop-daemon --test (...)ressemblerait l'accompagnement ?
Abdull
2
@MattClimbs Il écrase le fichier après chaque démarrage. utiliser >>au lieu de >pour ajouter.
Meow
2
Avant de paniquer (comme moi) parce que votre journal était vide, sachez qu'il est mis en mémoire tampon! Vous pouvez utiliser "exec stdbuf -oL -eL $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1" pour forcer la sortie à vider chaque ligne (de blog.lanyonm.org/articles/2015/01/11/… )
piers7
47

Tu as besoin de faire:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec /bin/bash -- -c "$DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1"

De plus, si vous utilisez --chuidou --user, assurez-vous que l'utilisateur peut écrire dans /var/logou dans le fichier /var/log/some.log. Le meilleur moyen est de faire en sorte que cet utilisateur soit propriétaire /var/log/subdir/.

youurayy
la source
1
Fantastique, merci ypocat. Aujourd'hui, en plus de sauvegarder le journal, j'avais besoin d'exécuter un script non binaire que --exec ne permet pas mais votre astuce fonctionne!
joeytwiddle
8
L'inconvénient ... l'arrêt du service tue bash, mais pas le processus enfant bash commencé! (Dans mon cas, DAEMON = café).
joeytwiddle
1
J'ai contourné cela en supprimant tous les processus enfants du processus bash en haut de do_stop. bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
joeytwiddle
5
Bon à savoir, et la pkillsolution aussi. Vous vous demandez ce que ferait ... -c "exec $DAEMON..."(en ajoutant le "exec"). Je n'ai pas ça dans l'assiette en ce moment, je ne peux donc pas l'essayer.
youurayy
12
@ypocat Je viens de vérifier que cela fonctionne avec -c "exec $ DAEMON ...". Cela signifie qu'aucun piratage de pkill n'est requis.
repenser
40

Il semble que vous devriez pouvoir utiliser maintenant le --no-closeparamètre lorsque vous commencez start-stop-daemonà capturer la sortie du démon. Cette nouvelle fonctionnalité est disponible dans le dpkgpaquet depuis la version 1.16.5 sur Debian:

Ajoutez une nouvelle option --no-close pour désactiver la fermeture des fds sur --background.

Cela permettait à l'appelant de voir les messages de processus à des fins de débogage ou de rediriger les descripteurs de fichiers vers des fichiers journaux, syslog ou similaires.

Stéphane
la source
8
C'est dommage qu'il ne soit pas disponible dans Ubuntu 12.04 :(
Leon Radley
Je n'arrive pas à obtenir que --no-close to work ... la sortie va toujours au shell que j'exécute le script init.d à partir de :(
stantonk
+1 Fonctionne parfaitement sur Debian squeeze avec un service node.js démonisé.
speakr
2
@stantonk Avez-vous également redirigé stdout / stderr vers un fichier? La ligne de commande complète ressemble à ceci. Et assurez-vous que le fichier journal peut être écrit par l'utilisateur $ USER: start-stop-daemon --start --chuid $ USER --pidfile $ PIDFILE --background --no-close --make-pidfile --exec $ DAEMON - $ DAEMONARGS >> /var/log/xxxxx.log 2> & 1
nharrer
1
Ceci n'est pas disponible avec l'openrc start-stop-daemon. Cependant, la version openrc a les options -1et -2pour rediriger respectivement stdout et stderr.
little-mec
14

Avec openrc (qui est la valeur par défaut sur Gentoo ou Alpine Linux par exemple) start-stop-daemona les options -1et -2:

-1, --stdout Redirige stdout vers un fichier

-2, --stderr Redirige stderr vers un fichier

Vous pouvez donc simplement écrire:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS -1 $LOGFILE -2 $LOGFILE
petit mec
la source
9

Il n'est pas trop difficile de capturer la sortie du démon et de l'enregistrer dans un fichier:

start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas $DAEMON --no-close \
  -- $DAEMON_ARGS >> $LOGFILE 2>&1

Cependant, cette solution peut être sous-optimale pour logrotate.

Il peut être préférable de capturer la sortie dans syslog. Sur Debian, cela correspondrait au comportement des services systemd. La simple tentative suivante de réécriture de l'exemple ci-dessus est erronée car elle laisse derrière elle deux processus sans parent ("zombie") (enregistreur et démon) après avoir arrêté le démon car start-stop-daemonne termine que son enfant mais pas tous les descendants:

## Do not use this!
start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas /bin/sh \
  -- -c """exec $DAEMON $DAEMON_ARGS | /usr/bin/logger --tag $NAME"""

Pour le faire fonctionner, nous avons besoin d'un wrapper qui termine ses enfants lors de la réception SIGTERMde start-stop-daemon. Il y a quelques:

duende :
start-stop-daemon --start --background \
  --pidfile $PIDFILE \
  --startas /usr/sbin/duende \
  -- --pid $PIDFILE --chroot=/ --uid 65534 --ident $NAME \
  /bin/su --login $DAEMON_USER --shell /bin/sh --command """exec ${DAEMON} $DAEMON_ARGS"""

Remarque: uid=65534est un utilisateur nobody.

Avantages : cela fonctionne et c'est relativement facile.
Inconvénients : 4 processus (superviseur duende, son fork avec des privilèges supprimés (logger) suet le démon lui-même); obligatoire --chroot; Si le démon se termine immédiatement (par exemple, une commande invalide), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"signalez-le comme démarré avec succès.

démon :
start-stop-daemon --start --pidfile $PIDFILE \
  --startas /usr/bin/daemon \
  -- --noconfig --name $NAME --stderr=syslog.info --stdout=syslog.info \
  -- /bin/su --login $DAEMON_USER --shell /bin/sh --command """exec $DAEMON $DAEMON_ARGS"""

Avantages : 3 (processus superviseur daemon, suet le démon lui - même).
Inconvénients : Difficile à gérer en $PIDFILEraison de la confusion des options de ligne de commande du démon ; Si le démon se termine immédiatement (par exemple, une commande invalide), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"signalez-le comme démarré avec succès.

pipexec ( le gagnant ):

start-stop-daemon --start --background \
  --pidfile $PIDFILE --make-pidfile \
  --chuid $DAEMON_USER \
  --startas /usr/bin/pipexec -- -k \
   -- [ D $DAEMON $DAEMON_ARGS ] [ L /usr/bin/logger --tag $NAME ] '{D:2>D:1}' '{D:1>L:0}'

Avantages : 3 (processus superviseur pipexec, loggeret le démon lui - même); Si le démon se termine immédiatement (par exemple, une commande invalide), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"signalez correctement l'échec.
Inconvénients : aucun.

C'est le gagnant - la solution la plus simple et la plus soignée qui semble bien fonctionner.

Onlyjob
la source
7

Ferme généralement start-stop-daemonles descripteurs de fichier standard lors de l'exécution en arrière-plan. Depuis la page de manuel de start-stop-daemon:

-C, --no-close
Ne ferme aucun descripteur de fichier en forçant le démon en arrière-plan. Utilisé à des fins de débogage pour voir la sortie du processus ou pour rediriger des descripteurs de fichier pour consigner la sortie du processus. Uniquement pertinent lors de l'utilisation de --background.

Celui-ci a fonctionné pour moi:

    start-stop-daemon -b -C -o -c \ 
         $DAEMON_USER -S -x $DAEMON > $DAEMON_LOG 2>&1
Raashid Muhammed
la source
4

Citant une ancienne liste de diffusion:

https://lists.ubuntu.com/archives/ubuntu-uk/2005-June/000037.html

Un moyen simple - et si vous voulez utiliser start-stop-daemon peut-être le seul - est de créer un petit script contenant:

#!/bin/sh
exec /home/boinc/boinc/boinc > /home/boinc/log/boinc.log

puis utilisez ce script comme argument pour start-stop-daemon.

La vraie question est peut-être de savoir s'il est vraiment nécessaire d'utiliser start-stop-daemon en premier lieu?

joeytwiddle
la source
3

Je ne sais pas si "$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1" fermera un jour le descripteur de fichier pour le fichier journal ... ce qui signifie que si votre démon s'exécute pour toujours, je ne suis pas sûr que logrotate ou d'autres mécanismes de nettoyage de l'espace disque fonctionneraient. Puisqu'il est> au lieu de >>, la commande suggérée tronquerait également les journaux existants au redémarrage. Si vous voulez voir pourquoi le démon a planté et qu'il redémarre automatiquement, cela peut ne pas être très utile.

Une autre option pourrait être "$ DAEMON | logger". logger est une commande qui se connectera à syslog (/ var / log / messages). Si vous avez également besoin de stderr, je pense que vous pouvez utiliser "$ DAEMON 1> & 2 | logger"

nairbv
la source
Vous avez raison, l'utilisation >>est généralement plus appropriée pour les démons, même si cela implique que vous devez maintenant créer une règle logrotate!
joeytwiddle
En ce qui concerne l'espace disque, les méthodes qui tronquent le fichier récupèrent l'espace immédiatement (au moins sous les systèmes de fichiers ext). Mais attention aux méthodes qui suppriment simplement un fichier en cours d'écriture: l'espace ne sera pas récupéré tant que le handle ne sera pas libéré, et vous ne trouverez plus le nœud de fichier pour le tronquer manuellement!
joeytwiddle
@joeytwiddle une partie de mon point ici est qu'il y a des situations où logrotate échouera à faire pivoter les journaux si le descripteur de fichier n'est jamais fermé.
nairbv
--no-close ... | loggerne fonctionne pas pour moi (Debian 7.3, start-stop-daemon 1.16.12). Le script start-stop-daemon ne revient pas, bien que / var / log / messages soit rempli :-). Je l'ai essayé avec et sans 1>&2.
hgoebl
hgoebl vous devez avoir l'expression "cmd | logger" entre guillemets, de sorte que l'interpréteur saura que c'est "cmd" que vous envoyez à logger, pas l'expression start-stop-daemon.
Wexxor
2

En supposant que c'est bash (bien que certains autres shells puissent également le permettre), la ligne:

exec >>/tmp/myDaemon.log

enverra toutes les futures sorties standard à ce fichier. C'est parce que execsans un nom de programme fait juste de la magie de redirection. Depuis la bashpage de manuel:

Si la commande n'est pas spécifiée, toutes les redirections prennent effet dans le shell actuel.

La gestion dudit fichier est bien entendu une autre question.

paxdiablo
la source
pouvez-vous préciser où cette ligne est censée être placée? Juste après la start-stop-daemonligne mentionnée par la question initiale?
Abdull
1

Que diriez-vous:

sudo -u myuser -i start-stop-daemon ...
jakub.piasecki
la source