Search code examples
rubyreadline

Return line number with Ruby readline


searching for a simple ruby/bash solution to investigate a logfile, for example an apache access log.

my log contains lines with beginning string "authorization:"

goal of the script is to return the whole next but one line after this match, which contains the string "x-forwarded-for".

host: 10.127.5.12:8088^M
accept: */*^M
date: Wed, 19 Apr 2019 22:12:36 GMT^M
authorization: FOP ASC-amsterdam-b2c-v7:fkj9234f$t34g34rf=^M
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0)
x-forwarded-for: 195.99.33.222, 10.127.72.254^M
x-forwarded-host: my.luckyhost.com^M
x-forwarded-server: server.luckyhost.de^M
connection: Keep-Alive^M
^M

My question relates to the if condition. How can I get the line number/caller from readline and in second step return the whole next line with x-forwarded-for.

file = File.open(args[:apache_access_log], "r")
log_snapshot = file.readlines
file.close

log_snapshot.reverse_each do |line|
  if line.include? "authorization:"
    puts line

  end
end

Solution

  • Maybe something along these lines:

    log_snapshot.each_with_index.reverse_each do |line, n|
      case (line)
      when /authorization:/
        puts '%d: %s' % [ n + 1, line ]
      end
    end
    

    Where each_with_index is used to generate 0-indexed line numbers. I've switched to a case style so you can have more flexibility in matching different conditions. For example, you can add the /i flag to do a case-insensitive match really easily or add \A at the beginning to anchor it at the beginning of the string.

    Another thing to consider using the block method for File.open, like this:

    File.open(args[:apache_access_log], "r") do |f|
      f.readlines.each_with_index.reverse_each do |line, n|
        # ...
      end
    end
    

    Where that eliminates the need for an explicit close call. The end of the block closes it for you automatically.