编辑数据库时来自 MySQL 的邮件警报

sus*_*ush 8 mysql

当 root 或其他人编辑或更新特定数据库时,如何从 MySQL 获取邮件?它应该触发发送邮件并记录编辑。

我试过触发器,但它不起作用。

服务器规格:

  • Ubuntu 10.04 64 位
  • MySQL 服务器 5.1.41

我试过的脚本

  #!/bin/sh

  tail -f /var/log/mysql/mysql.log | egrep 'INSERT|UPDATE|DELETE|root'
      | mail -s 'backend update' sushanth@example.com
Run Code Online (Sandbox Code Playgroud)

但它不工作

Rol*_*DBA 3

MySQL 没有任何内置的特定 SMTP 设置、机制或驱动程序。

但是,您可以通过两项基本操作来进行所需的监控。

选项 1:您可以监控二进制日志

如果启用了二进制日志,您可以编写一个shell脚本来调用mysql并执行SHOW MASTER STATUS;如果文件名或文件大小发生变化,则某些内容发生变化。一旦检测到,您可以发送一封电子邮件表示发生了变化!

尝试这样的事情:

FIRST_READ=1
while [ 1 -eq 1 ]
do
    mysql -h... -u... -p... --skip-column-names -A -e"SHOW MASTER STATUS" > /tmp/ms.txt
    currfile=`cat /tmp/ms.txt | awk '{print $1}'`
    currsize=`cat /tmp/ms.txt | awk '{print $2}'`
    if [ ${FIRST_READ} -eq 0 ]
    then
        SOMETHING_CHANGED=2
        if [ "${prevfile}" == "${currfile}" ] ; then (( SOMETHING_CHANGED-- )) ; fi
        if [ "${prevsize}" == "${currsize}" ] ; then (( SOMETHING_CHANGED-- )) ; fi
        if [ ${SOMETHING_CHANGED} -gt 0 ]
        then
            echo "Something Changed" | mail -s "Something Changed Subject" abc@xyz.com
        fi
    fi
    FIRST_READ=0
    prevfile=${currfile}
    prevsize=${currsize}
    sleep 10
done
Run Code Online (Sandbox Code Playgroud)

选项 2:您可以监控 information_schema.tables

您可以循环遍历每个表并检查 information_schema.tables 中的 UPDATE_TIME 列

首先收集所有以数据库开头的表名。然后,循环遍历所有表名并检查 information_schema.tables 中的该条目。

尝试以下操作(过去 10 分钟内发生更改的任何表):

mysql -h... -u... -p... --skip-column-names -A -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql') AND engine IS NOT NULL" > /tmp/TableNamesToPoll.txt

while [ 1 -eq 1 ]
do
    for DBTB in `cat /tmp/TableNamesToPoll.txt`
    do
        DB=`echo ${DBTB} | sed 's/\./ /g' | awk '{print $1}'`
        TB=`echo ${DBTB} | sed 's/\./ /g' | awk '{print $2}'`
        NEWUPDATE=`mysql -h... -u... -p... --skip-column-names -A -e"SELECT IFNULL(update_time,NOW() - INTERVAL 100 YEAR) > (NOW() - INTERVAL 10 MINUTE) UpdatedRecently FROM information_schema.tables WHERE table_schema='${DB}' AND table_name='${TB}'"`
        if [ ${NEWUPDATE} -eq 1 ]
        then
            echo "Something Changed in ${DBTB}" | mail -s "Something Changed Subject" abc@xyz.com
        fi
    done
    sleep 5
done
Run Code Online (Sandbox Code Playgroud)

这些只是检测变化的框架脚本。对于选项 1,您可以针对当前二进制日志执行 mysqlbinlog,并查看在您需要的任何时间范围内执行的 SQL。对于选项 2,您可以更改 SQL 以检索给定表的上次更新的日期时间戳。

更新 2011-06-29 06:30 美国东部时间

选项 3:您可以监控一般日志

有趣的是,您可以激活通用日志。更有趣的是,您可以将其激活为 MySQL 表。通用日志作为表的模板已作为general_log.CSV 存在于/var/lib/mysql/mysql 中。步骤如下:

步骤01)将这些添加到/etc/my.cnf

[mysqld]
log-output=TABLE
log
Run Code Online (Sandbox Code Playgroud)

步骤02)service mysql restart(general_log是重启后的CSV表)

步骤03)运行这些命令将general_Log从CSV转换为MyISAM

SET GLOBAL general_log = 'OFF';
ALTER TABLE mysql.general_log ENGINE = MyISAM;
ALTER TABLE mysql.general_log ADD INDEX (event_time);
Run Code Online (Sandbox Code Playgroud)

步骤04)将general_log文件移动到一个可以容纳快速增长的日志表的巨大磁盘卷

示例:如果您有以下磁盘布局

[root@iml-db10 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg1-root  117G  3.2G  108G   3% /
/dev/mapper/vg2-data01
                      1.7T  688G  877G  44% /data
/dev/sdc1             3.6T   36G  3.4T   2% /backup
/dev/sda1              99M   18M   77M  19% /boot
tmpfs                  95G     0   95G   0% /dev/shm
none                   16G   51M   16G   1% /var/tmpfs
Run Code Online (Sandbox Code Playgroud)

执行以下步骤移动通用日志表:

mkdir /backup/general_log
mv /var/lib/mysql/mysql/general_log.MY* /backup/general_log/.
chown -R mysql:mysql /backup/general_log
ln -s /backup/general_log/general_log.MYD /var/lib/mysql/mysql/general_log.MYD
ln -s /backup/general_log/general_log.MYI /var/lib/mysql/mysql/general_log.MYI
Run Code Online (Sandbox Code Playgroud)

何时确保符号链接存在

[root@db1]# ls -l /var/lib/mysql/mysql/general*
-rw-rw---- 1 mysql mysql 8776 Jun 25 15:53 /var/lib/mysql/mysql/general_log.frm
lrwxrwxrwx 1 root  root    35 Jun 25 18:33 /var/lib/mysql/mysql/general_log.MYD -> /backup/general_log/general_log.MYD
lrwxrwxrwx 1 root  root    35 Jun 25 18:32 /var/lib/mysql/mysql/general_log.MYI -> /backup/general_log/general_log.MYI
Run Code Online (Sandbox Code Playgroud)

步骤 05) 运行此 SQL 命令

SET GLOBAL general_log = 'ON';
Run Code Online (Sandbox Code Playgroud)

就是这样。您应该将 General_log 作为 MyISAM 表

mysql> show create table mysql.general_log\G
*************************** 1. row ***************************
       Table: general_log
Create Table: CREATE TABLE `general_log` (
  `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_host` mediumtext NOT NULL,
  `thread_id` int(11) NOT NULL,
  `server_id` int(10) unsigned NOT NULL,
  `command_type` varchar(64) NOT NULL,
  `argument` mediumtext NOT NULL,
  KEY `event_time` (`event_time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='General log' DATA DIRECTORY='/backup/general_log/' INDEX DIRECTORY='/backup/general_log/'
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

您需要做的就是通过运行此查询的 crontab 每 15 分钟轮询一次 General_log 表

SELECT COUNT(1) UpdateCount FROM mysql.general_log
WHERE LOCATE('UPDATE',argument) > 0
AND event_time >= (NOW() - INTERVAL 15 MINUTE);

SELECT COUNT(1) DeleteCount FROM mysql.general_log
WHERE LOCATE('DELETE',argument) > 0
AND event_time >= (NOW() - INTERVAL 15 MINUTE);
Run Code Online (Sandbox Code Playgroud)

警告:条目会很快堆积起来。删除保留最近 3 天的所有事件。每晚午夜在 crontab 中运行此命令

SET @old_log_state = @@global.general_log;
SET GLOBAL general_log = 'OFF';
DELETE FROM mysql.general_log WHERE event_time < NOW() - INTERVAL 3 DAY;
SET GLOBAL slow_query_log = @old_log_state;
Run Code Online (Sandbox Code Playgroud)

尝试一下!