Como posso registrar o stdout de um processo iniciado pelo start-stop-daemon?

120

Estou usando um script init para executar um processo simples, iniciado com:

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

O processo chamado $ DAEMON normalmente imprime informações de log em sua saída padrão. Tanto quanto posso dizer, esses dados não estão sendo armazenados em nenhum lugar.

Gostaria de escrever ou anexar o stdout de $ DAEMON a um arquivo em algum lugar.

A única solução que eu sei é dizer ao start-stop-daemon para chamar um shellscript em vez de $ DAEMON diretamente; o script chama $ DAEMON e grava no arquivo de log. Mas isso requer um script extra que, como modificar o próprio daemon, parece a maneira errada de resolver uma tarefa tão comum.

joeytwiddle
fonte

Respostas:

127

Para expandir a resposta do ypocat, já que não me permite 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 executar o daemon permite parar para parar corretamente o processo filho, em vez de apenas o pai bash.

Usar em --startasvez de --execgarantir que o processo seja corretamente detectado pelo seu pid e não iniciará erroneamente várias instâncias do daemon se o início for chamado várias vezes. Caso contrário, o start-stop-daemon procurará um processo / bin / bash e ignorará o processo filho real que está executando o daemon.

stormbeta
fonte
2
Essa é uma solução muito melhor que a do @ypocat, principalmente porque o desligamento do daemon novamente, substituindo-o --startpor --stoprealmente funciona.
aef 15/05
Tentei executar este comando a partir do rc.local em vez de init.d ... Parece que não estou obtendo os mesmos resultados. No entanto, ao executá-lo a partir de um shell através do SSH, ele funciona como um encanto!
nemo
1
Como seria o acompanhamento start-stop-daemon --test (...)?
Abdull
2
@MattClimbs Sobrescreve o arquivo após cada início. use em >>vez de >para anexar.
Miau
2
Antes de você surtar (como eu) porque seu log estava vazio, lembre-se de que isso é armazenado em buffer! Você pode usar "exec stdbuf -oL -e $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1" para forçar a saída para liberar cada linha (em blog.lanyonm.org/articles/2015/01/11/… )
piers7
47

Você precisa fazer:

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"

Além disso, se você usar --chuidou --user, verifique se o usuário pode gravar /var/logou o existente /var/log/some.log. A melhor maneira é fazer com que esse usuário possua um /var/log/subdir/pensamento.

youurayy
fonte
1
Fantástico, obrigado ypocat. Hoje, além de salvar o log, eu precisava executar um script não-binário que --exec não permite, mas seu truque funciona!
Joeytwiddle
8
A desvantagem ... interromper o serviço mata o bash, mas não o bash do processo filho foi iniciado! (No meu caso, DAEMON = café).
Joeytwiddle
1
Eu resolvi isso matando todos os processos filhos do processo bash na parte superior do do_stop. bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
Joeytwiddle 12/12/12
5
É bom saber, e a pkillsolução também. Pensando no que faria ... -c "exec $DAEMON..."(adicionando o "exec") faria. Não coloque isso no prato agora, então não pode tentar.
youurayy
12
@ypocat Acabei de verificar que ele funciona com -c "exec $ DAEMON ...". Isso significa que não são necessários hacks pkill.
22712 overthink
40

Parece que você deve poder usar agora o --no-closeparâmetro ao começar start-stop-daemona capturar a saída do daemon. Este novo recurso está disponível no dpkgpacote desde a versão 1.16.5 no Debian:

Adicione a nova opção --no-close para desativar o fechamento de fds no --background.

Isso permitiu ao chamador ver mensagens do processo para fins de depuração ou redirecionar descritores de arquivos para arquivos de log, syslog ou similares.

Stéphane
fonte
8
É uma pena que ele não está disponível no Ubuntu 12.04 :(
Leon Radley
Eu não consigo obter que --no-perto de trabalho ... a saída ainda está indo para a concha que eu estou executando o script init.d de :(
stantonk
O +1 funciona perfeitamente na compressão Debian com um serviço node.js daemonized.
Speakr
2
@stantonk Você também canalizou stdout / stderr para um arquivo? A linha de comando completa é a seguinte. E certifique-se de que o arquivo de log possa ser gravado pelo usuário $ USER: start-stop-daemon --start --chuid $ USER --pidfile $ PIDFILE --background --no-close --make-pidfile --exec $ DAEMON Você pode usar o seguinte comando: # $ DAEMONARGS >> /var/log/xxxxx.log 2> & 1
nharrer
1
Isso não está disponível com o openrc start-stop-daemon. No entanto, a versão do openrc tem as opções -1e -2para redirecionar o stdout e o stderr, respectivamente.
pouco cara
14

Com o openrc (que é o padrão no gentoo ou no linux alpino por exemplo) start-stop-daemontem as opções -1e -2:

-1, --stdout Redireciona o stdout para o arquivo

-2, --stderr Redireciona o stderr para o arquivo

Então você pode escrever:

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

Não é muito difícil capturar a saída do daemon e salvá-la no arquivo:

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

No entanto, esta solução pode estar abaixo do ideal para logrotate.

Talvez seja melhor capturar a saída no syslog. No Debian, isso corresponderia ao comportamento dos serviços systemd. A seguinte tentativa direta de reescrever o exemplo acima está incorreta porque deixa para trás dois processos sem pai ("zumbi") (logger e daemon) depois de parar o daemon porque start-stop-daemonencerra apenas seu filho, mas não todos os descendentes:

## 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 fazê-lo funcionar, precisamos de um invólucro que encerra suas crianças após o recebimento SIGTERMde start-stop-daemon. Há alguns:

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é um usuário nobody.

Prós : funciona e é relativamente fácil.
Contras : 4 processos (supervisor duende, seu fork com privilégios eliminados (logger) sue o próprio daemon); obrigatório --chroot; Se o daemon terminar imediatamente (por exemplo, comando inválido), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"relate-o como iniciado com sucesso.

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

Prós : 3 processos (supervisor daemon, sue daemon si).
Contras : difícil de gerenciar $PIDFILEdevido a opções confusas de linha de comando do daemon ; Se o daemon terminar imediatamente (por exemplo, comando inválido), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"relate-o como iniciado com sucesso.

pipexec ( o vencedor ):

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

Prós : 3 processa (supervisor pipexec, loggere daemon si); Se o daemon terminar imediatamente (por exemplo, comando inválido), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"relate corretamente a falha.
Contras : nenhum.

Esse é o vencedor - a solução mais fácil e organizada que parece estar funcionando bem.

Onlyjob
fonte
7

Geralmente start-stop-daemonfecha os descritores de arquivo padrão ao executar em segundo plano. Na página do manual de start-stop-daemon:

-C, --no-close
Não feche nenhum descritor de arquivo ao forçar o daemon em segundo plano. Usado para fins de depuração para ver a saída do processo ou redirecionar descritores de arquivo para registrar a saída do processo. Somente relevante ao usar --background.

Este funcionou para mim:

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

Citando uma lista de discussão antiga:

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

Uma maneira fácil - e se você quiser usar o start-stop-daemon, talvez o único -, contornar isso é criar um pequeno script contendo:

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

e use esse script como argumento para iniciar-parar-daemon.

Talvez a verdadeira questão, no entanto, seja se é realmente necessário usar o start-stop-daemon em primeiro lugar?

joeytwiddle
fonte
3

Não tenho certeza se "$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1" fechará o descritor de arquivo do arquivo de log ... o que significa que se o seu daemon for executado para sempre, não tenho certeza esse logrotate ou outros mecanismos para limpar o espaço em disco funcionariam. Como é> em vez de >>, o comando sugerido também truncará os logs existentes na reinicialização. Se você deseja ver por que o daemon travou e é reiniciado automaticamente, isso pode não ser muito útil.

Outra opção pode ser "$ DAEMON | logger". logger é um comando que fará logon no syslog (/ var / log / messages). Se você também precisar do stderr, acho que poderia usar "$ DAEMON 1> & 2 | logger"

nairbv
fonte
Você está correto, o uso >>geralmente é mais apropriado para daemons, embora isso implique que agora você deve criar uma regra de rotação de log!
Joeytwiddle #
Quanto ao espaço em disco, os métodos que truncam o arquivo recuperam o espaço imediatamente (pelo menos nos sistemas de arquivos ext). Mas tome cuidado com métodos que simplesmente excluem um arquivo que ainda está sendo gravado: o espaço não será recuperado até que o identificador seja liberado e você não poderá mais encontrar o nó do arquivo para truncá-lo manualmente!
Joeytwiddle
@joeytwiddle parte do meu argumento aqui é que há situações em que o logrotate falhará ao girar os logs se o identificador do arquivo nunca for fechado.
Nairbv
--no-close ... | loggernão funciona para mim (Debian 7.3, start-stop-daemon 1.16.12). O script start-stop-daemon não volta, embora / var / log / messages esteja preenchido :-). Eu tentei com e sem 1>&2.
precisa saber é
hgoebl, você precisa ter a expressão "cmd | logger" entre aspas, para que o intérprete saiba que é "cmd" que você está direcionando para o logger, não a expressão start-stop-daemon.
Wexxor
2

Supondo que seja bash (embora algumas outras conchas possam permitir isso também), a linha:

exec >>/tmp/myDaemon.log

enviará toda a saída padrão futura para esse arquivo. Isso execocorre porque sem o nome de um programa, apenas faz alguma mágica de redirecionamento. Na bashpágina do manual:

Se o comando não for especificado, qualquer redirecionamento entrará em vigor no shell atual.

O gerenciamento desse arquivo é outra questão, é claro.

paxdiablo
fonte
você pode esclarecer onde essa linha deve ser colocada? Logo após a start-stop-daemonlinha que a pergunta inicial mencionou?
Abdull
1

E se:

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