How can I log the stdout of a process started by start-stop-daemon?

落爺英雄遲暮 提交于 2019-11-28 02:48:07
stormbeta

To expand on ypocat's answer, since it won't let me comment:

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"

Using exec to run the daemon allows stop to correctly stop the child process instead of just the bash parent.

Using --startas instead of --exec ensures that the process will be correctly detected by its pid and won't erroneously start multiple instances of the daemon if start is called multiple times. Otherwise, start-stop-daemon will look for a /bin/bash process and ignore the actual child process running the daemon.

youurayy

You need to do:

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"

Also if you use --chuid or --user, make sure the user can write to /var/log or the existing /var/log/some.log. The best way is to have that user own a /var/log/subdir/ though.

It seems you should be able to use now the --no-close parameter when starting start-stop-daemon to capture the daemon output. This new feature is available in the dpkg package since version 1.16.5 on Debian:

Add new --no-close option to disable closing fds on --background.

This enabled the caller to see process messages for debugging purposes, or to be able to redirect file descriptors to log files, syslog or similar.

With openrc (which is the default on gentoo or alpine linux for instance) start-stop-daemon has the -1 and -2 options:

-1, --stdout Redirect stdout to file

-2, --stderr Redirect stderr to file

So you can just write:

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

It is not too hard to capture daemon's output and save it to file:

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

However this solution may be suboptimal for logrotate.

It might be better to capture output to syslog. On Debian this would match behaviour of systemd services. The following straightforward attempt to rewrite the above example is wrong because it leaves behind two parent-less ("zombie") processes (logger and daemon) after stopping the daemon because start-stop-daemon terminates only its child but not all 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"""

To make it work we need a wrapper that terminates its children upon receiving SIGTERM from start-stop-daemon. There are some:

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

Note: uid=65534 is a user nobody.

Pros: it works and it is relatively easy.
Cons: 4 processes (supervisor duende, its fork with dropped privileges (logger), su and daemon itself); mandatory --chroot; If daemon terminates right away (e.g. invalid command) status_of_proc -p $PIDFILE "$DAEMON" "$NAME" report it as started successfully.

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

Pros: 3 processes (supervisor daemon, su and daemon itself).
Cons: Difficult to manage $PIDFILE due to confusing daemon's command line options; If daemon terminates right away (e.g. invalid command) status_of_proc -p $PIDFILE "$DAEMON" "$NAME" report it as started successfully.

pipexec (the winner):

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 processes (supervisor pipexec, logger and daemon itself); If daemon terminates right away (e.g. invalid command) status_of_proc -p $PIDFILE "$DAEMON" "$NAME" correctly report failure.
Cons: none.

This is the winner -- the easiest, neat solution that seems to be working well.

Usually start-stop-daemon closes the standard file descriptors when running in the background. From the man page of start-stop-daemon:

-C, --no-close
Do not close any file descriptor when forcing the daemon into the background. Used for debugging purposes to see the process output, or to redirect file descriptors to log the process output. Only relevant when using --background.

This one worked for me:

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

Quoting an old mailing list:

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

An easy -- and if you want to use start-stop-daemon perhaps the only -- way around it is to create a small script containing:

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

and then use that script as the argument to start-stop-daemon.

Perhaps the real question however is whether it is really necessary to use start-stop-daemon in the first place?

I'm not sure if "$DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1" will ever close the file descriptor for the log file... which means if your daemon runs forever, I'm not sure that logrotate or other mechanisms for cleaning up disk space would work. Since it's > instead of >>, the suggested command would also truncate existing logs on restart. If you want to see why the daemon crashed, and it restarts automatically, that might not be very helpful.

Another option might be "$DAEMON | logger". logger is a command that will log to syslog (/var/log/messages). If you need stderr too, I think you could use "$DAEMON 1>&2 | logger"

Assuming it's bash (although some other shells may allow this as well), the line:

exec >>/tmp/myDaemon.log

will send all future standard output to that file. That's because exec without a program name just does some redirection magic. From the bash man page:

If command is not specified, any redirections take effect in the current shell.

Management of said file is another issue of course.

How about:

sudo -u myuser -i start-stop-daemon ...
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!