如何记录由 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 这不适用于 openrcstart-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
时终止其子级。有一些:
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"
报告它已成功启动。
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 个进程(主管 daemon
、su
和守护进程本身)。缺点:由于混乱,难以管理 $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 个进程(主管 pipexec
、logger
和守护进程本身);如果守护程序立即终止(例如无效命令)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 中创建多个实例?