获取发布平台日志并去重通知
CREATE TABLE `日志表` ( `log_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `log_time` datetime NOT NULL COMMENT '日志时间', `ip` varchar(50) DEFAULT NULL COMMENT 'IP地址', `title` varchar(255) DEFAULT NULL COMMENT '日志标题', `content` varchar(255) DEFAULT NULL COMMENT '日志内容',
。。。。 PRIMARY KEY (`log_id`) ) ENGINE=InnoDB AUTO_INCREMENT=166581 DEFAULT CHARSET=utf8 COMMENT='CMS日志表';
分析1:所以如果单纯查日志表,显示的字段:user_id是没法看的,需要找另一张用户表来根据 user_id 找到账号名。 ---- sql查询要做表关联
分析2:大家可以留意下发布后台的“时间” ,也就是查数据库日志表时,根据 log_time 逆序排序显示
select * from {日志表} order by log_time desc;
获取最新后台日志信息也应该逆序去查会比较好,方便跟后台日志对应上,但是发到钉钉可能会有点不习惯,毕竟是逆序显示,所以假设定时任务5分钟扫描一次日志表,获取最新信息,前5分钟内做了多个动作,通知的话为了好区分,我加了个脚本检测时间,和实际用户操作时间(日志表查到的):
分析3:发过的信息不要重复发。
可以利用日志ID,因为是唯一标识,而且每增加一条日志记录,ID编号会自增1,所以重复信息我们可以根据这个 ID 去判断。当前检测时间如果发现有新增ID(对应变量:ID_New),跟之前的记录文件(对应变量 ID_Old)比较(用命令diff),找出不同 ID 号,去数据库查出日志记录即可(对应变量:Ct_New)。
--------------------------------------
最后,讲下注意点
注意点 1:
每天一个日期目录,因为每天都会有几个记录文件用于当天判断,也方便后续清理删除。我说下每个文件分别代表的意思
(1)logid_old(变量:ID_Old):当天内,前一次检测时间所记录的日志ID,用于判断是否曾经发过钉钉通知的
(2)logid_new_src(变量:ID_SNew):当天内,从当天0点到当前检测时间,查出来的所以日志ID
(3)logid_new(变量:ID_New):去掉(2)文件原始查询结果的关键字 log_id 行
(4)dif:如果有新增日志,logid_new 比 logid_old 多出来的日志ID。假设当时时间new文件的日志ID为:1、2、3,而old文件只有1、2,则dif 文件找到日志ID:3,但是有无用行,如下图第一行
(5)dif_num:找到日志ID在(4)中所在的行号,比如下图的日志ID:166580 是在 dif 文件的第2行,166579 在第 3 行
我这样处理是为了从dif_num 记录的行号找到 dif 里的日志ID,过滤出来就可以找到新增日志ID的具体内容
(6)content_src(变量:Ct_SNew):新增日志 ID 的具体内容,查出来有无用行(日志表的表字段)。需要过滤得到真正日志内容,也就是下面的(7)
(7)content_new(变量:Ct_New):新增日志 ID 的具体内容
注意点 2:shell 传参如果有空格会被截断,所以里面有空格过滤
大家留意下,下面的脚本有个针对变量:content2 进行空格删除,因为日志表字段content,实际上是记录该账号做了什么操作,假设 title 为“增加文章”,content记录文章id,及titie=文章标题
然而,我发现文章标题起名不规范,里面还有空格,导致钉钉通知被截断,右边书名号都没了,内容发了一半,比较坑爹,如下图:
为了能发,我把标题空格去掉,牺牲点美观(我发现换表符\t也解决不了,所以暂时先这样处理)
另外content这个字段有时候查出来为空,当字段title记录“登录成功”的时候
所以下面会有个判断,登录成功,content2=""
另外一些判断也是因为各种理由,为了通知美观点,可读性强点,就不累赘了。
注意点 3:传参到钉钉通知函数
那个参数传递顺序要注意下,我一开始是把token放到最后的,但会出问题,因为content2有可能为空,导致发信息的字段存在错乱问题,所以后来我改成放第一个参数去传递给钉钉函数。
SendMessageToDingdingljy ${token1} ${user} ${time} ${title} ${content2}
另外下面这个写法是我参考一个开发写的python程序,感觉挺聪明的~~~~拿来即用。
因为有多个钉钉群,有些是我测试看的,有些是发领导看的,屏蔽也方便,适用于需要发多个钉钉群的情况,可以写成这样,不同钉钉群的机器人这样传递就可以了
Dingding_Url=https://oapi.dingtalk.com/robot/send?access_token=$1
二、脚本及效果图
1、脚本代码:
#!/bin/bash Dir='/home/xxx/xxx-content' log_path=`date +"%Y%m"` d=`date +"%d"` ymd=`date +"%Y-%m-%d"` Ymd_Dir=${Dir}/${log_path}/${d} ## 每天一个年月日表 [ ! -d ${Ymd_Dir} ] && mkdir -p ${Ymd_Dir} ID_SNew=${Ymd_Dir}/logid_new_src ID_New=${Ymd_Dir}/logid_new ID_Old=${Ymd_Dir}/logid_old #日志ID原始文件,不存在则创建 [ ! -f ${ID_Old} ] && touch ${ID_Old} #日志内容文件 Ct_SNew=${Ymd_Dir}/content_src Ct_New=${Ymd_Dir}/content_new cd ${Ymd_Dir} ## 当天0点 begin_time=`date +"%Y-%m-%d 00:00:00"` ## 当前检测时间 end_time=`date +"%Y-%m-%d %H:%M:%S"` ## ljy的测试群 token1='钉钉token' ## 公司群 token2='钉钉token' # 发钉钉群 function SendMessageToDingdingljy(){ Dingding_Url=https://oapi.dingtalk.com/robot/send?access_token=$1 d_t=`date "+%F"_"%T"` #d_t=`date +"%T"` User=$2 Time=$3 Title=$4 Content=$5 #发送钉钉消息 curl -H "Content-Type: application/json" -X POST --data ' { "msgtype": "text", "text": { "content": "------ xxx网 ------ \r检测时间:'${d_t}' \r登录用户:'${User}' \r用户操作时间:'${Time}' \r标题:'${Title}' '${Content}' "}, "at": { "atMobiles": [ "我的手机号码" ], "isAtAll": false } }' ${Dingding_Url} > /dev/null 2>&1 } ## 1、查 日志id(唯一):今天0点~当前检测而时间 mysql -u{数据库登录用户} -p'{数据库登录密码}' -h{数据库登录地址} -e "use {数据库名}; select {日志ID} from {日志表} where {时间字段} >= '$begin_time' AND {时间字段} <= '$end_time' order by {时间字段} desc;" > ${ID_SNew} #去掉首行无用行,只要查出来的id cat ${ID_SNew} |grep -v "log_id" > ${ID_New} ## 2、检查是否有新增:log_id diff ${ID_New} ${ID_Old} status=`echo $?` >${Ct_SNew} ## 3、如果有新增:log_id,表示后台日志有新内容 if [ ${status} -ne 0 ] then ## ID_New 内容肯定要比 ID_Old内容多 diff ${ID_New} ${ID_Old} > dif # 找到log_id对应的文件行号,去掉第一行无用行 sed -n '/</=' dif > dif_num
# 根据行号,找到 log_id cat dif_num | while read line do #根据行号,找到 log_id 的日志内容 Dif_ID=`sed -n "$line"p dif |awk '{print $2}'` echo "Dif_ID: $Dif_ID" #3.1 根据 log_id,查新增内容 mysql -u{数据库登录用户} -p'{数据库登录密码}' -h{数据库登录地址} -e "use {数据库名}; SELECT users.username, log.log_time, log.ip, log.title, log.content from {日志表} log, {用户表} users where log.user_id=users.user_id and log_id='$Dif_ID' and log_time >= '$begin_time' AND log_time <= '$end_time';" >> ${Ct_SNew} done #3.2 去掉无用行 cat ${Ct_SNew} |grep -v "content" > ${Ct_New} #3.3 查新增内容 cat ${Ct_New} |while read line do user=`echo $line | awk '{print $1}'` time=`echo $line | awk '{print $3}'` title=`echo $line | awk '{print $5}'` if [ "$title" == "修改用户" ]; then content=`echo $line | awk -F'username=' '{print $2}'` else content=`echo $line | awk -F'title=' '{print $2}'` fi #3.3.1 如果日志内容为空,表示登录 # 登录失败会显示密码,也要过滤掉 if [ ! -n "$content" ] || [ "$title" == "登录失败" ]; then content1="" elif [ "$title" == "修改用户" ]; then content1=`echo $content` else content1="《$content》" fi #去除标题内容里面的空格 content2=`echo ${content1// /}` echo "content2= $content2" #3.3.2 钉钉通知 SendMessageToDingdingljy ${token1} ${user} ${time} ${title} ${content2} SendMessageToDingdingljy ${token2} ${user} ${time} ${title} ${content2} done #3.4 替换最新log_id文件,防止重复发钉钉 cp ${ID_New} ${ID_Old} fi
2、运行效果图:
最后感叹下,用高级语言写应该没那么累赘,有机会改成python脚本~~~