- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我如何获取 Apache 通用日志文件并以整洁的直方图形式列出其中的所有 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 的哈希。例如:
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 日志文件格式没有标准分隔符,我建议使用正则表达式来获取每一行并将其分成您想要的 block 。假设您使用的是 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 ####"
就像您需要找到最长的名称以获得良好的格式一样,您可能想要找到点击次数最多的 URL,这样您就可以将最长的哈希值扩展到该值。 Hash#values
将为您提供一个包含所有值的数组。或者,您可能要求一个 #
必须始终代表 100 次匹配,或者类似的东西。
请注意,String#*
可让您通过重复创建字符串:
p '#'*10
#=> "##########"
如果您对代码有具体问题,请提出更多问题!
关于ruby - 在 Ruby 中解析 Apache 格式的 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5560796/
我是一名优秀的程序员,十分优秀!