代码改变世界

MySQL日志维护与监控脚本

2023-06-07 08:54  潇湘隐者  阅读(159)  评论(0编辑  收藏  举报

MySQL数据库的管理维护过程中,MySQL错误日志(MySQL Error Log)与MySQL慢查询日志(MySQL Slow Log),一般不会自动清理,也不会轮转/切换,这个跟MySQL的二进制日志(binlog)有所不同,所以如果数据库管理员对其不维护的话,这些日志随着时间的推移以及一些特殊原因,一方面日志文件可能会变得非常大(磁盘空间消耗),另外一方面影响一些操作的性能。例如,MySQL慢查询日志如果一直写入一个文件,这个文件会变得非常大, 当你去分析/解析MySQL慢查询日志的时候会影响性能。

这里分享一个之前写的shell脚本,用来轮转/切换MySQL错误日志和MySQL慢查询日志,以及监控MySQL错误日志,具体功能如下:

  1. 错误日志的轮换/切换
  2. 慢查询日志的轮换/切换
  3. 删除N天前的错误日志
  4. 删除N天前的慢查询日志
  5. 错误日志的监控告警
#!/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。使用前,请在具体环境下测试验证后使用。