更新:

更新:

当我的 crontab 中出现错误时,我收到此消息:

cron: No MTA installed, discarding output

我不想在我的系统上安装 MTA,但我也不想错过这些错误消息。

cron 尝试通过邮件发送这些信息是在哪里配置的?我可以更改它,以便将这些消息发送到文件吗? (也许通过 sysylog)。

我不想记录所有 cron 消息,只想记录错误。

我的rsyslog.conf

cron.=info                    stop

*.*                          |/dev/xconsole

不幸的是,似乎即使错误消息也有.info标签

我怎样才能只记录 cron 错误?或者,换句话说:我如何发送到日志文件,如果安装了 MTA,否则会发送到什么内容?

我的系统是 Debian 10,我用于rsyslog日志记录(无 systemd)

更新:

正如 @basin 所建议的那样,对每一行单独使用重定向是我到目前为止使用的解决方案,它几乎没有问题:

首先,正如我所说,我想要一个解决方案,将通常默认发送到 MTA 的内容重定向到其他位置,即|/dev/xconsole,无需单独指定每个谎言。

其次,如果我的 crontab 行中存在语法错误,则重定向将不起作用。 Cron 仍然尝试通过 MTA 发送错误,并且我No MTA installed在日志中收到错误。

是否有某种方法可以重定向通过 MTA 发送的内容,以便将其发送(直接或通过 sysylog)到/dev/xconsole

附加问题:

当使用建议的解决方案时@Binarus,编写我自己的自定义sendmail脚本:

我可以不使用默认值/usr/sbin/sendmail,而是为自定义脚本指定其他位置,例如/usr/local/sbin/sendmail?中的cron信息在哪里?这是硬编码的,还是可以在 cron 的配置文件之一中进行配置?sendmail/usr/sbin/

答案1

我相信我有一个解决方案,但只测试了一半。不幸的是,我无法测试/dev/xconsole,因为我的系统上没有该设备,而且我承认我什至不知道它是什么并且我没有时间研究它。

不过,有两个好处:第一,下面的方法是通用的;也就是说,您几乎肯定可以使用/dev/xconsole而不是我使用的文件名。其次,我有只是在 Debian Buster 上对其进行了测试,因此它确实应该可以开箱即用。

我将首先展示(非常简单)的解决方案,然后解释它是如何工作的,然后展示一些可能的问题以及如何规避它们。

解决方案

作为预防措施,请先检查您是否拥有/usr/sbin/sendmail。这应该不是是这样的,因为这个程序通常属于MTA,但你说你没有安装MTA。如果存在,请卸载它所在的包。

/usr/sbin/sendmail现在,创建一个包含以下内容的脚本:

#!/bin/bash
cat >>/root/result

相应地设置权限:

chmod a+rx,u+w,og-w /usr/sbin/sendmail

重新开始cron

systemctl restart cron

就是这样cron通常通过电子邮件发送的所有错误消息现在都将进入/root/result.

当然,您必须以 root 用户身份执行上述步骤。

在你的情况下,你可能想要替换/root/result/dev/xconsole(但请记住,我还没有测试过这个,如上所述:-)),并且你最终应该替换>>>(但由于我对 完全一无所知/dev/xconsole,这可能是错误的) 。

它是如何工作的?

定义: 在下文中,我将使用 SENDMAIL 来表示 SENDMAIL 软件包,并使用 来sendmail表示应用程序。

大多数(或至少是许多)发送电子邮件消息的程序本身并不实现 SMTP 协议栈,该协议栈需要通过套接字或网络连接直接与 MTA 通信,并且也不包含 SMTP 库;从安全角度来看,犯错误将是致命的,而且这是没有必要的,因为在大多数情况下,专门的应用程序会来救援。

这些专门的应用程序之一是/usr/bin/sendmail,它具有 SMTP(以及更多功能),并且使用起来非常容易。一个常见的模式是:

cat MyMailMessage | /usr/bin/sendmail [sendmail-options]
# OR, even shorter
/usr/bin/sendmail <MyMailMessage

也就是说,应用程序构造一条邮件消息(这非常简单,因为它只需要几个标头加上实际的正文)并将其通过管道传输到sendmail,而后者又执行 SMTP 魔法。

从历史上看,SENDMAIL 曾一度是主要的 MTA。 SENDMAIL不仅包含MTA,还包含MSP(消息提交程序)。 MSP部分是在/usr/sbin/sendmail.很长一段时间以来,没有人能够摆脱 SENDMAIL,因此许多应用程序实际上仍然依赖于/usr/sbin/sendmail或至少sendmail可以用作邮件提交程序。这就是为什么即使是 SENDMAIL 的竞争对手(例如 POSTFIX)也仍然提供该程序作为兼容性包装器。

cron在这方面,其行为与其他应用程序类似。它不支持 SMTP。相反,它依赖于sendmail实际发送消息;它只是构造原始消息,包括标头和正文,并将它们通过管道传输到sendmail,而后者实际发送它们。

所以我只需替换/usr/sbin/sendmail为上面显示的脚本(因为我安装了 MTA,这只是为了测试)。当它尝试发送邮件时cron调用/usr/sbin/sendmail,这就是我们的脚本。该脚本仅获取其标准输入并将其重定向到文件。

作为旁注,我实际上不知道是否cron将原始电子邮件消息直接通过管道传输到sendmail,或者是否先将其放入临时文件中,然后从该文件进行重定向调用sendmailstdin或者是否执行其他操作。

但这在这里并不重要:关键点是在每种情况下原始电子邮件消息都是由 , 构建的cron,并将cron其放入sendmail's stdin(但是这可以完成)。

缺点、问题、改进

请注意,cat在脚本中使用可能不是效率方面的最佳选择,但这取决于您的预期输出。有无数的文章解释了如何最好地将脚本放入stdin文件中;我认为这不在你的问题范围内。

我的解决方案的一个缺点是显而易见的:如果您需要“真实” /usr/sbin/sendmail,我们就会遇到问题。我可以想象一些微妙的事情:可能有一些应用程序会根据它们是否找到/usr/sbin/sendmail.

例如,如果应用程序发现该可执行文件,则可能决定通过电子邮件发送错误,否则将错误写入日志文件。该应用程序现在将改变其行为。接下来会发生什么很大程度上取决于具体情况。首先,您可能无法在通常的位置找到错误消息。其次,由于sendmail现在是我们的简单脚本,并且不能按应用程序预期的方式工作,因此可能会发生奇怪的事情。

不过,有一个补救措施:您提到您会接受重新编译cron。我相信(但现在无法验证)在其源代码中,config.h有一个#define定义了它使用的 MSP 名称。那么补救措施就很明确了:将我们的脚本重命名为abcd1234,并将其用作 的值#define,或者 - 可能更好 - 将脚本放入另一个目录中不是在系统的搜索路径中,并使用脚本的完整路径作为#define.

当您这样做时,您最终还应该更正命令行选项,这些选项位于单独的#define;中。不过,它们不会损害我们的脚本,因为它只是忽略它们。也许您甚至可以将脚本和 directcron的错误输出直接转储到您想要的文件或设备。判断这是否可行需要对源代码进行进一步分析,但我尚未进行过分析。无论如何我都会坚持剧本;请参阅下一段,了解一个重要原因。

[ 2021 年 10 月 20 日更新:

正如我在 2021 年 10 月 20 日对您的原始问题的评论中所述,有一种解决该问题的替代方法可以使您免于重新编译:将“真实”移动sendmail到其他地方并在其位置安装脚本。然后,每当执行脚本时,让它找出谁调用了它。如果cron已调用它,则使其行为如上所示;如果没有,则使其sendmail以相同的stdin参数调用“real”,即“relay”stdin和“real”的参数sendmail

]

另一个问题是,您不仅看到您感兴趣的错误消息,而且每次看到cron都会发送整个原始电子邮件,包括标题。补救措施是在我们的脚本中添加一些代码,过滤掉您不感兴趣的行,例如使用grepsed他们的朋友。但这也不属于这个问题的范围。

答案2

您可以告诉 cron 使用 stdout/stderr 重定向器作为您的SHELL.

Cron(特别是 vixie-cron,如 Debian Buster/10 中)在新的$SHELL.此行为在中指定定时任务(5),并且定义在do_command.c,

该行的整个命令部分(直到换行符或 % 字符)将由 /bin/sh 或 crontab 文件的 SHELL 变量中指定的 shell 执行。

320 |           char    *shell = env_get("SHELL", jobenv);
... |
348 |           execle(shell, shell, "-c", e->cmd, (char *)0, jobenv);

将发送到 MTA 的是 stdout/stderr 中的任何内容$SHELL -c "<command>",无论语法错误或运行时错误如何。 (这也在“do_command.c”中定义。)因此,通过SHELL=/path/to/stdout/stderr/redirector在 cron 文件中进行设置,所有四个问题都应该得到解决:

  1. 我怎样才能发送到日志文件,如果安装了MTA,什么会发送到它?

  2. 无需单独指定每个 li[n]e

  3. 如果我的 crontab 行中有语法错误,则重定向不起作用。

  4. cron: No MTA installed, discarding output

我用输出测试了它>>/tmp/test,我认为你可以用 替换它>/dev/xconsole。或者您可以编写一个脚本来保留时间戳、详细命令等,例如系统日志的包装器。

$ cat /tmp/sh-out
#!/usr/bin/sh
1>>/tmp/test 2>>/tmp/test /usr/bin/sh "$@"
$ crontab -l
SHELL=/tmp/sh-out
* * * * * echo output
* * * * * wrong-command
$ tail -f /tmp/test
output
/usr/bin/sh: 1: wrong-command: not found

为了回答您的其他问题,

cron 从哪里获取 sendmail 所在的信息/usr/sbin/

Debian 10 和 11 使用经过大量修补的 vixie-cron。被MAILCMD定义为_PATH_SENDMAIL配置.h#L24作为/usr/bin/sendmail

是否有某种方法可以重定向通过 MTA 发送的内容,以便将其发送(直接或通过 sysylog)到/dev/xconsole

不,vixie-cron 不支持这一点,尽管您可以通过更改命令或 MTA 来解决它。

克罗尼可以做到。

       -s     This option will direct Cron to send the job output to the
              system log using syslog(3).  This is useful if your system
              does not have sendmail(8), installed or if mail is
              disabled.

然而,cronie 仅在 Debian Experimental 中,并且计划从 vixie-cron 切换到 cronie此后就没有消息了2019-11-05

不幸的是,似乎即使错误消息也有.info标签

它被硬编码在杂项.c#L589,在体内void log_it(username, xpid, event, detail)

    syslog(LOG_INFO, "(%s) %s (%s)", username, event, detail);

似乎log_it可以使用一个补丁来添加对日志级别的支持。但是,日志级别与 cron 中的命令输出无关,因为它们要么发送到 MTA,要么完全丢弃。

答案3

最简单的方法是在 crontab 中的所有任务中进行重定向:

*  *  *  *  * user-name  command to be executed >/dev/null 2>>/tmp/some.log

或者,cronie有这个选项:

   -m     This option allows you to specify a shell command to use for sending Cron mail output instead of using sendmail(8) This command  must  accept  a  fully
          formatted  mail message (with headers) on standard input and send it as a mail message to the recipients specified in the mail headers.  Specifying the
          string off (i.e., crond -m off) will disable the sending of mail.

您可以创建一个 shell 脚本,将cat其内部输入写入文件。

我在 中没有找到类似的选项anacron,但也许/usr/bin/sendmail用自定义脚本替换会起作用。

答案4

如果您的操作系统sendmail默认使用类似于邮件系统,您也许可以使用自定义mailer.conf文件,该文件又调用自定义 shell 脚本,该脚本cron根据您的需要处理作业输出。

此设置需要sendmail类似的环境,但sendmail应该禁用守护进程本身,即不是跑步。

首先创建一个简单的mailer.conf文件,该文件将定义一个替代 shell 脚本作为sendmail“发送”邮件的组件,并创建 shell 脚本本身:

printf 'sendmail\t/etc/mail/mail-script.sh\n' > /etc/mail/mailer.conf

cat << 'EOF' > /etc/mail/mail-script.sh
#!/usr/bin/env bash

{
  date
  printf -- '--- BEGIN\n'
  cat
  printf -- '--- END\n'
} >> /var/log/cron-jobs.log
EOF

chmod 755 /etc/mail/mail-script.sh

这就完成了设置的“电子邮件”部分。现在让我们创建一个可以测试的示例 cron 作业:

cat << 'EOF' > /root/testjob.sh 
#!/usr/bin/env bash

printf 'This is a test cron job run at %s\n' "$(date)"
EOF

chmod 755 /root/testjob.sh

最后,我们将创建一个每分钟/etc/crontab运行一次的条目:/root/testjob.sh

cat << EOF >> /etc/crontab
MAILTO="foobar"
*   *   *   *   *   root    /root/testjob.sh
EOF

MAILTO条目必须存在(否则不会生成电子邮件),但可以是任意的。如果您愿意,您可以MAILTO为不同的目的定义某些名称,并cron根据作业引用的MAILTO标签以不同的方式处理作业输出cron

完成所有这些后,我们发现以下输出累积在/var/log/cron-jobs.log

# tail -f /var/log/cron-jobs.log
Tue Oct 12 14:11:00 PDT 2021
--- BEGIN
From: Cron Daemon <[email protected]>
To: foobar
Subject: Cron <root@test> /root/testjob.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <MAILTO=foobar>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

This is a test cron job run at Tue Oct 12 14:11:00 PDT 2021
--- END
Tue Oct 12 14:12:00 PDT 2021
--- BEGIN
From: Cron Daemon <[email protected]>
To: foobar
Subject: Cron <root@test> /root/testjob.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <MAILTO=foobar>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

This is a test cron job run at Tue Oct 12 14:12:00 PDT 2021
--- END
Tue Oct 12 14:13:00 PDT 2021
--- BEGIN
From: Cron Daemon <[email protected]>
To: foobar
Subject: Cron <root@test> /root/testjob.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <MAILTO=foobar>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

This is a test cron job run at Tue Oct 12 14:13:00 PDT 2021
--- END
Tue Oct 12 14:14:00 PDT 2021
--- BEGIN
From: Cron Daemon <[email protected]>
To: foobar
Subject: Cron <root@test> /root/testjob.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <MAILTO=foobar>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

This is a test cron job run at Tue Oct 12 14:14:00 PDT 2021
--- END
Tue Oct 12 14:15:00 PDT 2021
--- BEGIN
From: Cron Daemon <[email protected]>
To: foobar
Subject: Cron <root@test> /root/testjob.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <MAILTO=foobar>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

This is a test cron job run at Tue Oct 12 14:15:00 PDT 2021
--- END

相关内容