主题基本上说明了一切。我负责运行运行 Apache2 的 Ubuntu 12.04 的几个 Web 服务器,我想设置 APC。
现在我明白了,当对有错误或怪异的 PHP 代码进行操作时,APC 可能会遇到分段错误问题。因此,清理是可取的,但从人力角度来看并不实用。
因此,我编写了一个脚本来监控主 Apache2error.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="[email protected]"
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
答案1
这听起来像是一份工作logtail
。的目的logtail
是记住您上次读取文件时到达的位置,以便下次可以从该点重新开始。
使用方式如下:
logtail -o /tmp/apache.offset ${APACHE_ERROR_LOG} | egrep -c "${TEXT_TO_WATCH}"
答案2
这证明了我的想法
重启
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
样本日志文件.txt
segfault
segfault
segfault
restart
segfault
segfault
segfault
restart
segfault
segfault
segfault
restart
segfault
segfault
segfault
segfault