如何接收Apache Common Log文件并以简洁的直方图列出其中的所有URL:
/favicon.ico ##
/manual/mod/mod_autoindex.html #
/ruby/faq/Windows/ ##
/ruby/faq/Windows/index.html #
/ruby/faq/Windows/RubyonRails #
/ruby/rubymain.html #
/robots.txt ########
测试文件样本:
65.54.188.137 - - [03/Sep/2006:03:50:20 -0400] "GET /~longa/geomed/ppa/doc/localg/localg.htm HTTP/1.0" 200 24834
65.54.188.137 - - [03/Sep/2006:03:50:32 -0400] "GET /~longa/geomed/modules/sv/scen1.html HTTP/1.0" 200 1919
65.54.188.137 - - [03/Sep/2006:03:53:51 -0400] "GET /~longa/xlispstat/code/statistics/introstat/axis/code/axisDens.lsp HTTP/1.0" 200 15962
65.54.188.137 - - [03/Sep/2006:04:03:03 -0400] "GET /~longa/geomed/modules/cluster/lab/nm.pop HTTP/1.0" 200 66302
65.54.188.137 - - [03/Sep/2006:04:11:15 -0400] "GET /~longa/geomed/data/france/names.txt HTTP/1.0" 200 20706
74.129.13.176 - - [03/Sep/2006:04:14:35 -0400] "GET /~jbyoder/ambiguouslyyours/ambig.rss HTTP/1.1" 304 -
这就是我现在所拥有的(但我不知道如何制作直方图):
...
---
$apache_line = /\A(?<ip_address>\S+) \S+ \S+ \[(?<time>[^\]]+)\] "(?<method>GET|POST) (?<url>\S+) \S+?" (?<status>\d+) (?<bytes>\S+)/
$parts = apache_line.match(file)
$p parts[:ip_address], parts[:status], parts[:method], parts[:url]
def get_url(file)
hits = Hash.new {|h,k| h[k]=0}
File.read(file).to_a.each do |line|
while $p parts[:url]
if k = k
h[k]+=1
puts "%-15s %s" % [k,'#'*h[k]]
end
end
end
...
---
以下是完整的问题:http://pastebin.com/GRPS6cTZ伪代码很好。
答案 0 :(得分:2)
您可以创建哈希映射到命中数的每个路径。为方便起见,我建议使用一个Hash,当你要求一个以前没见过的路径时,它将值设置为0。例如:
hits = Hash.new{ |h,k| h[k]=0 }
...
hits["/favicon.ico"] += 1
hits["/ruby/faq/Windows/"] += 1
hits["/favicon.ico"] += 1
p hits
#=> {"/favicon.ico"=>2, "/ruby/faq/Windows/"=>1}
如果日志文件非常庞大,而不是将整个内容放入内存中,请一次处理一行。 (查看File
类的方法。)
由于Apache日志文件格式没有标准分隔符,我建议使用正则表达式来获取每一行并将其分成您想要的块。假设您正在使用Ruby 1.9,我将使用命名捕获来稍后对方法进行干净访问。例如:
apache_line = /\A(?<ip_address>\S+) \S+ \S+ \[(?<time>[^\]]+)\] "(?<method>GET|POST) (?<url>\S+) \S+?" (?<status>\d+) (?<bytes>\S+)/
...
parts = apache_line.match(log_line)
p parts[:ip_address], parts[:status], parts[:method], parts[:url]
您可能希望根据状态代码选择过滤这些内容。例如,您是否希望在图表中包含有人输入错误的所有404次点击?如果你没有将所有行都插入内存,你就不会使用Array#select
,而是在循环中跳过它们。
收集完所有热门后,是时候写出结果了。一些有用的提示:
Hash#keys
可以同时为您提供数组的所有键(路径)。您可能希望写出具有相同空白量的所有路径,因此您需要确定哪个路径最长。也许您希望map
路径到达其长度,然后获取max
元素,或者您可能希望使用max_by
来查找最长路径,然后找到它的长度。
虽然令人讨厌,但使用sprintf
或String#%
是制作格式化报告的好方法。例如:
puts "%-15s %s" % ["Hello","####"]
#=> "Hello ####"
就像你需要找到最好的格式名称一样,可能想找到点击率最高的网址,这样你就可以将最长的哈希值扩展到该值。 Hash#values
将为您提供所有值的数组。或者,您可能要求一个#
必须始终代表100次点击或其他内容。
请注意,String#*
允许您通过重复创建字符串:
p '#'*10
#=> "##########"
如果您对代码有任何疑问,请提出更多问题!
答案 1 :(得分:1)
由于这是作业,我不会给你确切的答案,但是Simone Carletti已经实现了Ruby class来解析Apache日志文件。你可以从那里开始看看他是如何做事的。