Отправлять по электронной почте весь вывод stdout+stderr cron только на stderr.

Вопрос или проблема

Я хочу, чтобы 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"

Применение

  1. Подготовка: Во-первых, нужно создать скрипт cron-wrapper.sh, который будет использован как обертка для заданий cron. Он принимает команду и аргументы, исполняет их, а затем обрабатывает выводы.

  2. Настройка cron: Пример настройки cron для использования созданного скрипта будет выглядеть так:

    30 * * * * root sh /путь/к/cron-wrapper.sh sh /путь/к/vашему-скрипту.sh >/dev/null

    Здесь cron-wrapper.sh обрабатывает стандартный и ошибочный вывод во временные файлы, объединяет их и проверяет наличие ошибок.

  3. Использование: Этот скрипт проверяет наличие данных в stderr и только тогда пересылает весь объединенный вывод (stdout и stderr) в stderr cronie, что инициирует отправку почты.

Альтернативы

Существуют и другие решения, которые можно рассмотреть, например, cronic. Этот скрипт был специально разработан для таких задач: отправка почты только при ошибках. Он определяет ошибку как любой вывод в stderr или ненулевой код возврата команды. Подключение скрипта cronic аналогично предыдущим примерам, и может значительно упростить конфигурацию.

Пример использования cronic:

# выполнение задачи в 23:42 каждый день
42 23 * * * cronic /root/.local/bin/vаш-сценарий.sh

Заключение

Настройка cronie с отправкой почты только при возникновении ошибок, с включением stdout для контекста, требует грамотного использования возможностей bash, файловых операций и взаимодействия с системными утилитами. Представленный подход позволяет добиться нужного результата, обеспечивая точную информацию для последующей диагностики и оптимизации процессов. Бережное отношение к ресурсам (таким как временные файлы и системные процессы) и полная проверка вывода поможет избежать потенциальных проблем в будущем.

Оцените материал
Добавить комментарий

Капча загружается...