如何记录由 start-stop-daemon 启动的进程的标准输出?

Posted

技术标签:

【中文标题】如何记录由 start-stop-daemon 启动的进程的标准输出?【英文标题】:How can I log the stdout of a process started by start-stop-daemon? 【发布时间】:2012-01-05 07:41:06 【问题描述】:

我正在使用一个 init 脚本来运行一个简单的进程,它的开头是:

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

名为 $DAEMON 的进程通常将日志信息打印到其标准输出。据我所知,这些数据没有存储在任何地方。

我想将 $DAEMON 的标准输出写入或附加到某个文件中。

我知道的唯一解决方案是告诉 start-stop-daemon 直接调用 shellscript 而不是 $DAEMON;然后脚本调用 $DAEMON 并写入日志文件。但这需要一个额外的脚本,就像修改守护程序本身一样,似乎是解决这种常见任务的错误方法。

【问题讨论】:

【参考方案1】:

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

exec >>/tmp/myDaemon.log

会将所有未来的标准输出发送到该文件。那是因为没有程序名的exec 只是做了一些重定向魔术。来自bash 手册页:

如果没有指定command,任何重定向都会在当前shell中生效。

当然,所述文件的管理是另一个问题。

【讨论】:

你能澄清一下这条线应该放在哪里吗?在最初的问题提到的start-stop-daemon 行之后?【参考方案2】:

引用一个旧的邮件列表:

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

一个简单的 -- 如果你想使用 start-stop-daemon 可能是唯一的 -- 方法 围绕它的方法是创建一个小脚本,其中包含:

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

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

也许真正的问题是是否真的有必要使用 首先启动-停止-守护进程?

【讨论】:

【参考方案3】:

你需要做的:

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/

【讨论】:

太棒了,谢谢 ypocat。今天,除了保存日志,我还需要运行 --exec 不允许的非二进制脚本,但你的技巧可以解决! 不利的一面...停止服务会杀死 bash,但不会启动子进程 bash! (在我的例子中,DAEMON=coffee)。 我通过在 do_stop 顶部杀死 bash 进程的所有子进程来解决这个问题。 bashPID=$(cat $PIDFILE); [ -n "$bashPID" ] && pkill -P "$bashPID" 很高兴知道,pkill 解决方案也是如此。想知道... -c "exec $DAEMON..."(添加“exec”)会做什么。现在盘子里没有这个,所以不能尝试。 @ypocat 我刚刚验证它可以与 -c "exec $DAEMON..." 一起使用。这意味着不需要 pkill hack。【参考方案4】:

怎么样:

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

【讨论】:

【参考方案5】:

看来您现在应该可以在启动start-stop-daemon 时使用--no-close 参数来捕获守护程序输出。这个 new feature 在 Debian 1.16.5 版本之后在 dpkg 软件包中可用:

添加新的 --no-close 选项以禁用在 --background 上关闭 fds。

这使调用者能够查看用于调试的进程消息 目的,或者能够将文件描述符重定向到日志文件, syslog 或类似的。

【讨论】:

很遗憾它在 Ubuntu 12.04 中不可用 :( 我似乎无法让 --no-close 工作......输出仍将发送到我正在执行 init.d 脚本的 shell :( +1 在带有守护进程 node.js 服务的 Debian 挤压上完美运行。 @stantonk 您是否还将标准输出/标准错误通过管道传输到文件?完整的命令行如下所示。并确保用户 $USER 可以写入日志文件: start-stop-daemon --start --chuid $USER --pidfile $PIDFILE --background --no-close --make-pidfile --exec $DAEMON -- $DAEMONARGS >> /var/log/xxxxx.log 2>&1 这不适用于 openrc start-stop-daemon。但是 openrc 版本有 -1-2 选项来分别重定向标准输出和标准错误。【参考方案6】:

我不确定 "$DAEMON $DAEMON_ARGS > /var/log/some.log 2>&1" 是否会关闭日志文件的文件描述符...这意味着如果您的守护程序永远运行,我' m 不确定 logrotate 或其他清理磁盘空间的机制是否有效。由于它是 > 而不是 >>,因此建议的命令还会在重新启动时截断现有日志。如果您想查看守护程序崩溃的原因并自动重新启动,这可能不是很有帮助。

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

【讨论】:

你是对的,使用>> 通常更适合守护进程,尽管这意味着你现在应该创建一个 logrotate 规则! 对于磁盘空间,截断文件的方法将立即取回空间(至少在 ext 文件系统下)。但是要注意那些简单地删除一个仍在写入的文件的方法:在释放句柄之前不会回收空间,并且您再也找不到文件节点来手动截断它!跨度> @joeytwiddle 我的观点的一部分是,如果文件句柄从未关闭,logrotate 将无法旋转日志。 --no-close ... | logger 对我不起作用(Debian 7.3,start-stop-daemon 1.16.12)。尽管 /var/log/messages 已填充,但 start-stop-daemon 脚本不会返回 :-)。我在有和没有1>&2的情况下都试过了。 hgoebl 您需要将“cmd | logger”表达式放在引号中,这样解释器就会知道您正在通过管道传递给 logger 的是“cmd”,而不是 start-stop-daemon 表达式。【参考方案7】:

扩展 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 进程并忽略运行该守护进程的实际子进程。

【讨论】:

这比@ypocat 的解决方案要好得多,主要是因为通过将--start 替换为--stop 来再次关闭守护进程确实有效。 我尝试从 rc.local 而不是 init.d 运行此命令...我似乎没有得到相同的结果。但是,当通过 SSH 从 shell 运行它时,它就像一个魅力! 伴随的start-stop-daemon --test (...)会是什么样子? @MattClimbs 每次启动后都会覆盖文件。使用>> 而不是> 进行追加。 在你因为你的日志是空的而吓坏(像我一样)之前,请注意这是缓冲的!您可以使用“exec stdbuf -oL -eL $DAEMON $DAEMONARGS > $LOGFILE 2>&1”强制输出刷新每一行(来自blog.lanyonm.org/articles/2015/01/11/…)【参考方案8】:

捕获守护进程的输出并将其保存到文件中并不难:

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

但是,对于logrotate,此解决方案可能不是最理想的。

将输出捕获到系统日志可能会更好。在 Debian 上,这将匹配 systemd 服务的行为。 以下直接重写上述示例的尝试是错误,因为它在停止守护进程后留下了两个无父(“僵尸”)进程(记录器和守护进程),因为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 时终止其子级。有一些:

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

注意:uid=65534 是用户 nobody

优点:它可以工作,而且相对容易。缺点:4 个进程(主管 duende,它的叉子具有已删除的权限(记录器),@ 987654336@ 和守护进程本身);强制--chroot; 如果守护程序立即终止(例如无效命令)status_of_proc -p $PIDFILE "$DAEMON" "$NAME" 报告它已成功启动。

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

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

pipexec(获胜者):

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" 正确报告失败。缺点:无。

这是赢家——最简单、简洁的解决方案似乎运行良好。

【讨论】:

要使用单独的文件登录,请参阅 ***.com/questions/15045946/… 下的 Ansgar Wiechers 回答【参考方案9】:

通常start-stop-daemon 在后台运行时会关闭标准文件描述符。 来自start-stop-daemon的手册页:

-C, --no-close 强制守护程序进入后台时不要关闭任何文件描述符。用于调试目的以查看 进程输出,或重定向文件描述符以记录进程输出。仅在使用 --background 时相关。

这个对我有用:

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

【讨论】:

【参考方案10】:

使用 openrc(例如,这是 gentoo 或 alpine linux 上的默认设置)start-stop-daemon 具有 -1-2 选项:

-1, --stdout 将标准输出重定向到文件

-2, --stderr 将标准错误重定向到文件

所以你可以写:

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

【讨论】:

【参考方案11】:

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

这会将进程start-stop-daemon 的stdout/stderr 重定向到文件。并且您的可执行文件从其父进程 start-stop-daemon 继承 stdout/stderr。

【讨论】:

以上是关于如何记录由 start-stop-daemon 启动的进程的标准输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过start-stop-daemon优雅地关闭Spring Boot应用程序[重复]

如何防止 start-stop-daemon 在 cronjob 中创建多个实例?

start-stop-daemon 在外部脚本条件下运行

什么是 linux 脚本中的 start-stop-daemon?

start-stop-daemon

关于 'start-stop-daemon' not found in PATH or not executable