Разбор Apache отформатированных URL в Ruby - PullRequest
1 голос
/ 06 апреля 2011

Как мне взять файл общего журнала 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 Псевдокод в порядке.

Ответы [ 2 ]

2 голосов
/ 06 апреля 2011
  1. Вы можете создать хеш, отображающий каждый путь на количество попаданий.Для удобства я предлагаю использовать 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}
    
  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. Хотя geeky, использование sprintf или String#% является отличным способом выложить отформатированные отчеты.Например:

      puts "%-15s %s" % ["Hello","####"]
      #=> "Hello           ####"
      
    3. Точно так же, как вам нужно было найти самое длинное имя для хорошего форматирования, вы можете найти URL с наибольшим количеством показов, чтобы вы могли масштабировать самое длинноеколичество хэшей к этому значению.Hash#values даст вам массив всех значений.В качестве альтернативы, возможно, у вас есть требование, чтобы один # всегда представлял 100 обращений или что-то в этом роде.

    4. Обратите внимание, что String#* позволяет создавать строку с повторением:

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

Если у вас есть конкретные вопросы с вашим кодом, задавайте больше вопросов!

1 голос
/ 06 апреля 2011

Поскольку это домашнее задание, я не буду давать вам точного ответа, но Симона Карлетти внедрила Ruby класс для анализа файлов журнала Apache.Вы можете начать там и посмотреть, как он делает вещи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...