这似乎是以前被问过的问题,但我在任何地方都找不到。
我有一个在计时器上运行的 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 作为正文的电子邮件。相当光滑,是吧?
这就是我想要服务做的事情。默认情况下将标准输出打印到日志,但将标准错误重定向到我选择的命令。我首先尝试了这个:
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]'