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

LoggingStdoutinit.dStart Stop-Daemon

Logging Problem Overview


I am using an init script to run a simple process, which is started with:

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

The process called $DAEMON usually prints log information to its standard output. As far as I can tell this data is not being stored anywhere.

I would like to write or append the stdout of $DAEMON to a file somewhere.

The only solution I know is to tell start-stop-daemon to call a shellscript instead of $DAEMON directly; the script then calls $DAEMON and writes to the logfile. But that requires an extra script which, like modifying the daemon itself, seems the wrong way to solve such a common task.

Logging Solutions


Solution 1 - Logging

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.

Solution 2 - Logging

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.

Solution 3 - Logging

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.

Solution 4 - Logging

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

Solution 5 - Logging

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.

Solution 6 - Logging

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

Solution 7 - Logging

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?

Solution 8 - Logging

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"

Solution 9 - Logging

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.

Solution 10 - Logging

there is an option --no-close for start-stop-daemon, which means "don't close any fd when it's run background."

start-stop-daemon --start --quiet --chuid $DAEMONUSER    \
    --make-pidfile --pidfile $PIDFILE --background       \
    --exec $DAEMON --no-close \
    -- $DAEMON_ARGS > /var/log/some.log 2>&1

this redirect the stdout/stderr of process start-stop-daemon to the file. and your executable inherits stdout/stderr from its parent process start-stop-daemon.

Solution 11 - Logging

How about:

sudo -u myuser -i start-stop-daemon ...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjoeytwiddleView Question on Stackoverflow
Solution 1 - LoggingstormbetaView Answer on Stackoverflow
Solution 2 - LoggingyouurayyView Answer on Stackoverflow
Solution 3 - LoggingStéphaneView Answer on Stackoverflow
Solution 4 - Logginglittle-dudeView Answer on Stackoverflow
Solution 5 - LoggingOnlyjobView Answer on Stackoverflow
Solution 6 - LoggingRaashid MuhammedView Answer on Stackoverflow
Solution 7 - LoggingjoeytwiddleView Answer on Stackoverflow
Solution 8 - LoggingnairbvView Answer on Stackoverflow
Solution 9 - LoggingpaxdiabloView Answer on Stackoverflow
Solution 10 - LoggingZimView Answer on Stackoverflow
Solution 11 - Loggingjakub.piaseckiView Answer on Stackoverflow