【问题标题】:Parse Apache Formatted URLs in Ruby在 Ruby 中解析 A​​pache 格式的 URL
【发布时间】:2011-07-30 11:14:27
【问题描述】:

我如何获取一个 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 伪代码很好。

【问题讨论】:

  • 现在,仅仅因为你删除了显示这是一个家庭作业问题的帖子并不意味着你可以通过声称它不是来解决这个问题。
  • Phrogz,我从未声称这不是家庭作业。您能否将直方图添加到我的标签中,因为我不能?
  • @에이바 由于您使用homework 标签提出问题,然后将其删除并询问没有该标签的较小版本,我粗鲁地假设您试图隐藏这个事实。我道歉。有关创建直方图的帮助,请参阅我的答案。

标签: ruby regex apache url


【解决方案1】:
  1. 您可以创建一个哈希值,将每个路径映射到命中数。为方便起见,我建议在您询问以前从未见过的路径时使用将值设置为 0 的 Hash。例如:

    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}
    
  2. 如果日志文件真的很大,不要将整个文件都放入内存中,而是一次处理一行。 (查看File 类的方法。)

  3. 因为 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]
    
  4. 您可能希望选择根据状态代码过滤这些。例如,您是否想在图表中包含有人输入错误的所有 404 次点击?如果你没有把所有的行都塞进内存,你就不会使用Array#select,而是在你的循环中跳过它们。

  5. 在您收集了所有点击后,就该写出结果了。一些有用的提示:

    1. Hash#keys 可以一次性为您提供数组的所有键(路径)。您可能想用相同数量的空格写出所有路径,因此您需要找出最长的路径。或许您想map 路径到它们的长度,然后得到max 元素,或者您想使用max_by 找到最长的路径,然后找到它的长度。

    2. 虽然很奇怪,但使用 sprintfString#% 是布置格式化报告的好方法。例如:

      puts "%-15s %s" % ["Hello","####"]
      #=> "Hello           ####"
      
    3. 就像您需要找到最长的名称以获得良好的格式一样,您可能希望找到点击次数最多的 URL,以便您可以将最长的哈希值缩放到该值。 Hash#values 会给你一个包含所有值的数组。或者,您可能要求一个 # 必须始终代表 100 次点击或其他内容。

    4. 请注意,String#* 允许您通过重复创建字符串:

      p '#'*10
      #=> "##########"
      

如果您对代码有具体问题,请提出更多问题!

【讨论】:

    【解决方案2】:

    由于这是家庭作业,我不会给你确切的答案,但 Simone Carletti 已经实现了 Ruby class 来解析 Apache 日志文件。你可以从那里开始,看看他是如何做事的。

    【讨论】:

    • 这不是我的问题,更多的是如何制作直方图。
    猜你喜欢
    • 2016-07-23
    • 2013-05-04
    • 2011-11-28
    • 2010-09-14
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 2010-09-17
    相关资源
    最近更新 更多