将 systemd 服务 STDERR 重定向到命令 (sendmail)

将 systemd 服务 STDERR 重定向到命令 (sendmail)

这似乎是以前被问过的问题,但我在任何地方都找不到。

我有一个在计时器上运行的 systemd 服务,用于更新我的软件包。我希望ssmtp每次服务抛出错误时都会收到电子邮件。

如果我以 root 身份在终端中运行它,它就可以工作。

 # /root/bin/update 2> >(printf "Subject: ERROR from update.service\n\n$(cat -)" | sendmail [email protected])
Updating package lists... Done!
Updating packages... Done!
Removing old packages... Done!
Cleaning up... Done!
Updating dotfiles... FAILED!
Updating bpytop... Done!
Updating global npm packages... Done!

失败的部分发送了 STDERR,该错误被伪文件捕获>()。将printf "...$(cat -)"主题附加到流的开头。我收到一封以 stderr 作为正文的电子邮件。相当光滑,是吧?

发送的电子邮件 update.service 的屏幕截图

这就是我想要服务做的事情。默认情况下将标准输出打印到日志,但将标准错误重定向到我选择的命令。我首先尝试了这个:

ExecStart=/root/bin/update 2> >(printf "Subject: ERROR from update.service\n\n$(cat -)" | sendmail [email protected])

但错误仍然发送到journald而不是ssmtp。我认为 systemd 会拦截 stderr 并将其发送到指定的任何地方StandardError=。该StandardError=选项允许将 stderr 发送到文件描述符或文件......所以我尝试了这样的东西:

ExecStart=/root/bin/update
StandardError=file:>(printf "Subject: ERROR from update.service\n\n$(cat -)" | sendmail [email protected])

StandardError=fd:printf "Subject: ERROR from update.service\n\n$(cat -)" | sendmail [email protected]

没用。可以将 StandardError 发送到指向 sendmail 的命名管道。我胡思乱想试图让它发挥作用,最后放弃并来到这里。

编辑:我还考虑过在发送电子邮件的更新脚本中编写一个 bash 函数,然后将脚本中每个命令的 stderr 重定向到该函数。不过,我正在寻找 systemd 级别的解决方案,而不是在脚本本身中对 STDERR 的目的地进行硬编码。

答案1

我想出了一种可能的解决方案:将 stderr 写入文件并然后使用 邮寄ExecStartPost=。我还了解到,systemd 服务文件不能很好地进行重定向,除非您将命令包装在/bin/bash -c ''

ExecStartPre=/bin/rm -f /root/update.err
ExecStart=/bin/bash -c '/root/bin/update 2>/root/update.err'
ExecStartPost=/bin/bash -c 'test -f /root/update.err && printf "Subject: ERROR from update.service\n\n$(cat /root/update.err)\n" | sendmail [email protected]'

来源:如何将 Systemd 服务标准输出从 ExecStart 传输到 shell,例如。重击?

相关内容