Назад | Перейти на главную страницу

Как использовать TAIL & EGREP для указанного временного диапазона в сценарии BASH

Тема в основном говорит сама за себя. Я отвечаю за несколько веб-серверов под управлением Ubuntu 12.04 с Apache2, и я хотел бы настроить APC.

Теперь я понимаю, что APC может столкнуться с ошибками сегментации при работе с PHP-кодом, который имеет ошибки или причуды. Так что очистка желательна, но не совсем практична с точки зрения персонала.

Итак, я приготовил скрипт для мониторинга основного Apache2 error.log & посчитайте, сколько ошибок сегментации он видит. Я запускаю его как задание cron, которое выполняется каждые 2 минуты. Если он попадает в указанное количество ошибок сегментации, он должен автоматически перезапустить Apache2, чтобы очистить APC и снова обеспечить бесперебойную работу служб. Основная идея этого скрипта взято из комментария на этой странице но я действительно сильно опирался на эту концепцию, чтобы сделать ее более производственной, готовой к моим потребностям и вкусам.

Я в целом доволен этим сценарием, но считаю, что одним из основных улучшений является основная логика этого фрагмента:

if [[ `tail -n ${TAIL_NUMLINES} "${APACHE_ERROR_LOG}" | egrep -c "${TEXT_TO_WATCH}"` -ge ${FAIL_COUNT} ]]; then

Это в основном основная логика, которая отслеживает файл журнала на указанное количество строк, и если он видит указанное количество записей журнала с exit signal Segmentation fault в них, тогда он решает, что пора что-то делать. В этом случае зарегистрируйте инцидент, напишите кому-нибудь об инциденте и перезапустите Apache.

Я хотел бы, чтобы эта логика учитывалась во времени, потому что ошибок может быть немного и они могут быть очень редкими. Так что есть случаи, когда мои FAIL_COUNT просто соответствует TAIL_NUMLINES несмотря на перезапуск, потому что в главном журнале ошибок нет новых записей, потому что новых ошибок не произошло. Что закончится ситуацией, когда сервер в основном перезагружается каждый раз, когда срабатывает задание cron. Что ужасно.

Итак, мое временное решение на данный момент - установить FAIL_COUNT & TAIL_NUMLINES до достаточно низкого числа, чтобы соответствовать стандартному количеству записей, которые создаются при перезагрузке Apache2. Но мне это все равно не нравится.

Так что - если что-нибудь - можно сделать, чтобы добавить временные рамки к моему tail/egrep логика. Кроме того, я бы хотел избежать создания отметки времени или подсказки позиции строки журнала, сохраняемой в файл, если это возможно. Я хочу, чтобы этот сценарий был автономным, кроме зависимости от задания cron.

Полный сценарий, как есть у меня сейчас.

#!/bin/bash

LOCK_NAME="APACHE_LOGWATCHER"
LOCK_DIR=/tmp/${LOCK_NAME}.lock
PID_FILE=${LOCK_DIR}/${LOCK_NAME}.pid

DATE=`date +%Y%m%d`
TIME=`date +%H%M`
# SUFFIX="-"${DATE}"-"${TIME};
SUFFIX="-"${DATE};

APACHE_ERROR_LOG="/var/log/apache2/error.log"
APACHE_RESTART="/etc/init.d/apache2 restart"
TEXT_TO_WATCH="exit signal Segmentation fault"

HOSTNAME=$(hostname)
MAIL_ADDRESS="myname@domain.name.here.com"
MAIL_SUBJECT=${HOSTNAME}": Apache Segfault Notification"

SCRIPT_NAME=$(basename "$0")
SCRIPT_BASE_NAME=${SCRIPT_NAME%.*}

LOG_DIR="/opt/segfault_logs/"
LOG_FILENAME=${SCRIPT_BASE_NAME}${SUFFIX}".log"
LOG_FULLPATH=${LOG_DIR}${LOG_FILENAME}

TAIL_NUMLINES=5
FAIL_COUNT=4

# If the Apache log file doesn't exist, then exit.
if [ ! -f ${APACHE_ERROR_LOG} ]; then
    exit
fi

# Main process.
if mkdir ${LOCK_DIR} 2>/dev/null; then
    # If the ${LOCK_DIR} doesn't exist, then start working & store the ${PID_FILE}
    echo $$ > ${PID_FILE}

    STARTUP_MESSAGE="`date` Log watcher starting."
    if [ -d ${LOG_DIR} ]; then
        echo ${STARTUP_MESSAGE} >> ${LOG_FULLPATH}
    fi

    # Tail--but do not follow--a chunk of the LOG_FULLPATH if the number of instances is
    # greater than or equal to the FAIL_COUNT, act
    if [[ `tail -n ${TAIL_NUMLINES} "${APACHE_ERROR_LOG}" | egrep -c "${TEXT_TO_WATCH}"` -ge ${FAIL_COUNT} ]]; then

        # Create the log message.
        LOG_MESSAGE="`date` Segfault detected on "$HOSTNAME

        # Log the error to the file.
        if [ -d ${LOG_DIR} ]; then
            echo ${LOG_MESSAGE} >> ${LOG_FULLPATH}
        fi

        # Send e-mail notification.
        echo ${LOG_MESSAGE}$'\n\r'${FAIL_COUNT} | mail -s "${MAIL_SUBJECT}" ${MAIL_ADDRESS}

        # Restart Apache
        ${APACHE_RESTART}
    fi

    rm -rf ${LOCK_DIR}
    exit
else
    if [ -f ${PID_FILE} ] && kill -0 $(cat ${PID_FILE}) 2>/dev/null; then
        # Confirm that the process file exists & a process
        # with that PID is truly running.
        # echo "Running [PID "$(cat ${PID_FILE})"]" >&2
        exit
    else
        # If the process is not running, yet there is a PID file--like in the case
        # of a crash or sudden reboot--then get rid of the ${LOCK_DIR}
        rm -rf ${LOCK_DIR}
        exit
    fi
fi

РЕДАКТИРОВАТЬ: Вот пример вывода файла журнала Apache2, который отслеживает вышеуказанный сценарий.

[Sat Mar 02 14:32:26 2013] [notice] child pid 14696 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:27 2013] [notice] child pid 13914 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:27 2013] [notice] child pid 15735 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:28 2013] [notice] child pid 14865 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:28 2013] [notice] child pid 15545 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:30 2013] [notice] child pid 13821 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:31 2013] [notice] child pid 15683 exit signal Segmentation fault (11)
[Sat Mar 02 14:32:47 2013] [notice] child pid 15684 exit signal Segmentation fault (11)
[Sat Mar 02 14:33:54 2013] [notice] child pid 15482 exit signal Segmentation fault (11)
[Sat Mar 02 14:34:04 2013] [notice] caught SIGTERM, shutting down
[Sat Mar 02 14:34:06 2013] [notice] ModSecurity for Apache/2.6.3 (http://www.modsecurity.org/) configured.
[Sat Mar 02 14:34:06 2013] [notice] ModSecurity: APR compiled version="1.4.6"; loaded version="1.4.6"
[Sat Mar 02 14:34:06 2013] [notice] ModSecurity: PCRE compiled version="8.12"; loaded version="8.12 2011-01-15"
[Sat Mar 02 14:34:06 2013] [notice] ModSecurity: LUA compiled version="Lua 5.1"
[Sat Mar 02 14:34:06 2013] [notice] ModSecurity: LIBXML compiled version="2.7.8"
[Sat Mar 02 14:34:07 2013] [notice] Apache/2.2.22 (Ubuntu) mod_ssl/2.2.22 OpenSSL/1.0.1 configured -- resuming normal operations

Это похоже на работу для logtail. Цель logtail - помнить, где вы пришли при чтении файла в последний раз, чтобы в следующий раз начать заново с этого места.

Используйте это так:

logtail -o /tmp/apache.offset ${APACHE_ERROR_LOG} | egrep -c "${TEXT_TO_WATCH}"

Это демонстрирует мою идею

should_restart.sh

last_restart_line_number=$( grep restart sample_log_file.txt -n | tail -1 | cut -f1 -d: )
segfaults_since_restart=$( tail -n +$last_restart_line_number sample_log_file.txt | grep segfault -c )

if [ $segfaults_since_restart -gt 5 ]; then
    echo "Yes, restart apache"
else
    echo "No, don't restart apache"
fi

sample_log_file.txt

segfault
segfault
segfault
restart
segfault
segfault
segfault
restart
segfault
segfault
segfault
restart
segfault
segfault
segfault
segfault