解析ruby上的日志文件

时间:2018-05-01 10:02:02

标签: ruby regex parsing

我需要你的帮助。我在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
  • 我需要从文件中获取:
    • URLS(例如:/ api / users / 1686318645 / get_friends_progress,/ api / users / 1145906359);
    • 连接时间+服务时间(例如:connect = 2ms service = 55ms);
    • 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 :(得分:3)

好的,要写你的正则表达式,你需要的是找到所有这些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

答案 1 :(得分:1)

我不是正则表达式专家,也知道下面的代码闻起来 - ))但你可以把它作为一个起点。

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

Link to repl

Edit suggested by Wiktor Stribiżew,显然更简洁,更好。我更喜欢它比我的。为历史原因保留上述代码 - ))

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

答案 2 :(得分:0)

解决方案是使用named capturesString#match(/dyno=(?<dyno>\S+)/)将捕获dyno字符串。您可以展开正则表达式以匹配更多。

你可以在这里举例说明: http://rubular.com/r/4XcovTiqh3 - 通过一些试验和错误,您可以找到正确的正则表达式

添加代码后更新:

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

将返回一个MatchData对象,您可以从中获取匹配的dyno:

parser['dyno']

一旦你完成正则表达式以从每一行捕获更多内容,并且如果你使用Ruby 2.4或更高版本,你也可以使用named_captures来获得所有匹配组的漂亮哈希

了解它的工作原理:https://repl.it/repls/SpectacularBewitchedPolygon