¿Cómo puedo registrar la salida estándar de un proceso iniciado por start-stop-daemon?

120

Estoy usando un script de inicio para ejecutar un proceso simple, que se inicia con:

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

El proceso llamado $ DAEMON generalmente imprime información de registro en su salida estándar. Por lo que puedo decir, estos datos no se almacenan en ningún lugar.

Me gustaría escribir o agregar la salida estándar de $ DAEMON a un archivo en algún lugar.

La única solución que conozco es decirle a start-stop-daemon que llame a un shellscript en lugar de $ DAEMON directamente; el script luego llama a $ DAEMON y escribe en el archivo de registro. Pero eso requiere un script adicional que, al igual que modificar el demonio en sí, parece la forma incorrecta de resolver una tarea tan común.

joeytwiddle
fuente

Respuestas:

127

Para ampliar la respuesta de ypocat, ya que no me deja comentar:

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"

Usar execpara ejecutar el demonio permite detener correctamente el proceso hijo en lugar de solo el padre bash.

Usar en --startaslugar de --execasegura que el proceso será detectado correctamente por su pid y no iniciará erróneamente varias instancias del demonio si se llama a start varias veces. De lo contrario, start-stop-daemon buscará un proceso / bin / bash e ignorará el proceso hijo real que ejecuta el daemon.

stormbeta
fuente
2
Esta es una solución mucho mejor que la de @ypocat principalmente porque cerrar el demonio nuevamente reemplazando --startcon --stoprealmente funciona.
aef
Intenté ejecutar este comando desde rc.local en lugar de init.d ... No parece que obtengo los mismos resultados. Sin embargo, cuando se ejecuta desde un shell a través de SSH, ¡funciona como un encanto!
nemo
1
¿Cómo se vería el acompañante start-stop-daemon --test (...)?
Abdull
2
@MattClimbs Sobrescribe el archivo después de cada inicio. utilizar en >>lugar de >para añadir.
Miau
2
Antes de asustarse (como yo) porque su registro estaba vacío, ¡tenga en cuenta que esto está almacenado en búfer! Puede usar "exec stdbuf -oL -eL $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1" para forzar la salida a vaciar cada línea (de blog.lanyonm.org/articles/2015/01/11/… )
piers7
47

Necesitas hacer:

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"

Además, si usa --chuido --user, asegúrese de que el usuario pueda escribir en /var/logel archivo /var/log/some.log. La mejor manera es que el usuario tenga un /var/log/subdir/pensamiento.

youurayy
fuente
1
Fantástico, gracias ypocat. Hoy, además de guardar el registro, necesitaba ejecutar un script no binario que --exec no permite, ¡pero tu truco funciona!
joeytwiddle
8
El lado negativo ... detener el servicio mata a bash, ¡pero no se inició el proceso hijo! (En mi caso, DAEMON = café).
joeytwiddle
1
Trabajé en torno a eso eliminando todos los procesos secundarios del proceso bash en la parte superior de do_stop. bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
joeytwiddle
5
Es bueno saberlo y la pkillsolución también. Preguntándose qué haría ... -c "exec $DAEMON..."(agregando el "ejecutivo"). No tengo esto en el plato ahora, así que no puedo probarlo.
youurayy
12
@ypocat Acabo de verificar que funciona con -c "exec $ DAEMON ...". Esto significa que no se requieren hacks de pkill.
pensar demasiado el
40

Parece que debería poder usar ahora el --no-closeparámetro al comenzar start-stop-daemona capturar la salida del demonio. Esta nueva característica está disponible en el dpkgpaquete desde la versión 1.16.5 en Debian:

Agregue la nueva opción --no-close para deshabilitar el cierre de fds en --background.

Esto permitió a la persona que llamaba ver los mensajes de proceso con fines de depuración, o poder redirigir los descriptores de archivos a archivos de registro, syslog o similares.

Stéphane
fuente
8
Es una pena que no esté disponible en Ubuntu 12.04 :(
Leon Radley
Parece que no puedo conseguir eso, no, cerca de funcionar ... la salida todavía va al shell desde el que estoy ejecutando el script init.d desde :(
stantonk
+1 Funciona perfectamente en Debian squeeze con un servicio node.js demonizado.
speakr
2
@stantonk ¿También canalizó stdout / stderr a un archivo? La línea de comando completa se ve como sigue. Y asegúrese de que el usuario $ USER puede escribir el archivo de registro: start-stop-daemon --start --chuid $ USER --pidfile $ PIDFILE --background --no-close --make-pidfile --exec $ DAEMON - $ DAEMONARGS >> /var/log/xxxxx.log 2> & 1
nharrer
1
Esto no está disponible con openrc start-stop-daemon. Sin embargo, la versión openrc tiene las opciones -1y -2para redirigir stdout y stderr respectivamente.
little-dude
14

Con openrc (que es el predeterminado en gentoo o alpine linux, por ejemplo) start-stop-daemontiene las opciones -1y -2:

-1, --stdout Redirigir stdout al archivo

-2, --stderr Redirigir stderr al archivo

Entonces puedes escribir:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS -1 $LOGFILE -2 $LOGFILE
pequeño amigo
fuente
9

No es demasiado difícil capturar la salida del demonio y guardarla en un archivo:

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

Sin embargo, esta solución puede no ser óptima para logrotate.

Podría ser mejor capturar la salida en syslog. En Debian esto coincidiría con el comportamiento de los servicios systemd. El siguiente intento directo de reescribir el ejemplo anterior es incorrecto porque deja atrás dos procesos sin padres ("zombi") (registrador y demonio) después de detener el demonio porque start-stop-daemontermina solo su hijo pero no todos los descendientes:

## 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"""

Para que funcione, necesitamos un contenedor que termine sus hijos al recibir SIGTERMde start-stop-daemon. Hay algunos:

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"""

Nota: uid=65534es un usuario nobody.

Ventajas : funciona y es relativamente fácil.
Contras : 4 procesos (supervisor duende, su bifurcación con privilegios eliminados (registrador) suy el propio demonio); obligatoria --chroot; Si el demonio termina de inmediato (por ejemplo, un comando no válido), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"infórmelo como iniciado correctamente.

demonio :
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"""

Pros : 3 procesos (supervisor daemon, suy daemon sí mismo).
Contras : Difícil de administrar $PIDFILEdebido a las opciones confusas de la línea de comandos del demonio ; Si el demonio termina de inmediato (por ejemplo, un comando no válido), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"infórmelo como iniciado correctamente.

pipexec ( el ganador ):

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}'

Pros : 3 Procesos (supervisor pipexec, loggery Daemon sí mismo); Si el demonio termina de inmediato (por ejemplo, un comando no válido) status_of_proc -p $PIDFILE "$DAEMON" "$NAME", informe correctamente el error.
Contras : ninguno.

Este es el ganador: la solución más sencilla y ordenada que parece funcionar bien.

Solo trabajo
fuente
7

Por lo general, start-stop-daemoncierra los descriptores de archivos estándar cuando se ejecuta en segundo plano. Desde la página de manual de start-stop-daemon:

-C, --no-close
No cierra ningún descriptor de archivo al forzar el demonio en segundo plano. Se utiliza con fines de depuración para ver la salida del proceso o para redirigir los descriptores de archivo para registrar la salida del proceso. Solo es relevante cuando se usa --background.

Este funcionó para mí:

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

Citando una vieja lista de correo:

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

Una forma fácil, y si desea usar start-stop-daemon quizás la única, es crear un pequeño script que contenga:

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

y luego use ese script como argumento para start-stop-daemon.

Quizás la pregunta real, sin embargo, es si realmente es necesario usar start-stop-daemon en primer lugar.

joeytwiddle
fuente
3

No estoy seguro de si "$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1" alguna vez cerrará el descriptor de archivo para el archivo de registro ... lo que significa que si su demonio se ejecuta para siempre, no estoy seguro que logrotate u otros mecanismos para limpiar el espacio en disco funcionarían. Dado que es> en lugar de >>, el comando sugerido también truncaría los registros existentes al reiniciar. Si desea ver por qué se bloqueó el demonio y se reinicia automáticamente, puede que no sea de mucha ayuda.

Otra opción podría ser "$ DAEMON | logger". logger es un comando que se registrará en syslog (/ var / log / messages). Si también necesita stderr, creo que podría usar "$ DAEMON 1> & 2 | logger"

nairbv
fuente
Tiene razón, usar >>es generalmente más apropiado para demonios, ¡aunque implica que ahora debería crear una regla de logrotate!
joeytwiddle
En cuanto al espacio en disco, los métodos que truncan el archivo recuperarán el espacio inmediatamente (al menos en sistemas de archivos ext). Pero tenga cuidado con los métodos que simplemente eliminan un archivo en el que aún se está escribiendo: el espacio no se recuperará hasta que se libere el identificador, ¡y ya no podrá encontrar el nodo del archivo para truncarlo manualmente!
joeytwiddle
@joeytwiddle parte de mi punto aquí es que hay situaciones en las que logrotate no rotará los registros si el identificador del archivo nunca se cierra.
nairbv
--no-close ... | loggerno me funciona (Debian 7.3, start-stop-daemon 1.16.12). El script start-stop-daemon no regresa, aunque / var / log / messages está lleno :-). Lo probé con y sin 1>&2.
hgoebl
hgoebl, debe tener la expresión "cmd | logger" entre comillas, para que el intérprete sepa que es "cmd" que está conectando al logger, no la expresión start-stop-daemon.
Wexxor
2

Suponiendo que es bash (aunque algunos otros shells también pueden permitir esto), la línea:

exec >>/tmp/myDaemon.log

enviará toda la salida estándar futura a ese archivo. Eso es porque execsin un nombre de programa solo hace algo de magia de redirección. Desde la bashpágina del manual:

Si no se especifica el comando, cualquier redirección tendrá efecto en el shell actual.

La gestión de dicho expediente es, por supuesto, otro tema.

paxdiablo
fuente
¿Puede aclarar dónde se supone que debe colocarse esta línea? ¿Justo después de la start-stop-daemonlínea que mencionó la pregunta inicial?
Abdull
1

Qué tal si:

sudo -u myuser -i start-stop-daemon ...
jakub.piasecki
fuente