企业命令linux下处理实时日志生成另一个实时日志
时间紧张,先记一笔,后续优化与完善。
一.背景分析
1.知识点
写这篇blog,主要有下面几个知识点想分析:
curl获得http响应内容;
shell中执行php文件;
php中执行shell命令(通过exec函数);
php实现tail -f命令;
包含空格的参数如何作为参数传递(用双引号括起来)。
2.业务流程
这篇blog的背景是读取"/data3/im-log/nginx.im.imp.current/nginx.im.imp.current_current"这个实时日记,生成招聘会所需的实时日记。
业务流程如下:
(1)从http://bj.baidu.com/jobfairs/jobfairs_im_port.php?action=getIms获得企业和IM客户端id的关系。
响应的格式如下:
{"status":1,"ret":{"company_id":{“im_accout”:[im_id],"company_name":[]}}}
获得到的数据如下:
{"status":1,"ret":{"2028107":{"im_account":["31669394","50000098"],"name":["baidu"]},"2028098":{"im_account":["50029298","50000098","31669376","31669394","50006271"],"name":["sogou"]}},"msg":""}
这里遇到的第一个问题是我开辟所在的环境和http://bj.baidu.com不在同一个网段内,该url服务所在的IP为10.3.255.201,此时我须要进行hosts映射,这样当我拜访http://bj.baidu.com/jobfairs/jobfairs_im_port.php?action=getIms时,便相称于我在拜访了http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms。
但是我们一定有一个疑问,为什么我们不直接使用http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms来进行拜访,谜底是我们须要通过url获得到用户的城市,即http://bj.baidu.com/jobfairs/jobfairs_im_port.php?action=getIms,这里面包含bj.baidu.com,包含用户的城市信息bj。
解决方法是通过curl对url和host进行映射:
curl -H "Host: bj.ganji.com" http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms
参考链接:http://blog.csdn.net/lianxiang_biancheng/article/details/7575370 中的curl命令的使用。
(2)其次,如果这条日记记录中fromUserId或者toUserId包含某个企业的IM客户端id,则说明这条消息属于这个企业;
(3)最后,生成所需格式的日记,日记的字段格式如下:
时间 企业Id 企业名称 企业IM的id 应聘者IM的id 谁发送的信息(0:企业,1:应聘者) 消息内容
二.采取了三种实现方法
1.第一种:shell读取每一行记录传递给php进行匹配并输出
(1)start.sh是启动文件,如下:
#!/bin/sh#执行前清除所有该进程
pids=`ps aux | grep jobfairs | grep -v "grep" | awk '{print $2}'`
if [ "$pids" != "" ];then echo $pidskill -9 $pids
fi
sh jobfairs.sh >> /home/baidu/log/jobfairs.log
(2)jobfairs.sh是获得http内容,读取实时日记并每2分钟重新请求的实现,如下:
#!/bin/shlogfile="/data3/im-log/nginx.im.imp.current/nginx.im.imp.current_current"hours=`date +%H`
start_time=`date +%s`#17点后停止运行程序
while [ $hours -lt 17 ]
dores=`curl -s -H "Host: bj.baidu.com" http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms`#echo $reslen=${#res}if [ $len = 0 ]; thenecho "Failed! Request error!"exitfistatus=`echo $res | sed -e 's/.*status"://' -e 's/,.*//'`if [ $status != 1 ]; then echo "Failed! Request stauts:"$statusexitfiret=`echo $res | sed -e 's/.*ret"://' -e 's/,"msg.*//'`#ret='{"2028097":{"im_account":["2875001357","197823104","3032631861","197305863"],"name":["8\u811a\u732b\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8\uff08\u4e60\u5927\u7237\u6dae\u8089\u5bf9\u976210000\u7c73\u7684\u79d1\u6280\u516c\u53f8\uff09"]},"2028098":{"im_account":["3658247660","192683241","197488883","108963206","197305001"],"name":["9\u811a\u732b\u521b\u65b0\u79d1\u6280\u6709\u9650\u516c\u53f8"]}}';tail -f $logfile | grep sendMsgOk | grep "spamReasons=\[\]" | awk -F"\t" '{printf("%s\t%s\t%s\t%s\n",$1,$3,$4,$11); }' | while read linedo/usr/local/webserver/php/bin/php jobfairs.php $ret "$line"#120s后停止生成日记,重新执行http请求去获得公司相干信息end_time=`date +%s`if [ $(expr $end_time - $start_time) -ge 120 ]; then#echo `date +%T`" "`date +%D`#echo "120s is done!"breakfidonestart_time=`date +%s`hours=`date +%H`
done
这里还涉及到一个知识点,就是如何将包含空格的字符串作为参数传递。
这里的场景是这样的:由于一行记录各个字段是以制表符分隔的,其中有一个字段msgContent是消息内容,而消息中经常包含空格,而php接受外来参数默许是以空格分隔的,这样如果将$line作为参数进行传递,就致使msgContent被分隔为了好几个字段。那我们如何解决这个问题呢,谜底就是通过加双引号(即将$line变为"$line"),将一行记录作为一个团体字符串传入即可,然后php接收到这个字符串后,再通过explode("\t",$line)进行分隔出各个字段。如下所示:
/usr/local/webserver/php/bin/php jobfairs.php $ret
"$line"
(3)jobfairs.php是对实时日记的每一行进行匹配并输出为IM的log格式:
<?php$ret = $_SERVER["argv"][1];$arr = json_decode($ret, true);//将json字符串解码成数组foreach ($arr as $key => $value) {$name = $value["name"][0];//企业名称foreach ($value["im_account"] as $v) { //企业对应的叮咚id$userId[$v] = $key;$compName[$v] = $name;//echo $key ."\t" . $v ."\t" . $name ."\n";}}$line = $_SERVER["argv"][2];//获得日记的一条记录$logArr = explode("\t", $line);//echo $line . "\n";//获得各个字段$time = $logArr[0];$fromUserId = $logArr[1];$toUserId = $logArr[2];$msgContent = $logArr[3];$fuiArr = explode('=', $fromUserId);$tuiArr = explode('=', $toUserId);$fui = $fuiArr[1];$tui = $tuiArr[1];$output = $time . "\t";if(isset($userId[$fui])) { //fromUserId是某个企业的叮咚id//echo $line . "\n";$output .= "companyId=$userId[$fui]\t";$output .= "companyName=$compName[$fui]\t";$output .= "companyDingdongId=$fui\t";$output .= "personalDingdongId=$tui\t";$output .= "whoSend=0\t";$output .= $msgContent;echo $output . "\n";} else if(isset($userId[$tui])) { //toUserId是某个企业的叮咚id//echo $line . "\n";$output .= "companyId=$userId[$tui]\t";$output .= "companyName=$compName[$tui]\t";$output .= "companyDingdongId=$tui\t";$output .= "personalDingdongId=$fui\t";$output .= "whoSend=1\t";$output .= $msgContent;echo $output . "\n";}
?>
2.第二种:php执行shell命令并将输出结果进行匹配
注:该方法不能生成实时日记,因为tail -f命令是实时获得更新命令,php无法获得其返回结果。所以该方法仅用于读取一段牢固文本并进行处理。
这里通过exec执行tail -n1000这个shell命令,获得到最后1000行数据然后再进行处理。同时,这里还调用了php中curl模块获得http响应内容。该文件名为jobfairs2.php。
灯,带有一种明亮的光,每当深夜来临,是它陪伴着你,如此默默无闻。它是平凡的,外表华丽与否,那都是一样的,珍珠点缀,水晶加饰的灯它只能用以装饰,来满足人们的虚荣心,比起这,普普通通的日光灯是幸运的,因为它照明的本性没有改变,如同生活中的一部分人平平凡凡却实实在在。
<?php//error_reporting(E_ALL & ~E_NOTICE);$host = array("Host: bj.baidu.com");$data = 'user=xxx&qq=xxx&id=xxx&post=xxx';$url = 'http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms';$res = curl_post($host, $data, $url);$arr = json_decode($res, true);$status = $arr["status"];if ($status != 1) {echo "Request Failed!";exit;}//获得返回的企业信息$ret = $arr["ret"];foreach ($ret as $key => $value) {$name = $value["name"][0];//将IM的Id和企业id进行hash映射foreach ($value["im_account"] as $v) {$userId[$v] = $key;$compName[$v] = $name;}}$logfile = "/data3/im-log/nginx.im.imp.current/nginx.im.imp.current_current";//tail -n1000获得最后1000行记录,并保存到$log变量中$shell = "tail -n 1000 $logfile | grep sendMsgOk | grep 'spamReasons=\[\]' | ";$shell .= "awk -F'\t' '{print $1,$3,$4,$11;}'";exec($shell, $log); //将执行的shell结果保存到数组中//处理每一行记录foreach ($log as $line) {//通过正则表达式匹配出所须要的字段$flag = preg_match("/([0-9]+:[0-9]+:[0-9]+).*fromUserId=([0-9]+).*toUserId=([0-9]+).*msgContent=(.*)/", $line, $matches);if( $flag == 0 ){//匹配失败continue;}//echo $line . "\n";$time = $matches[1];$fui = $matches[2];$tui = $matches[3];$msgContent = $matches[4];//查看fromUserId和toUserId有无对应的公司$output = $time . "\t";//通过hash判断IM的id是否属于某个企业if(isset($userId[$fui])){//echo $line . "\n";$output .= "companyId=$userId[$fui]\t";$output .= "companyName=$compName[$fui]\t";$output .= "companyDingdongId=$fui\t";$output .= "personalDingdongId=$tui\t";$output .= "whoSend=0\t";$output .= $msgContent;echo $output . "\n";}else if(isset($userId[$tui])){//echo $line . "\n";$output .= "companyId=$userId[$tui]\t";$output .= "companyName=$compName[$tui]\t";$output .= "companyDingdongId=$tui\t";$output .= "personalDingdongId=$fui\t";$output .= "whoSend=1\t";$output .= $msgContent;echo $output . "\n";}}/** 提交请求* @param $host array 须要配置的域名 array("Host: bj.ganji.com");* @param $data string 须要提交的数据 'user=xxx&qq=xxx&id=xxx&post=xxx'....* @param $url string 要提交的url 'http://192.168.1.12/xxx/xxx/api/';*/function curl_post($host,$data,$url){$ch = curl_init();$res= curl_setopt($ch, CURLOPT_URL,$url);//var_dump($res);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);curl_setopt ($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_POST, 0);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch,CURLOPT_HTTPHEADER,$host);$result = curl_exec($ch);curl_close($ch);if ($result == NULL) {return 0;}return $result;}
?>
php执行shell命令的函数参考链接:
http://blog.csdn.net/a600423444/article/details/6059548
3.第三种:php自己实现tail -f命令来实时读取日记文件
该文件名为jobfairs3.php。这里是php通过文件偏移量实现tail -f命令的效果。但是不实用于读取每次都动态指向不同文件。同时,这里还调用了php中curl模块获得http响应内容。
<?php//error_reporting(E_ALL & ~E_NOTICE);//php通过curl获得http响应的内容$host = array("Host: bj.ganji.com");$data = 'user=xxx&qq=xxx&id=xxx&post=xxx';$url = 'http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms';$res = curl_post($host, $data, $url);//将json字符串解码成数组 $arr = json_decode($res, true);$status = $arr["status"];if ($status != 1) {echo "Request Failed!";exit;}//获得返回的企业信息$ret = $arr["ret"];foreach ($ret as $key => $value) {$name = $value["name"][0];//将IM的Id和企业id进行hash映射foreach ($value["im_account"] as $v) {$userId[$v] = $key;$compName[$v] = $name;}}$logfile = "/data3/im-log/nginx.im.imp.current/nginx.im.imp.current_current";tail_f($logfile, $userId);//通过php实现shell的tail -f命令function tail_f($logfile, $userId) {$size = filesize($logfile);$ch = fopen($logfile, 'r');$i = 0;while (1) {clearstatcache();$tmp_size = filesize($logfile);if (0 < ($len = $tmp_size - $size)) {$i = 0;fseek($ch, -($len -1), SEEK_END);$content = fread($ch, $len);$lineArr = explode("\n", $content);foreach ($lineArr as $line) {//echo $line . "\n";if (preg_match("/sendMsgOk.*spamReasons=\[\]/", $line)) {matchCompany($line, $userId);}}} else {$i++;if ($i > 60) {echo PHP_EOL . 'The file in 60s without change,So exit!';break;}sleep(1);continue;}$size = $tmp_size;}fclose($ch);}//对一行记录判断是否在企业信息中,如果在,则输出组合后的记录function matchCompany($line, $userId) {$flag = preg_match("/([0-9]+:[0-9]+:[0-9]+).*fromUserId=([0-9]+).*toUserId=([0-9]+).*msgContent=(.*)\tchannel=.*/", $line, $matches);if( $flag == 0 ){return;}//echo $matches[0] ."\t" .$matches[1] . "\t" . $matches[2] . "\t" . $matches[3] . "\t" . $matches[4] . "\n";$time = $matches[1];$fromUserId = $matches[2];$toUserId = $matches[3];$msgContent = $matches[4];//查看fromUserId和toUserId有无对应的公司$output = $time . "\t";//如果IM的id属于某个企业if(isset($userId[$fromUserId])){//echo $line . "\n";$output .= "companyId=$userId[$fui]\t";$output .= "companyName=$compName[$fui]\t";$output .= "companyDingdongId=$fui\t";$output .= "personalDingdongId=$tui\t";$output .= "whoSend=0\t";$output .= $msgContent;echo $output . "\n";}else if(isset($userId[$toUserId])){//echo $line . "\n";$output .= "companyId=$userId[$tui]\t";$output .= "companyName=$compName[$tui]\t";$output .= "companyDingdongId=$tui\t";$output .= "personalDingdongId=$fui\t";$output .= "whoSend=1\t";$output .= $msgContent;echo $output . "\n";}}/** 提交请求* @param $host array 须要配置的域名 array("Host: bj.ganji.com");* @param $data string 须要提交的数据 'user=xxx&qq=xxx&id=xxx&post=xxx'....* @param $url string 要提交的url 'http://192.168.1.12/xxx/xxx/api/';*/function curl_post($host,$data,$url){$ch = curl_init();$res= curl_setopt($ch, CURLOPT_URL,$url);//var_dump($res);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);curl_setopt ($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_POST, 0);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch,CURLOPT_HTTPHEADER,$host);$result = curl_exec($ch);curl_close($ch);if ($result == NULL) {return 0;}return $result;}
?>
三.总结
本文最终采取了第一种方法来实现,最后还须要将start.sh参加到crontab -e中,参加如下一条记录:
30 9 * * * cd /home/baidu/zhaolincheung/JobFairs; sh start.sh
第二种方法不适合这里的业务,因为须要实时读取日记,但是php的exec无法返回tail -f的读取结果。
第三种方法也可以实现,仅实用读取一个牢固的动态增长的日记文件。但是这里的日记文件nginx.im.imp.current_current是一个软连接,它会动态地指向不同的文件,如下图所示:
这样自己实现tail -f的话,由于文件会改变,致使文件的动态偏移量有多是不同的文件的,致使读取的日记不对。所以这类方法也没有采取。
文章结束给大家分享下程序员的一些笑话语录: 某程序员对书法十分感兴趣,退休后决定在这方面有所建树。花重金购买了上等的文房四宝。一日突生雅兴,一番磨墨拟纸,并点上了上好的檀香,颇有王羲之风 范,又具颜真卿气势,定神片刻,泼墨挥毫,郑重地写下一行字:hello world.
企业命令linux下处理实时日志生成另一个实时日志相关推荐
- linux查代替命令,Linux下查/删/替 命令(转)
▪查看某目录下所有文件的个数: [root@localhost1 opt]# ls -l |grep "^-"|wc -l ▪查看某目录下所有文件的个数,包括子目录里面的: [ro ...
- Linux下的tree命令 --Linux下目录树查看
Linux下的tree命令 --Linux下目录树查看 有时我们需要生成目录树结构,可以使用的有ls -R,但是实际效果并不好 这时需要用到tree命令,但是大部分Linux系统是默认不安装该命令的, ...
- Linux下Makefile的automake生成全攻略(转)
Linux下Makefile的automake生成全攻略(转)[@more@] 文/余涛 作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便 ...
- linux下tar命令解压缩,tar解压缩命令 Linux下的tar压缩解压缩命令详解
<tar解压缩命令 Linux下的tar压缩解压缩命令详解>由会员分享,可在线阅读,更多相关<tar解压缩命令 Linux下的tar压缩解压缩命令详解(14页珍藏版)>请在人人 ...
- java调用c 生成so,Java在linux下调用C/C++生成的so文件
Java在linux下调用C/C++生成的so文件 1. CplusUtil.java是java web工程中的一个工具类 内容如下: CplusUtil.java package cn.undone ...
- 嵌入式linux完整top命令,linux下top命令详细介绍
top 命令是 Linux 下常用的系统资源占用查看及性能分析工具,能够实时显示系统中各个进程的资源(比如cpu.内存的使用)占用状况,top命令的执行结果是一个动态显示过程,即可以通过用户按键来不断 ...
- linux下安装navicat并生成桌面图标
linux下安装navicat并生成桌面图标 下载客户端 下载连接 http://www.navicat.com.cn/dow... 从navicat官网下载试用客户端即可 下载ico http:// ...
- linux生成缩略图,linux下使用imagemagick批量生成缩略图的python脚本
linux下使用imagemagick批量生成缩略图的python脚本.程序用了递归,可以查找目录下所有的图片按照一定的规则生成指定宽度的缩略图. #!/usr/bin/env python # -* ...
- linux 测试串口命令,Linux 下测试串口的命令microcom
昨天应为要测试主板上的串口,查了一下,可以使用microcom 这条命令进行测试. 命令使用方法很简单: Usage: microcom [-d DELAY] [-t TIMEOUT] [-s SPE ...
最新文章
- 管理系统状态栏和导航栏(翻译)
- 10月了,聊聊我今年参加秋招的真实感受
- 配置解压版本的Tomcat为Windows服务
- linux安装mysql5.7.18_Linux下安装mysql5.7.18版本步骤
- CPU多核并发缓存架构介绍
- DRBD+Corosync+Pacemaker+MySQL(下)
- nginx日志的监控【转】
- Java连接MySQL数据库步骤
- spring注解原理解析
- sagemath matlab,sagemath 是否真的好用?还是隐藏了大坑?
- windows无法访问共享文件 所有解决方法(非复制粘贴的烂大街处理方法)
- 加州房价篇 (三) : 模型的训练,评估和房价的预测
- 星起航:抖音小店截流是什么,怎么玩?
- 影像组学训练营 第三天(共三天)
- Ubuntu 18.04 创建 mdadm RAID0
- ZZULIOJ:1023大小写转换
- 斐讯(Phicomm)空气检测仪(悟空 M1)通过 EasyLink
- 【故障诊断】基于贝叶斯优化支持向量机的轴承故障诊断附matlab代码
- 化工企业MES解决方案
- angular的数据双向绑定
热门文章
- PHP isset 函数作用
- Incorrect number of FETCH variables
- stl的complex(二)
- JAVA之二叉查找树
- 执行RF测试只生成output.xml文件,不生成log和report文件
- 数据结构之C语言模拟整数数组实现
- http://wenku.baidu.com/view/63e7b8270066f5335a812142.html
- Q+ Web 改版设计小结
- 来自韩国的优秀Java应用性能监控软件JENNIFER
- 爱因斯坦牛顿达尔文投胎中国后