Вопрос или проблема
Я хочу, чтобы cron отправлял email только при выводе stderr, но при этом включал весь вывод stdout и stderr.
Это отличается от обычного вопроса об отправке email только при stderr (например, при перенаправлении stdout в /dev/null). В этом случае cron отправляет только stderr, но я хотел бы видеть все для полного понимания.
Я использую Rocky 9 с cronie в качестве демона cron.
Если команда завершается с ненулевым статусом, вы можете попробовать:
bash -c 'command 2>&1 > /tmp/err || mail -A /tmp/err [email protected]'
где:
bash -c ''
позволяет использовать несколько команд в cron-задании; можно использовать и скрипт.command
– путь к выполняемой команде2>&1
перенаправляет stderr в stdout> /tmp/err
сохраняет stdout (теперь оба потока) в файл (путь/tmp/err
)||
запускает вторую команду только если первая завершилась с ненулевым статусомmail -A /tmp/err
отправляет файл в качестве вложенияmail [email protected] < /tmp/err
отправит его в теле сообщения
Вы можете улучшить это, используя, например, mktemp
для использования разных путей для каждого лога в случае одновременного запуска & sleep
, если в конце файла что-то отсутствует.
Я решил написать скрипт, который мог бы приблизительно решить вопрос об отправке email только при выводе stderr.
Ключ в том, чтобы сохранять stdout/stderr в файлы до тех пор, пока не будет обнаружен stderr, а затем выводить объединенный файл.
Можно сказать, что объединенный файл грубо сохраняет порядок stdout/stderr, если tail может достаточно быстро проходить по своим файлам. Если нет буферизации, и команда занимает более одной-двух секунд, и есть задержка между выводами stdout/stderr, то этот подход может приблизительно сохранять упорядоченный вывод stdout/stderr.
Я назвал этот скрипт cron-wrapper.sh. Его цель – принимать команду и аргументы и выполнять их.
Он должен вызываться из crontab следующим образом:
30 * * * * root sh cron-wrapper.sh sh cron-job.sh >/dev/null
Обратите внимание, что при выводе всего в stderr “все” выводится в stderr, а не в stdout, чтобы выполнить мое требование, чтобы cron отправлял email со всем выводом stderr.
Скрипт:
#!/bin/bash
# Ввод
cmd=$1
shift
# Запуск данной команды в фоновом режиме, чтобы мы могли немедленно следить за файлами вывода
stdoutFile=`mktemp`
stderrFile=`mktemp`
$cmd "${@}" >"$stdoutFile" 2>"$stderrFile" &
cmdPid=$!
# Отслеживание файлов stdout и stderr
teeFile=`mktemp`
tail -F -s 0.01 --pid=$cmdPid --quiet --silent "$stdoutFile" "$stderrFile" | tee "$teeFile"
# Вывод всего, если был обнаружен вывод stderr
if [ -s "$stderrFile" ]; then
cat "$teeFile" >&2
fi
# Очистка
rm -f "$stdoutFile" "$stderrFile" "$teeFile"
Используйте cronic
, который делает именно это. С веб-страницы:
Cronic — это небольшой скрипт-заглушка на оболочке для обертки заданий cron, чтобы cron отправлял email только при возникновении ошибки. Cronic определяет ошибку как любой вывод ошибок, не связанный с трассировкой, или ненулевой код результата.
Пример:
# Выполнить действие в 23:42 каждый день.
42 23 * * * cronic /root/.local/bin/doit.sh
Ответ или решение
Когда речь идет о настройке cron для отправки электронной почты только при возникновении ошибок, с включением как стандартного вывода (stdout), так и стандартного вывода ошибок (stderr), задача может показаться более сложной, чем кажется. В данной ситуации пользователь использует Rocky 9 с cronie в качестве демона cron, что требует специфического подхода к решению проблемы.
Теория
Cron — это утилита Unix, позволяющая автоматизировать выполнение задач в заданное время. Обычно, cron отправляет почту с выводом задачи каждый раз, когда она запускается, включая как stdout, так и stderr. Однако, если интерес представляет только stderr, при этом необходим весь контекст выполнения, задача усложняется: нужно обеспечить сохранение и последующую отправку stdout только в случае ошибки.
Пример
Этот подход включает создание временных файлов для хранения stdout и stderr. Используя возможности bash, можно организовать выполнение команды в фоновом режиме, а затем через tee
и tail
прослеживать оба вывода. В случае обнаружения вывода в stderr, объединенные данные можно отправить на stderr cron для отправки по почте.
Пример кода:
#!/bin/bash
# Входная команда
cmd=$1
shift
# Запуск команды в фоновом режиме
stdoutFile=$(mktemp)
stderrFile=$(mktemp)
$cmd "${@}" >"$stdoutFile" 2>"$stderrFile" &
cmdPid=$!
# Просмотр файлов stdout и stderr
teeFile=$(mktemp)
tail -F -s 0.01 --pid=$cmdPid --quiet --silent "$stdoutFile" "$stderrFile" | tee "$teeFile"
# Если есть вывод в stderr, отправка всего на stderr cron
if [ -s "$stderrFile" ]; then
cat "$teeFile" >&2
fi
# Очистка
rm -f "$stdoutFile" "$stderrFile" "$teeFile"
Применение
-
Подготовка: Во-первых, нужно создать скрипт
cron-wrapper.sh
, который будет использован как обертка для заданий cron. Он принимает команду и аргументы, исполняет их, а затем обрабатывает выводы. -
Настройка cron: Пример настройки cron для использования созданного скрипта будет выглядеть так:
30 * * * * root sh /путь/к/cron-wrapper.sh sh /путь/к/vашему-скрипту.sh >/dev/null
Здесь
cron-wrapper.sh
обрабатывает стандартный и ошибочный вывод во временные файлы, объединяет их и проверяет наличие ошибок. -
Использование: Этот скрипт проверяет наличие данных в stderr и только тогда пересылает весь объединенный вывод (stdout и stderr) в stderr cronie, что инициирует отправку почты.
Альтернативы
Существуют и другие решения, которые можно рассмотреть, например, cronic
. Этот скрипт был специально разработан для таких задач: отправка почты только при ошибках. Он определяет ошибку как любой вывод в stderr или ненулевой код возврата команды. Подключение скрипта cronic
аналогично предыдущим примерам, и может значительно упростить конфигурацию.
Пример использования cronic
:
# выполнение задачи в 23:42 каждый день
42 23 * * * cronic /root/.local/bin/vаш-сценарий.sh
Заключение
Настройка cronie с отправкой почты только при возникновении ошибок, с включением stdout для контекста, требует грамотного использования возможностей bash, файловых операций и взаимодействия с системными утилитами. Представленный подход позволяет добиться нужного результата, обеспечивая точную информацию для последующей диагностики и оптимизации процессов. Бережное отношение к ресурсам (таким как временные файлы и системные процессы) и полная проверка вывода поможет избежать потенциальных проблем в будущем.