时间紧张,先记一笔,后续优化与完善。

一.背景分析

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下处理实时日志生成另一个实时日志相关推荐

  1. linux查代替命令,Linux下查/删/替 命令(转)

    ▪查看某目录下所有文件的个数: [root@localhost1 opt]# ls -l |grep "^-"|wc -l ▪查看某目录下所有文件的个数,包括子目录里面的: [ro ...

  2. Linux下的tree命令 --Linux下目录树查看

    Linux下的tree命令 --Linux下目录树查看 有时我们需要生成目录树结构,可以使用的有ls -R,但是实际效果并不好 这时需要用到tree命令,但是大部分Linux系统是默认不安装该命令的, ...

  3. Linux下Makefile的automake生成全攻略(转)

    Linux下Makefile的automake生成全攻略(转)[@more@] 文/余涛 作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便 ...

  4. linux下tar命令解压缩,tar解压缩命令 Linux下的tar压缩解压缩命令详解

    <tar解压缩命令 Linux下的tar压缩解压缩命令详解>由会员分享,可在线阅读,更多相关<tar解压缩命令 Linux下的tar压缩解压缩命令详解(14页珍藏版)>请在人人 ...

  5. java调用c 生成so,Java在linux下调用C/C++生成的so文件

    Java在linux下调用C/C++生成的so文件 1. CplusUtil.java是java web工程中的一个工具类 内容如下: CplusUtil.java package cn.undone ...

  6. 嵌入式linux完整top命令,linux下top命令详细介绍

    top 命令是 Linux 下常用的系统资源占用查看及性能分析工具,能够实时显示系统中各个进程的资源(比如cpu.内存的使用)占用状况,top命令的执行结果是一个动态显示过程,即可以通过用户按键来不断 ...

  7. linux下安装navicat并生成桌面图标

    linux下安装navicat并生成桌面图标 下载客户端 下载连接 http://www.navicat.com.cn/dow... 从navicat官网下载试用客户端即可 下载ico http:// ...

  8. linux生成缩略图,linux下使用imagemagick批量生成缩略图的python脚本

    linux下使用imagemagick批量生成缩略图的python脚本.程序用了递归,可以查找目录下所有的图片按照一定的规则生成指定宽度的缩略图. #!/usr/bin/env python # -* ...

  9. linux 测试串口命令,Linux 下测试串口的命令microcom

    昨天应为要测试主板上的串口,查了一下,可以使用microcom 这条命令进行测试. 命令使用方法很简单: Usage: microcom [-d DELAY] [-t TIMEOUT] [-s SPE ...

最新文章

  1. 管理系统状态栏和导航栏(翻译)
  2. 10月了,聊聊我今年参加秋招的真实感受
  3. 配置解压版本的Tomcat为Windows服务
  4. linux安装mysql5.7.18_Linux下安装mysql5.7.18版本步骤
  5. CPU多核并发缓存架构介绍
  6. DRBD+Corosync+Pacemaker+MySQL(下)
  7. nginx日志的监控【转】
  8. Java连接MySQL数据库步骤
  9. spring注解原理解析
  10. sagemath matlab,sagemath 是否真的好用?还是隐藏了大坑?
  11. windows无法访问共享文件 所有解决方法(非复制粘贴的烂大街处理方法)
  12. 加州房价篇 (三) : 模型的训练,评估和房价的预测
  13. 星起航:抖音小店截流是什么,怎么玩?
  14. 影像组学训练营 第三天(共三天)
  15. Ubuntu 18.04 创建 mdadm RAID0
  16. ZZULIOJ:1023大小写转换
  17. 斐讯(Phicomm)空气检测仪(悟空 M1)通过 EasyLink
  18. 【故障诊断】基于贝叶斯优化支持向量机的轴承故障诊断附matlab代码
  19. 化工企业MES解决方案
  20. angular的数据双向绑定

热门文章

  1. PHP isset 函数作用
  2. Incorrect number of FETCH variables
  3. stl的complex(二)
  4. JAVA之二叉查找树
  5. 执行RF测试只生成output.xml文件,不生成log和report文件
  6. 数据结构之C语言模拟整数数组实现
  7. http://wenku.baidu.com/view/63e7b8270066f5335a812142.html
  8. Q+ Web 改版设计小结
  9. 来自韩国的优秀Java应用性能监控软件JENNIFER
  10. 爱因斯坦牛顿达尔文投胎中国后