Jak mogę zarejestrować standardowe wyjście procesu uruchomionego przez start-stop-daemon?

120

Używam skryptu init do uruchomienia prostego procesu, który zaczyna się od:

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

Proces o nazwie $ DAEMON zwykle wypisuje informacje dziennika na swoje standardowe wyjście. O ile wiem, te dane nie są nigdzie przechowywane.

Chciałbym napisać lub dołączyć gdzieś standardowe wyjście $ DAEMON do pliku.

Jedynym rozwiązaniem, jakie znam, jest polecenie start-stop-daemonowi, aby bezpośrednio wywołał skrypt powłoki zamiast $ DAEMON; skrypt następnie wywołuje $ DAEMON i zapisuje do pliku dziennika. Ale to wymaga dodatkowego skryptu, który, podobnie jak modyfikacja samego demona, wydaje się niewłaściwym sposobem rozwiązania tak powszechnego zadania.

joeytwiddle
źródło

Odpowiedzi:

127

Aby rozwinąć odpowiedź ypocat, ponieważ nie pozwala mi komentować:

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"

Użycie execdo uruchomienia demona umożliwia zatrzymanie, aby poprawnie zatrzymać proces potomny zamiast tylko rodzica bash.

Użycie --startaszamiast --execzapewnia, że ​​proces zostanie poprawnie wykryty przez jego pid i nie uruchomi błędnie wielu instancji demona, jeśli start zostanie wywołany wiele razy. W przeciwnym razie start-stop-daemon będzie szukał procesu / bin / bash i zignoruje rzeczywisty proces potomny, na którym działa demon.

stormbeta
źródło
2
Jest to o wiele lepsze rozwiązanie niż @ypocat, głównie dlatego, że ponowne wyłączenie demona poprzez zastąpienie --startgo --stopfaktycznie działa.
aef
Próbowałem uruchomić to polecenie z rc.local zamiast z init.d ... Wydaje się, że nie uzyskuję takich samych wyników. Jednak uruchamianie go z powłoki przez SSH działa jak urok!
nemo
1
Jak wyglądałby towarzyszący start-stop-daemon --test (...)?
Abdull
2
@MattClimbs Zastępuje plik po każdym uruchomieniu. użyj >>zamiast >dołączania.
Meow
2
Zanim przestraszysz się (tak jak ja), ponieważ twój dziennik był pusty, pamiętaj, że jest to buforowane! Możesz użyć "exec stdbuf -oL -eL $ DAEMON $ DAEMONARGS> $ LOGFILE 2> & 1", aby wymusić na wyjściu opróżnienie każdej linii (z blog.lanyonm.org/articles/2015/01/11/... )
piers7
47

Musisz zrobić:

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"

Również jeśli używasz --chuidlub --user, upewnij się, że użytkownik może pisać do /var/loglub istniejącego /var/log/some.log. Najlepszym sposobem jest pozostawienie tego użytkownika jako właściciela /var/log/subdir/.

youurayy
źródło
1
Fantastycznie, dziękuję ypocat. Dzisiaj, oprócz zapisania dziennika, potrzebowałem uruchomić niebinarny skrypt, na który --exec nie pozwala, ale twoja sztuczka działa!
joeytwiddle
8
Wada ... zatrzymanie usługi zabija bash, ale nie rozpoczął się proces potomny! (W moim przypadku DAEMON = kawa).
joeytwiddle
1
Obejrzałem to, zabijając wszystkie procesy potomne procesu bash na początku do_stop. bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID"
joeytwiddle
5
Dobrze wiedzieć, a także pkillrozwiązanie. Zastanawiasz się, co by się stało ... -c "exec $DAEMON..."(dodanie "exec"). Nie miej tego teraz na talerzu, więc nie mogę tego spróbować.
youurayy
12
@ypocat Właśnie sprawdziłem, że działa z -c "exec $ DAEMON ...". Oznacza to, że nie są wymagane żadne hacki.
overthink
40

Wygląda na to, że powinieneś być w stanie użyć tego --no-closeparametru teraz , gdy zaczynasz start-stop-daemonprzechwytywać wyjście demona. Ta nowa funkcja jest dostępna w dpkgpakiecie od wersji 1.16.5 na Debianie:

Dodaj nową opcję --no-close, aby wyłączyć zamykanie fds na --background.

Umożliwiło to wywołującemu przeglądanie komunikatów procesowych w celu debugowania lub przekierowanie deskryptorów plików do plików dziennika, syslog lub podobnych.

Stéphane
źródło
8
Szkoda, że ​​nie jest dostępny w Ubuntu 12.04 :(
Leon Radley
Wydaje się, że nie mogę tego uzyskać - nie-blisko do pracy ... dane wyjściowe nadal trafiają do powłoki, z której
wykonuję
+1 Działa doskonale na Debianie squeeze z zdemonizowaną usługą node.js.
speakr
2
@stantonk Czy również potokowałeś stdout / stderr do pliku? Pełna linia poleceń wygląda następująco. I upewnij się, że plik dziennika może zostać zapisany przez użytkownika $ 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
Nie jest to dostępne z openrc start-stop-daemon. Jednak wersja openrc ma opcje -1i -2do przekierowania odpowiednio stdout i stderr.
mały koleś
14

Z openrc (który jest domyślny na przykład w gentoo lub alpine linux) start-stop-daemonma opcje -1i -2:

-1, --stdout Przekierowuje standardowe wyjście do pliku

-2, --stderr Przekierowuje stderr do pliku

Możesz więc po prostu napisać:

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON $DAEMON_ARGS -1 $LOGFILE -2 $LOGFILE
mały kumpel
źródło
9

Przechwycenie wyjścia demona i zapisanie go do pliku nie jest zbyt trudne:

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

Jednak to rozwiązanie może być nieoptymalne dla logrotate.

Lepiej byłoby przechwycić dane wyjściowe do syslog. W Debianie pasowałoby to do zachowania usług systemowych. Poniższa prosta próba przepisania powyższego przykładu jest błędna, ponieważ po zatrzymaniu demona pozostawia dwa procesy bez rodzica („zombie”) (rejestrator i demon), ponieważ start-stop-daemonkończy tylko jego dziecko, ale nie wszystkie elementy podrzędne:

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

Aby to działało, potrzebujemy opakowania, które kończy swoje dzieci po otrzymaniu SIGTERMod start-stop-daemon. Tam jest trochę:

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

Uwaga: uid=65534jest użytkownikiem nobody.

Plusy : działa i jest stosunkowo łatwe.
Wady : 4 procesy (nadzorca duende, jego rozwidlenie z utraconymi uprawnieniami (rejestrator) sui sam demon); obowiązkowe --chroot; Jeśli demon natychmiast się zakończy (np. Nieprawidłowa komenda) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"zgłoś, że został pomyślnie uruchomiony.

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

Zalet : 3 procesy (promotor daemon, sui demon siebie).
Wady : Trudne w zarządzaniu $PIDFILEze względu na mylące opcje wiersza poleceń demona ; Jeśli demon natychmiast się zakończy (np. Nieprawidłowa komenda) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"zgłoś, że został pomyślnie uruchomiony.

pipexec ( zwycięzca ):

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

Zalet : 3 procesy (promotor pipexec, loggeri demon siebie); Jeśli demon natychmiast się zakończy (np. Nieprawidłowa komenda), status_of_proc -p $PIDFILE "$DAEMON" "$NAME"poprawnie zgłoś błąd.
Wady : brak.

Oto zwycięzca - najłatwiejsze, zgrabne rozwiązanie, które wydaje się działać dobrze.

Onlyjob
źródło
7

Zwykle start-stop-daemonzamyka standardowe deskryptory plików, gdy działa w tle. Ze strony podręcznika man start-stop-daemon:

-C, --no-close
Nie zamyka żadnego deskryptora pliku podczas wymuszania działania demona w tle. Służy do debugowania w celu wyświetlenia danych wyjściowych procesu lub do przekierowania deskryptorów plików w celu zarejestrowania danych wyjściowych procesu. Ma znaczenie tylko w przypadku korzystania z --background.

Ten pracował dla mnie:

    start-stop-daemon -b -C -o -c \ 
         $DAEMON_USER -S -x $DAEMON > $DAEMON_LOG 2>&1
Raashid Muhammed
źródło
4

Cytując starą listę mailingową:

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

Łatwym - i jeśli chcesz użyć demona start-stop-być może jedynym - sposobem obejścia tego jest utworzenie małego skryptu zawierającego:

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

a następnie użyj tego skryptu jako argumentu start-stop-daemon.

Być może prawdziwe pytanie brzmi jednak, czy naprawdę konieczne jest użycie demona start-stop-w pierwszej kolejności?

joeytwiddle
źródło
3

Nie jestem pewien, czy „$ DAEMON $ DAEMON_ARGS> /var/log/some.log 2> & 1” kiedykolwiek zamknie deskryptor pliku dla pliku dziennika ... co oznacza, że ​​jeśli twój demon będzie działał wiecznie, nie jestem pewien że logrotate lub inne mechanizmy czyszczenia miejsca na dysku będą działać. Ponieważ jest to> zamiast >>, sugerowane polecenie spowodowałoby również obcięcie istniejących dzienników przy ponownym uruchomieniu. Jeśli chcesz zobaczyć, dlaczego demon się zawiesił i uruchamia się ponownie automatycznie, może to nie być zbyt pomocne.

Inną opcją może być „$ DAEMON | logger”. logger to polecenie, które będzie logować się do syslog (/ var / log / messages). Jeśli potrzebujesz również stderr, myślę, że możesz użyć „$ DAEMON 1> & 2 | logger”

nairbv
źródło
Masz rację, używanie >>jest generalnie bardziej odpowiednie dla demonów, chociaż sugeruje, że powinieneś teraz utworzyć regułę logrotate!
joeytwiddle
Jeśli chodzi o miejsce na dysku, metody, które skracają plik, natychmiast odzyskają miejsce (przynajmniej w systemach plików ext). Uważaj jednak na metody, które po prostu usuwają plik, w którym nadal jest zapisywany: miejsce nie zostanie odzyskane, dopóki uchwyt nie zostanie zwolniony i nie możesz już znaleźć węzła pliku, aby go ręcznie skrócić!
joeytwiddle
@joeytwiddle częścią mojego punktu jest to, że są sytuacje, w których logrotate nie obróci dzienników, jeśli uchwyt pliku nigdy nie zostanie zamknięty.
nairbv
--no-close ... | loggernie działa dla mnie (Debian 7.3, start-stop-daemon 1.16.12). Skrypt start-stop-daemon nie wraca, chociaż / var / log / messages jest wypełnione :-). Próbowałem z i bez 1>&2.
hgoebl
hgoebl musisz mieć wyrażenie "cmd | logger" w cudzysłowach, aby interpreter wiedział, że to "cmd" przesyłasz do loggera, a nie wyrażenie start-stop-daemon.
Wexxor
2

Zakładając, że jest to bash (chociaż niektóre inne powłoki również na to pozwalają), wiersz:

exec >>/tmp/myDaemon.log

wyśle ​​wszystkie przyszłe standardowe wyjście do tego pliku. Dzieje się tak, ponieważ execbez nazwy programu po prostu wykonuje magię przekierowania. Ze strony podręcznika bash:

Jeśli polecenie nie zostanie określone, wszelkie przekierowania odniosą skutek w bieżącej powłoce.

Zarządzanie tym plikiem to oczywiście inna kwestia.

paxdiablo
źródło
czy możesz wyjaśnić, gdzie ma być umieszczona ta linia? Zaraz po start-stop-daemonwersie, o którym wspomniało pierwsze pytanie?
Abdull
1

Co powiesz na:

sudo -u myuser -i start-stop-daemon ...
jakub.piasecki
źródło