MySQL日志维护与监控脚本
潇湘隐者
MySQL数据库的管理维护过程中,MySQL错误日志(MySQL Error Log)与MySQL慢查询日志(MySQL Slow Log),一般不会自动清理,也不会轮转/切换,这个跟MySQL的二进制日志(binlog)有所不同,所以如果数据库管理员对其不维护的话,这些日志随着时间的推移以及一些特殊原因,一方面日志文件可能会变得非常大(磁盘空间消耗),另外一方面影响一些操作的性能。例如,MySQL慢查询日志如果一直写入一个文件,这个文件会变得非常大, 当你去分析/解析MySQL慢查询日志的时候会影响性能。
这里分享一个之前写的shell脚本,用来轮转/切换MySQL错误日志和MySQL慢查询日志,以及监控MySQL错误日志,具体功能如下:
- 错误日志的轮换/切换
- 慢查询日志的轮换/切换
- 删除N天前的错误日志
- 删除N天前的慢查询日志
- 错误日志的监控告警
#!/bin/bash
source /etc/profile
#########################################################################################
# #
# This script is used for rotation mysql error log & slow log and monitor the error log #
# 1:错误日志的轮换/切换 #
# 2:如果开启了慢查询日志,慢查询日志的轮换/切换 #
# 3:删除N天前的错误日志 #
# 4:删除N天前的慢查询日志 #
# 5: 错误日志的监控告警 #
# #
# #######################################################################################
# #
# ScriptName : mysql_log_manage_monitor.sh #
# Author : 潇湘隐者 #
# CerateDate : 2020-09-03 #
# Blogs : www.cnblogs.com/kerrycode #
# Email : kerry2008code@qq.com #
#***************************************************************************************#
# 参数配置 #
#---------------------------------------------------------------------------------------#
# 注意,如果维护的MySQL数据库都规范化安装、配置的化,下面很多参数都不需要修改 #
#---------------------------------------------------------------------------------------#
# MYSQL_ERRORLOG_PATH MySQL错误日志的路径 #
# MYSQL_ERRORLOG_FILE MySQL错误日志文件名 #
# ALERT_LOG_PATH 告警日志路径 #
# KEEYP_DAYS MySQL错误日志/慢查询日志保留天数 #
# ERROR_FILE_TYPE 错误日志文件格式 #
# SLOW_FILE_TYPE 慢查询日志文件格式 #
# MAIL_FROM 发件人 #
# MAIL_TO 收件人 #
#***************************************************************************************#
# Version Modified Date Description #
#***************************************************************************************#
# V.1.0 2020-09-03 创建此脚本 #
# V.1.1 2020-09-23 增加轮转慢查询日志的功能 #
# V.2.0 2023-06-01 重构此脚本,相关功能模块化 #
#########################################################################################
SERVER_IP=""
#LOG_ROTATION_DATE=$(date +%Y_%m_%d)
#轮转日期改为前一天
LOG_ROTATION_DATE=$(date -d yesterday +%Y_%m_%d)
MAIL_FROM="xxxx@xxx.com.cn"
MAIL_TO="xxxx@xxx.com.cn"
#default value is /data/mysql/logs
MYSQL_ERRORLOG_PATH=/data/mysql/logs
#default value is mysql_error.log
MYSQL_ERRORLOG_FILE=mysql_error.log
#default value is /data/mysql/slow_logs
SLOW_LOG_PATH=/data/mysql/slow_logs
#default value is mysql_slow.log
SLOW_LOG_FILE=mysql_slow.log
#default value is /mysql_backup/logs
LOG_FILE_PATH=/mysql_backup/logs
#default value is /mysql_backup/logs/mysql_log_manage_monitor.log
LOG_FILE=${LOG_FILE_PATH}/mysql_log_manage_monitor.log
#default value is /mysql_backup/logs/alert_log
ALERT_LOG_PATH=/mysql_backup/logs/alert_log
NEW_SLOW_LOG_FILE=''
HOUR=`date '+%H'`
KEEYP_DAYS=30
ERROR_FILE_TYPE="mysql_error*.log"
SLOW_FILE_TYPE="mysql_slow*.log"
MAIL_SUBJECT=""
#LOG_DATE用`date`替换,以便更精准的记录时间
##LOG_DATE=$(date +%Y_%m_%d_%H_%M_%S)
function check_enviroment(){
if [ ! -d $MYSQL_ERRORLOG_PATH ]; then
echo "`date`>usage: $MYSQL_ERRORLOG_PATH didn't exists" >> $LOG_FILE
exit -1
fi
if [ ! -f "$MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE" ] ; then
echo "`date`>usage: $MYSQL_ERRORLOG_FILE didn't exists" >> $LOG_FILE
exit -1
fi
if [ ! -d $SLOW_LOG_PATH ]; then
echo "`date`>usage: $SLOW_LOG_PATH didn't exists" >> $LOG_FILE
exit -1
fi
if [ ! -f "$SLOW_LOG_PATH/$SLOW_LOG_FILE" ] ; then
echo "`date`>usage: $SLOW_LOG_FILE didn't exists" >> $LOG_FILE
exit -1
fi
if [ ! -d $LOG_FILE_PATH ]; then
echo "`date`>usage: $LOG_FILE_PATH didn't exists" >> $LOG_FILE
exit -1
fi
if [ ! -x /bin/mailx ];then
echo "`date`>usage:mailx did not exists!" >> $LOG_FILE
exit -1
fi
#ALERT_LOG_PATH目录不存在则创建目录
if [ ! -d $ALERT_LOG_PATH ] ; then
echo "`date`>the path $ALERT_LOG_PATH didn't exists" >> $LOG_FILE
mkdir -p $ALERT_LOG_PATH
fi
}
function rotation_mysql_log(){
#0点开始轮换/切换前一天的错误日志
if [ $HOUR -eq '00' ]; then
#轮换/切换错误日志
#注意:赋值的=号前后不要有空格
NEW_ERRORLOG_NAME=$(basename ${MYSQL_ERRORLOG_PATH}/${MYSQL_ERRORLOG_FILE} .log)
if [ -f "$MYSQL_ERRORLOG_PATH/${NEW_ERRORLOG_NAME}_${LOG_ROTATION_DATE}.log" ] ; then
echo "`date`>MySQL的错误日志已经切换(rotation)" >> $LOG_FILE
else
cat $MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE > $MYSQL_ERRORLOG_PATH/${NEW_ERRORLOG_NAME}_${LOG_ROTATION_DATE}.log
#最后运行的命令的结束代码(返回值)
if [ $? -eq 0 ]; then
cat /dev/null > $MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE
else
echo "`date`>failed to rotate the mysql error file" >> $LOG_FILE
fi
fi
#轮换/切换慢查询日志
NEW_SLOW_LOG_FILE=$(basename ${SLOW_LOG_PATH}/${SLOW_LOG_FILE} .log)
if [ -f "${SLOW_LOG_PATH}/${NEW_SLOW_LOG_FILE}_${LOG_ROTATION_DATE}.log" ] ; then
echo "`date`>MySQL慢查询日志已经切换(rotation)" >> $LOG_FILE
else
cat $SLOW_LOG_PATH/$SLOW_LOG_FILE > $SLOW_LOG_PATH/${NEW_SLOW_LOG_FILE}_${LOG_ROTATION_DATE}.log
#最后运行的命令的结束代码(返回值)
if [ $? -eq 0 ]; then
cat /dev/null > $SLOW_LOG_PATH/$SLOW_LOG_FILE
else
echo "`date`>failed to rotate the mysql slow file" >> $LOG_FILE
fi
fi
fi
}
function mysql_error_log_monitor(){
if [ -s "${ALERT_LOG_PATH}/mysql_alert.log" ] ; then
cat $ALERT_LOG_PATH/mysql_alert.log > $ALERT_LOG_PATH/mysql_alert_old.log
fi
if [ -s "${MYSQL_ERRORLOG_PATH}/${MYSQL_ERRORLOG_FILE}" ] ; then
egrep -i 'error|warning' $MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE | sort -u > $ALERT_LOG_PATH/mysql_alert.log
fi
# 第一次时,没有生成mysql_alert_old.log,则执行下面逻辑
if [ ! -f "$ALERT_LOG_PATH/mysql_alert_old.log" ] ; then
if [ -s "$ALERT_LOG_PATH/mysql_alert.log" ] ; then
MAIL_SUBJECT="Error messages & Warning messages in MySQL Alert Log File on the `hostname` ($SERVER_IP) at `date` "
mailx -s "${MAIL_SUBJECT}" -r ${MAIL_FROM} ${MAIL_TO} < $ALERT_LOG_PATH/mysql_alert.log
fi
else
#diff命令返回值为 0,说明两个文件相同,否则两个文件不相同
diff $ALERT_LOG_PATH/mysql_alert.log $ALERT_LOG_PATH/mysql_alert_old.log
# $?是上一执行命令的返回值
if [ $? == 0 ]; then
echo "$LOG_DATE>there is no new error logs and warning logs are generated" >> $LOG_FILE
else
if [ -s "$ALERT_LOG_PATH/mysql_alert.log" ] ; then
MAIL_SUBJECT="Error messages & Warning messages in MySQL Alert Log File on the `hostname` ($SERVER_IP) at `date` "
mailx -s "${MAIL_SUBJECT}" -r ${MAIL_FROM} ${MAIL_TO} < $ALERT_LOG_PATH/mysql_alert.log
fi
fi
fi
}
function delete_old_mysql_log(){
#删除指定天数前的错误日志文件
find $MYSQL_ERRORLOG_PATH -name ${ERROR_FILE_TYPE} -type f -mtime +$KEEYP_DAYS -delete
#删除指定天数前的慢查询日志文件
find $SLOW_LOG_PATH -name ${SLOW_FILE_TYPE} -type f -mtime +$KEEYP_DAYS -delete
}
function main()
{
echo "`date`>----------------- the mysql_log_manage_monitor.sh start -----------------" >> $LOG_FILE
#注意,下面命令可能有些Linux平台不支持,请测试验证。这里在RHEL 7.x/RHEL 8下测试均OK
SERVER_IP=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
check_enviroment;
rotation_mysql_log;
mysql_error_log_monitor;
delete_old_mysql_log;
echo "`date`>----------------- the mysql_log_manage_monitor.sh stoped -----------------" >> $LOG_FILE
return 0;
}
main;
另外,当MySQL错误日志中出现Warning信息或ERROR信息时,发送告警邮件(或者接入公司的告警平台,一般调用相关API,此处略过),如果对于出现的Warning告警信息,不想脚本发送邮件告警的话,调整一下脚本即可。
修改前:
if [ -s "${MYSQL_ERRORLOG_PATH}/${MYSQL_ERRORLOG_FILE}" ] ; then
egrep -i 'error|warning' $MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE | sort -u > $ALERT_LOG_PATH/mysql_alert.log
fi
修改后(取消过滤的关键字waning即可)
if [ -s "${MYSQL_ERRORLOG_PATH}/${MYSQL_ERRORLOG_FILE}" ] ; then
egrep -i 'error' $MYSQL_ERRORLOG_PATH/$MYSQL_ERRORLOG_FILE | sort -u > $ALERT_LOG_PATH/mysql_alert.log
fi
另外,这里不考虑MySQL通用查询日志,因为绝大部分环境下和绝大数场景下,都很少开启MySQL通用查询日志,所以这里不予考虑。
最后,上面脚本仅供参考,脚本在一些平台经过多次测试验证,但是不保证所有平台都OK。使用前,请在具体环境下测试验证后使用。
扫描上面二维码关注我