Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4212409
  • 博文数量: 291
  • 博客积分: 8003
  • 博客等级: 大校
  • 技术积分: 4275
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-30 18:28
文章分类

全部博文(291)

文章存档

2017年(1)

2013年(47)

2012年(115)

2011年(121)

2010年(7)

分类: Python/Ruby

2011-03-21 20:56:59

前段时间公司运维部门要求我对CDN节点的日志进行分析,具体要求如下
1、输入参数为文件名,支持统配。文件为gz压缩,可用zcat解压。统配的多个文件,
必须是一天内的。
2、文件内为一条条的访问日志。格式如下:
2011-01-02 15:55:01 122.245.127.73
"/down.eebbk.net/xzzx/h1sp/\xb8\xdf\xd6\xd0\xc9\xfa\xce\xef\xb1\xd8\xd0\xde2
\xc8\xbe\xc9\xab\xcc\xe5\xb1\xe4\xd2\xec(\xb6\xfe).avi" 206 11568567 3316812
"
&dhbig=\xbb\xc6\xb8\xd4\xbf\xce\xcc\xc3&dhsmall=\xb8\xdf\xd6\xd0\xb1\xd8\xd0
\xde2&dhtiny=\xc9\xfa\xce\xef&title=\xca\xd3\xc6\xb5\xd1\xa7\xcf\xb0xbb\xfa
H1&mode=6846" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET
CLR 1.1.4322; .NET CLR 2.0.50727)"
3、该条日志中,2011-01-02 15:55:01 为日志时间点。其基准时间点的计算方法为,
将该时间点转换为标准的秒,再模300,得到基准时间点。如15:55。再比如,
18:23:08,其基准时间点位18:20。
4、该条日志中,表示应用层在3316812 毫秒,输出了11568567 字节。该信息折算到日
志统计上,是按如下处理:
--3316812 毫秒为 3316812/300000+1 = 11+1 = 12个日志计费点。(每个日志计费点
代表一个5分钟的区间)
--11568567字节平均分到12个日志计费点上,为该记录在该计费点上的带宽占用。如
11568567/12/300=3213bps
5、则该日志的流量将给15:00、15:05、15:10、15:15、15:20、15:25、15:30、
15:35、15:40、15:45、15:50、15:55这12个基准时间点,每个增加3123bps的值。
6、要求统计所有指定日志文件综合的各基准时间点的带宽
7、将各基准时间点的带宽值以如下格式输出显示:
time     bps
00:00   1903342
00:05   1833133
....
23:55   2312342
Total Traffic
 
8、由于该程序将是手动运行在Apache服务器上的。所以程序要轻量级,同时不用占用
太多的磁盘。或许比较理想的是直接处理zcat的输出。(服务器上没有php)
我花了5个小时,先写出了一个单线程的程序,后来又改为多线程,感觉用perl写起来比较快,之间学会了用parsewords进行解析日志,parsewords太好用了。
执行命令:perl analy_log.pl CT-ZHZ-1-N004-A-bbg04_2011010414*
测试结果,分析几十M的压缩日志,才2秒多
 
代码如下:
 
  1. use Text::ParseWords;
  2. use threads;
  3. use threads::shared;
  4. use Time::Local;
  5. #print @ARGV;

  6. #分析结果集

  7. my %result:shared;
  8. #最大线程数

  9. my $max_thread = 2;
  10. #线程池

  11. my @thread_array;
  12. my $current_thread = 0;

  13. #检查参数

  14. $argv_len = @ARGV;
  15. if($argv_len == 0)
  16. {
  17.     print "it need filename\n";
  18.     exit(1);
  19. }

  20. #处理参数开始

  21. $cmd="ls '".join("' '",@ARGV)."' |";
  22. #print $cmd."\n";


  23. #处理参数结束


  24. open(PIPE, $cmd);
  25. @filenames = <PIPE>;
  26. close(PIPE);
  27. #print "[";

  28. #print @filenames;

  29. #print "]\n";


  30. #多线程分析多个日志文件

  31. foreach(@filenames){
  32.     if( $current_thread >= $max_thread )
  33.   {
  34.     foreach my $thread( @thread_array )
  35.     {
  36.       $thread -> join( );
  37.     }
  38.     $current_thread = 0;
  39.     @thread_array=();
  40.   }
  41.   $thread_array[$current_thread] = threads -> new(\&analy,$_);
  42.   $current_thread ++;
  43. }

  44. #等待线程结束

  45. foreach my $thread( @thread_array )
  46. {
  47.    $thread -> join();
  48. }

  49. #按时间排序输出

  50. my @key=sort(keys(%result));
  51. print "time\t\t\tbps\n";
  52. foreach (@key){
  53.         $k=$_;
  54.         print $k."\t\t".$result{$k}."\n";
  55. }

  56. #去除前后空白字符

  57. sub trim
  58. {
  59.         my $string = shift;
  60.         $string =~ s/^\s+//;
  61.         $string =~ s/\s+$//;
  62.         return $string;
  63. }

  64. #分析一个日志文件

  65. sub analy
  66. {
  67.     my $filename= trim(shift);
  68.     $cmd="zcat $filename |";
  69.     open(PIPEFILE,$cmd);
  70.     @lines=<PIPEFILE>;
  71.     close(PIPEFILE);
  72.     foreach(@lines)
  73.     {
  74.         #分解每一行

  75.         my @line=quotewords(" ", 1, $_);
  76.         #print join(",",@line)."\n";

  77.         #print $line[6]."\n";

  78.         
  79.         #根据时间合并

  80.         my($h,$m)=split(/:/g,$line[1]);
  81.         my($y,$mon,$d)=split(/-/g,$line[0]);
  82.         $m=int($m/5)*5;
  83.         my $point=int($line[6]/300000+1);
  84.         my $bps=int($line[5]/$point/300);
  85.      #print $line[0].$line[1]." m=$m,point=$point,bps=$bps\n";

  86.         $endtime=timelocal(0,$m,$h,$d,$mon,$y-1900);#秒,分,时,日,月,年(year-1900)

  87.         my @time_list=get_time_list($endtime,$point);
  88.         #累计字节数

  89.         my $i=0;
  90.         for($i=0;$i<$point;$i++)
  91.         {
  92.             $result{$time_list[$i]}+=$bps;
  93.         }
  94.     }
  95. }
  96. #获得时间列表

  97. sub get_time_list
  98. {
  99.     my $endtime=trim(shift);
  100.     my $point=trim(shift);
  101.     my @time_list;
  102.     my $i=0;
  103.     for($i=0;$i<$point;$i++)
  104.     {
  105.         push(@time_list,get_time_str($endtime));
  106.         $endtime-=300;
  107.     }
  108.     @time_list;
  109. }
  110. #获得时间字符串

  111. sub get_time_str
  112. {
  113.     my $endtime=trim(shift);
  114.     #@t=gmtime($endtime);

  115.     ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = localtime($endtime);
  116.     if($min<10)
  117.     {
  118.         $min="0$min";
  119.     }
  120.     if($hour<10)
  121.     {
  122.         $hour="0$hour";
  123.     }
  124.     if($day<10)
  125.     {
  126.         $day="0$day";
  127.     }
  128.     if($mon<10)
  129.     {
  130.         $mon="0$mon";
  131.     }
  132.     $year+=1900;
  133.     my $str="$year-$mon-$day_$hour:$min";
  134. }
阅读(5451) | 评论(2) | 转发(1) |
0

上一篇:Valgrind使用1

下一篇:perl判断ipv6,ipv4,ip

给主人留下些什么吧!~~

sandy-shi2011-03-25 12:37:03

楼主的功力真是深厚,佩服,希望有时间可以交流,msn:lvyoukaifa2008@163.com

小雅贝贝2011-03-22 09:50:42

不错啊。支持,以后要多多写博文啊,多多支持我们的活动呢~~