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

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.

105223 次浏览

假设它是 bash (尽管其他一些 shell 可能也允许这样做) ,行:

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:

如果未指定 command,则任何重定向将在当前 shell 中生效。

Management of said file is another issue of course.

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

然后使用该脚本作为 start-stop-daemon 的参数。

然而,或许真正的问题在于是否真的有必要使用 启动,停止,守护进程?

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"

此外,如果您使用 --chuid--user,请确保用户可以写入 /var/log或现有的 /var/log/some.log。最好的方法是让用户拥有一个 /var/log/subdir/

这个怎么样:

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

现在似乎可以在启动 start-stop-daemon时使用 --no-close参数来捕获守护进程的输出。这个 新功能在 Debian 版本1.16.5之后的 dpkg包中就有了:

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

This enabled the caller to see process messages for debugging 或者能够将文件描述符重定向到日志文件, Syslog 或类似的。

我不确定“ $DAEMON $DAEMON _ ARGS >/var/log/some. log 2 > & 1”是否会关闭日志文件的文件描述符... ... 这意味着如果您的守护进程永远运行,我不确定 logrotl 或其他清理磁盘空间的机制是否有效。因为它是 > 而不是 > > ,所以建议的命令在重新启动时也会截断现有的日志。如果您想知道守护进程崩溃的原因,并且它会自动重新启动,那可能没有多大帮助。

另一个选项可能是“ $DAEMON | logger”。Logger 是一个将日志记录到 syslog (/var/log/message)的命令。如果您也需要 stderr,我认为您可以使用“ $DAEMON 1 > & 2 | logger”

详述 ypocat 的回答,因为它不让我评论:

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"

使用 exec运行守护进程允许 stop 正确地停止子进程,而不仅仅是 bash 父进程。

使用 --startas而不是 --exec可以确保进程将被其 pid 正确检测到,并且如果 start 被多次调用,则不会错误地启动守护进程的多个实例。否则,start-stop-daemon 将查找/bin/bash 进程,并忽略运行守护进程的实际子进程。

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

然而,这种解决方案可能是次优的 logrotate

将输出捕获到 syslog 可能更好,在 Debian上,这将匹配 systemd 服务的行为。 下面是重写上面示例的简单尝试,即 错了,因为它在停止守护进程后留下了两个没有父进程(“僵尸”)的进程(logger 和 daemon) ,因为 start-stop-daemon只终止它的子进程,而不是所有子进程:

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

为了让它工作,我们需要一个包装器,在从 start-stop-daemon接收到 SIGTERM时终止它的子级:

魅力:
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"""

注意: uid=65534是一个用户 nobody

Pros: it works and it is relatively easy.
缺点 : 4个进程(主管 duende,其带有删除特权的 fork (logger)、 su和守护进程本身) ; 强制 --chroot; 如果守护进程立即终止(例如,无效命令) ,status_of_proc -p $PIDFILE "$DAEMON" "$NAME"会报告它已成功启动。

守护进程 :
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"""

优点 : 3个进程(主管 daemonsu和守护进程本身)。
缺点 : 由于混淆了 Daemon的命令行选项,难以管理 $PIDFILE; 如果守护进程立即终止(例如,无效命令) ,status_of_proc -p $PIDFILE "$DAEMON" "$NAME"会报告它已成功启动。

Piexec (赢家) :

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

优点 : 3个进程(主管 pipexeclogger和守护进程本身) ; 如果守护进程立即终止(例如无效命令) status_of_proc -p $PIDFILE "$DAEMON" "$NAME"正确报告失败。
缺点: 没有。

这就是胜利者——最简单、最巧妙的解决方案,看起来效果不错。

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

- 第三,不-差不多
在强制将守护进程放入后台时,不要关闭任何文件描述符。用于调试目的,以查看 进程输出,或者重定向文件描述符以记录进程输出。

这个对我很管用:

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

对于 openrc (这是 gentoo 或者 alpine linux 的默认选项) ,start-stop-daemon-1-2选项:

-1,—— stdout 将 stdout 重定向到文件

-2,—— stderr 将 stderr 重定向到文件

所以你可以写:

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

start-stop-daemon有一个选项 --no-close,这意味着“在运行后台时不要关闭任何 fd”

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.