寫這篇文章,主要有下面幾個知識點想介紹:
curl獲取http相應內容;
shell中執行php文件;
php中執行shell命令(通過exec函數);
php實現tail -f命令;
包含空格的參數如何作為參數傳遞(用雙引號括起來)。
這篇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://www.linuxidc.com/Linux/2013-06/85457.htm 中的curl命令的使用。
(2)其次,如果這條日志記錄中fromUserId或者toUserId包含某個企業的IM客戶端id,則說明這條消息屬於這個企業;
(3)最後,生成所需格式的日志,日志的字段格式如下:
時間 企業Id 企業名稱 企業IM的id 應聘者IM的id 誰發送的信息(0:企業,1:應聘者) 消息內容
(1)start.sh是啟動文件,如下:
#!/bin/sh
#執行前清除所有該進程
pids=`ps aux | grep jobfairs | grep -v "grep" | awk '{print $2}'`
if [ "$pids" != "" ];then
echo $pids
kill -9 $pids
fi
sh jobfairs.sh >> /home/baidu/log/jobfairs.log
(2)jobfairs.sh是獲取http內容,讀取實時日志並每2分鐘重新請求的實現,如下:
#!/bin/sh
logfile="/data3/im-log/nginx.im.imp.current/nginx.im.imp.current_current"
hours=`date +%H`
start_time=`date +%s`
#17點後停止運行程序
while [ $hours -lt 17 ]
do
res=`curl -s -H "Host: bj.baidu.com" http://10.3.255.201/jobfairs/jobfairs_im_port.php?action=getIms`
#echo $res
len=${#res}
if [ $len = 0 ]; then
echo "Failed! Request error!"
exit
fi
status=`echo $res | sed -e 's/.*status"://' -e 's/,.*//'`
if [ $status != 1 ]; then
echo "Failed! Request stauts:"$status
exit
fi
ret=`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 line
do
/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!"
break
fi
done
start_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";
}
?>