How can I log the stdout of a process started by s

2019-01-16 01:28发布

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.

10条回答
Anthone
2楼-- · 2019-01-16 01:52

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.

查看更多
唯我独甜
3楼-- · 2019-01-16 01:53

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.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-16 01:58

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.

查看更多
啃猪蹄的小仙女
5楼-- · 2019-01-16 01:58

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
查看更多
登录 后发表回答