【问题标题】:How can I log the stdout of a process started by start-stop-daemon?如何记录由 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 并写入日志文件。但这需要一个额外的脚本,就像修改守护程序本身一样,似乎是解决这种常见任务的错误方法。

【问题讨论】:

    标签: logging stdout init.d start-stop-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" 正确报告失败。
        缺点:无。

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

        【讨论】:

        【解决方案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。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-09-29
              • 2013-09-05
              • 2017-11-20
              • 2013-07-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多