Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Linux下处理实时日志生成另一个实时日志

一.背景介绍

1.知识点

写这篇文章,主要有下面几个知识点想介绍: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://www.linuxidc.com/Linux/2013-06/85457.htm  中的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 $pids
    kill -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 ]
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":["8u811au732bu521bu65b0u79d1u6280u6709u9650u516cu53f8uff08u4e60u5927u7237u6daeu8089u5bf9u976210000u7c73u7684u79d1u6280u516cu53f8uff09"]},"2028098":{"im_account":["3658247660","192683241","197488883","108963206","197305001"],"name":["9u811au732bu521bu65b0u79d1u6280u6709u9650u516cu53f8"]}}";    tail -f $logfile | grep sendMsgOk | grep "spamReasons=[]" | awk -F" " "{
        printf("%s %s %s %s ",$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(" ",$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 ." " . $v ." " . $name ." ";
        }
    }
 
    $line = $_SERVER["argv"][2];//获取日志的一条记录
    $logArr = explode(" ", $line);
    //echo $line . " ";    //获取各个字段
    $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 . " ";
    if(isset($userId[$fui])) { //fromUserId是某个企业的叮咚id
        //echo $line . " ";
        $output .= "companyId=$userId[$fui] ";
        $output .= "companyName=$compName[$fui] ";
        $output .= "companyDingdongId=$fui ";
        $output .= "personalDingdongId=$tui ";
        $output .= "whoSend=0 ";
        $output .= $msgContent;
        echo $output . " ";
    } else if(isset($userId[$tui])) { //toUserId是某个企业的叮咚id
        //echo $line . " ";
        $output .= "companyId=$userId[$tui] ";
        $output .= "companyName=$compName[$tui] ";
        $output .= "companyDingdongId=$tui ";
        $output .= "personalDingdongId=$fui ";
        $output .= "whoSend=1 ";
        $output .= $msgContent;
        echo $output . " ";
    }
?>