Come posso registrare lo stdout di un processo avviato da start-stop-daemon?


120

Sto usando uno script di inizializzazione per eseguire un processo semplice, che viene avviato con:

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

Il processo chiamato $ DAEMON di solito stampa le informazioni di registro sul suo output standard. Per quanto ne so, questi dati non vengono archiviati da nessuna parte.

Vorrei scrivere o aggiungere lo stdout di $ DAEMON a un file da qualche parte.

L'unica soluzione che conosco è dire a start-stop-daemon di chiamare uno shellscript invece di $ DAEMON direttamente; lo script quindi chiama $ DAEMON e scrive nel file di log. Ma ciò richiede uno script aggiuntivo che, come la modifica del demone stesso, sembra il modo sbagliato per risolvere un'attività così comune.

Risposte:


127

Per espandere la risposta di ypocat, poiché non mi consente di commentare:

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"

Usare execper eseguire il demone consente a stop di arrestare correttamente il processo figlio invece del solo genitore bash.

L'utilizzo --startasinvece di --execgarantisce che il processo venga rilevato correttamente dal suo pid e non avvierà erroneamente più istanze del demone se start viene chiamato più volte. Altrimenti, start-stop-daemon cercherà un processo / bin / bash e ignorerà il processo figlio effettivo che esegue il daemon.


2
Questa è una soluzione di gran lunga migliore di quella di @ypocat principalmente perché chiudere di nuovo il demone sostituendolo --startcon --stopfunziona effettivamente.
aef

Ho provato a eseguire questo comando da rc.local invece di init.d ... Non mi sembra di ottenere gli stessi risultati. Tuttavia, quando lo si esegue da una shell tramite SSH, funziona come un fascino!
nemo

1
Come sarebbe l'accompagnamento start-stop-daemon --test (...)?
Abdull

2
@MattClimbs Sovrascrive il file dopo ogni avvio. utilizzare >>invece di >aggiungere.
Miao

2
Prima di impazzire (come me) perché il tuo registro era vuoto, tieni presente che è bufferizzato! Puoi usare "exec stdbuf -oL -eL $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1" per forzare l'output a svuotare ogni riga (da blog.lanyonm.org/articles/2015/01/11/… )
piers7

47

Devi fare:

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"

Inoltre, se usi --chuido --user, assicurati che l'utente possa scrivere su /var/logo nel file /var/log/some.log. Il modo migliore è che quell'utente possieda un /var/log/subdir/pensiero.


1
Fantastico, grazie ypocat. Oggi, oltre a salvare il log, avevo bisogno di eseguire uno script non binario che --exec non consente ma il tuo trucco funziona!
joeytwiddle

8
Il lato negativo ... l'arresto del servizio uccide bash, ma non il processo figlio bash avviato! (Nel mio caso DAEMON = caffè).
joeytwiddle

1
Ho aggirato questo problema uccidendo tutti i processi figlio del processo bash nella parte superiore di do_stop. bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
joeytwiddle

5
Buono a sapersi, e anche la pkillsoluzione. Chiedendosi cosa farebbe ... -c "exec $DAEMON..."(aggiungendo "exec"). Non averlo nel piatto in questo momento, quindi non posso provarlo.
youurayy

12
@ypocat Ho appena verificato che funziona con -c "exec $ DAEMON ...". Ciò significa che non sono necessari hack pkill.
pensare troppo al

40

Sembra che dovresti essere in grado di usare ora il --no-closeparametro quando inizi start-stop-daemona catturare l'output del demone. Questa nuova funzionalità è disponibile nel dpkgpacchetto dalla versione 1.16.5 su Debian:

Aggiungi una nuova opzione --no-close per disabilitare la chiusura di fds su --background.

Ciò ha consentito al chiamante di vedere i messaggi di processo a scopo di debug o di essere in grado di reindirizzare i descrittori di file a file di registro, syslog o simili.


8
È un peccato che non sia disponibile in Ubuntu 12.04 :(
Leon Radley

Non riesco a far funzionare --no-close per funzionare ... l'output sta ancora andando alla shell da cui sto eseguendo lo script init.d da :(
stantonk

+1 Funziona perfettamente su Debian squeeze con un servizio node.js daemonizzato.
speakr

2
@stantonk Hai anche reindirizzato stdout / stderr a un file? La riga di comando completa appare come segue. E assicurati che il file di log possa essere scritto dall'utente $ 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
Questo non è disponibile con openrc start-stop-daemon. Tuttavia la versione openrc ha le opzioni -1e -2per reindirizzare rispettivamente stdout e stderr.
piccoletto

14

Con openrc (che è l'impostazione predefinita su gentoo o alpine linux per esempio) start-stop-daemonha le opzioni -1e -2:

-1, --stdout Reindirizza lo stdout al file

-2, --stderr Reindirizza lo stderr su file

Quindi puoi semplicemente scrivere:

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

9

Non è troppo difficile catturare l'output del demone e salvarlo su file:

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

Tuttavia questa soluzione potrebbe non essere ottimale per logrotate.

Potrebbe essere meglio catturare l'output in syslog. Su Debian questo corrisponderebbe al comportamento dei servizi di systemd. Il seguente semplice tentativo di riscrivere l'esempio sopra è sbagliato perché lascia dietro di sé due processi senza genitori ("zombie") (logger e daemon) dopo aver arrestato il daemon perché start-stop-daemontermina solo il suo figlio ma non tutti i discendenti:

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

Per farlo funzionare abbiamo bisogno di un wrapper che termini i suoi figli quando riceve SIGTERMda start-stop-daemon. Ci sono alcuni:

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=65534è un utente nobody.

Pro : funziona ed è relativamente facile.
Contro : 4 processi (supervisore duende, relativo fork con privilegi rimossi (logger) sue daemon stesso); obbligatorio --chroot; Se il daemon termina immediatamente (ad es. Comando non valido) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"segnalalo come avviato correttamente.

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

Pro : 3 processi (supervisore daemon, sue demone stesso).
Contro : difficile da gestire a $PIDFILEcausa delle confuse opzioni della riga di comando del demone ; Se il daemon termina immediatamente (ad es. Comando non valido) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"segnalalo come avviato correttamente.

pipexec ( il vincitore ):

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

Pro : 3 elabora (supervisore pipexec, loggere demone stesso); Se il daemon termina immediatamente (es. Comando non valido) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"riporta correttamente l'errore.
Contro : nessuno.

Questo è il vincitore: la soluzione più semplice e precisa che sembra funzionare bene.


7

Di solito start-stop-daemonchiude i descrittori di file standard durante l'esecuzione in background. Dalla pagina man di start-stop-daemon:

-C, --no-close
Non chiude alcun descrittore di file quando si forza il demone in background. Utilizzato per scopi di debug per vedere l'output del processo o per reindirizzare i descrittori di file per registrare l'output del processo. Rilevante solo quando si utilizza --background.

Questo ha funzionato per me:

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

4

Citando una vecchia mailing list:

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

Un modo facile - e se vuoi usare start-stop-daemon forse l'unico - è creare un piccolo script contenente:

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

e poi usa quello script come argomento per start-stop-daemon.

Forse la vera domanda, tuttavia, è se sia davvero necessario utilizzare start-stop-daemon in primo luogo?


3

Non sono sicuro che "$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1" chiuderà mai il descrittore di file per il file di registro ... il che significa che se il tuo demone funziona per sempre, non ne sono sicuro quel logrotate o altri meccanismi per ripulire lo spazio su disco funzionerebbero. Poiché è> anziché >>, il comando suggerito troncerà anche i registri esistenti al riavvio. Se vuoi vedere perché il demone si è bloccato e si riavvia automaticamente, potrebbe non essere molto utile.

Un'altra opzione potrebbe essere "$ DAEMON | logger". logger è un comando che accederà a syslog (/ var / log / messages). Se hai bisogno anche di stderr, penso che potresti usare "$ DAEMON 1> & 2 | logger"


Hai ragione, l'uso >>è generalmente più appropriato per i daemon, anche se implica che ora dovresti creare una regola logrotate!
joeytwiddle

Per quanto riguarda lo spazio su disco, i metodi che troncano il file recupereranno lo spazio immediatamente (almeno sotto i filesystem ext). Ma attenzione ai metodi che eliminano semplicemente un file su cui si sta ancora scrivendo: lo spazio non verrà recuperato fino a quando l'handle non viene rilasciato e non è più possibile trovare il nodo del file per troncarlo manualmente!
joeytwiddle

@joeytwiddle parte del mio punto qui è che ci sono situazioni in cui logrotate non riesce a ruotare i log se l'handle del file non viene mai chiuso.
nairbv

--no-close ... | loggernon funziona per me (Debian 7.3, start-stop-daemon 1.16.12). Lo script start-stop-daemon non ritorna, sebbene / var / log / messages sia riempito :-). L'ho provato con e senza 1>&2.
hgoebl

hgoebl devi avere l'espressione "cmd | logger" tra virgolette, così l'interprete saprà che è "cmd" che stai collegando al logger, non l'espressione start-stop-daemon.
Wexxor

2

Supponendo che sia bash (sebbene anche altre shell possano consentirlo), la riga:

exec >>/tmp/myDaemon.log

invierà tutto l'output standard futuro a quel file. Questo perché execsenza un nome di programma fa solo qualche magia di reindirizzamento. Dalla bashpagina man:

Se il comando non è specificato, qualsiasi reindirizzamento avrà effetto nella shell corrente.

La gestione di tale file è ovviamente un'altra questione.


puoi chiarire dove dovrebbe essere posizionata questa linea? Subito dopo la start-stop-daemonriga menzionata nella domanda iniziale?
Abdull

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.