Разобрать файл журнала на ruby - PullRequest
0 голосов
/ 01 мая 2018

Мне нужна твоя помощь. Я пишу скрипт на ruby, который разбирает файл журнала. Но я не могу написать простое регулярное выражение для такого журнала. Помоги мне, пожалуйста. Вот пример строки из журнала:

2014-01-09T06:16:53.766841+00:00 heroku[router]: at=info method=POST path=/logs/save_personal_data host=services.pocketplaylab.com fwd="5.13.87.91" dyno=web.10 connect=1ms service=42ms status=200 bytes=16
2014-01-09T06:16:53.772938+00:00 heroku[router]: at=info method=POST path=/api/users/100002844291023 host=services.pocketplaylab.com fwd="46.195.178.244" dyno=web.6 connect=2ms service=43ms status=200 bytes=52
2014-01-09T06:16:53.765430+00:00 heroku[router]: at=info method=GET path=/api/users/100005936523817/get_friends_progress host=services.pocketplaylab.com fwd="5.13.87.91" dyno=web.11 connect=1ms service=47ms status=200 bytes=7498
2014-01-09T06:16:53.760472+00:00 heroku[router]: at=info method=POST path=/api/users/1770684197 host=services.pocketplaylab.com fwd="74.139.217.81" dyno=web.5 connect=1ms service=17ms status=200 bytes=681
2014-01-09T06:15:15.893505+00:00 heroku[router]: at=info method=GET path=/api/users/1686318645/get_friends_progress host=services.pocketplaylab.com fwd="1.125.42.139" dyno=web.3 connect=8ms service=90ms status=200 bytes=7534
2014-01-09T06:16:53.768188+00:00 heroku[router]: at=info method=GET path=/api/users/100005936523817/get_friends_score host=services.pocketplaylab.com fwd="5.13.87.91" dyno=web.13 connect=2ms service=46ms status=200 bytes=9355
2014-01-09T06:15:17.858874+00:00 heroku[router]: at=info method=POST path=/api/users/1145906359 host=services.pocketplaylab.com fwd="107.220.72.53" dyno=web.14 connect=2ms service=362ms status=200 bytes=52
2014-01-09T06:16:53.797975+00:00 heroku[router]: at=info method=GET path=/api/users/100000622081059/count_pending_messages host=services.pocketplaylab.com fwd="174.239.6.42" dyno=web.12 connect=1ms service=20ms status=200 bytes=33
2014-01-09T06:16:53.796869+00:00 heroku[router]: at=info method=GET path=/api/users/100004683190675/get_friends_score host=services.pocketplaylab.com fwd="99.138.1.64" dyno=web.12 connect=2ms service=55ms status=200 bytes=16881
  • Мне нужно получить из файла:
    • URL-адреса (пример: / api / users / 1686318645 / get_friends_progress, / api / users / 1145906359);
    • время соединения + время обслуживания (пример: соединение = услуга 2 мс = 55 мс);
    • dyno (пример: dyno = web.12, dyno = web.14).

Мой код (Обновление):

     #!/usr/bin/env ruby
require 'csv'

sample_logs = File.readlines "/home/railsroger/Playlab_test/sample.log"

file_name = ARGV.last
result_parse = []
CSV.open(file_name, "wb") do |csv_line|
  csv_line << ['URL', 'Dyno', 'Connect', 'Service']
  sample_logs.each_with_index do |sample_log, idx|
    path    = sample_log.scan(/path=([^\s]+)/).first.first
    dyno    = sample_log.scan(/dyno=([^\s]+)/).first.first
    connect = sample_log.scan(/connect=([^\s]+)/).first.first
    service = sample_log.scan(/service=([^\s]+)/).first.first


    result_parse = [path, dyno, connect, service]

    csv_line << result_parse    

  end

end

Спасибо.

Ответы [ 3 ]

0 голосов
/ 01 мая 2018

Решение состоит в том, чтобы использовать именованные захваты : String#match(/dyno=(?<dyno>\S+)/) захватит строку динамо. Вы можете расширить регулярное выражение, чтобы соответствовать больше.

Вы можете поиграть с примером здесь: http://rubular.com/r/4XcovTiqh3 - с небольшим количеством проб и ошибок вы можете найти правильное регулярное выражение

Обновление после добавления вашего кода:

parser = log.match(/dyno=(?<dyno>\S+)/) 

вернет объект MatchData, из которого вы можете получить соответствующий динамо с помощью:

parser['dyno']

Как только вы завершите свое регулярное выражение, чтобы захватить больше из каждой строки, и если вы используете Ruby 2.4 или более позднюю версию, вы также можете использовать named_captures, чтобы получить хороший хеш со всеми соответствующими группами

Посмотрите, как это работает: https://repl.it/repls/SpectacularBewitchedPolygon

0 голосов
/ 01 мая 2018

Я не эксперт по регулярным выражениям, и также знаю, что код ниже пахнет -)), но вы можете взять это как отправную точку.

lines = File.readlines 'sample.log'

lines.each_with_index do |line, idx|
  path    = line.scan(/path=([^\s]+)/).first.first
  dyno    = line.scan(/dyno=([^\s]+)/).first.first
  connect = line.scan(/connect=([^\s]+)/).first.first
  service = line.scan(/service=([^\s]+)/).first.first
  puts "#{path} #{dyno} #{connect} #{service}"
end

Ссылка на реплей

Правка, предложенная Виктором Стрибьевым , что, очевидно, лаконично и лучше. Я должен предпочесть это по моему. Сохранение вышеуказанного кода по историческим причинам -))

lines.each_with_index do |line, idx|
  path    = line[/path=([^\s]+)/, 1]
  dyno    = line[/dyno=([^\s]+)/, 1]
  connect = line[/connect=([^\s]+)/, 1]
  service = line[/service=([^\s]+)/, 1]
  puts "#{path} #{dyno} #{connect} #{service}"
end
0 голосов
/ 01 мая 2018

Хорошо, чтобы написать свое регулярное выражение, вам нужно найти все эти пары some_variable=some_data.

Вот как вы можете это сделать:

/\S*=\S*/ #
 \S*      # match any non-whitespace-character, 0-n times
    =     # match the equal sign    
     \S*  # match any non-whitespace-character, 0-n times

Это будет соответствовать парам. Для извлечения данных вы используете группы захвата. Вы заключаете то, что хотите извлечь в скобки (xxx), для имени переменной и значения.

/(\S*)=(\S*)/  
 (\S*)         # capture the name
       (\S*)   # capture the value

Таким образом, для каждой строки журнала вы можете сделать:

line_of_log.scan(/(\S*)=(\S*)\s/)

Чтобы увидеть, что происходит, и для создания регулярных выражений, я рекомендую всегда пробовать его с помощью такого инструмента, как https://regex101.com/,, который действительно помогает понять, что происходит.

Это вернет массив массивов, подобных этому:

[["at", "info"],
 ["method", "POST"],
 ["path", "/api/online/platforms/facebook_canvas/users/100002266342173/add_ticket"],
 ["host", "services.pocketplaylab.com"],
 ["fwd", "\"94.66.255.106\""],
 ["dyno", "web.12"],
 ["connect", "12ms"],
 ["service", "21ms"],
 ["status", "200"],
 ["bytes", "78"]]

Нет, вы можете перебирать массив и создавать какой-то объект или хеш для работы.

scanresult.inject({}) do |obj, pair|
  obj[pair[0].to_sym] = pair[1]
  obj
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...