Created
April 30, 2014 07:50
-
-
Save y13i/7144f5026989c5b8626d to your computer and use it in GitHub Desktop.
ApacheのアクセスログをJSONに変換する
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "json" | |
require "time" | |
require "optparse" | |
# require "pry" | |
# require "awesome_print" | |
ApacheLog = Struct.new :line do | |
IP_ADDR_PATTERN = %q((\d{1,3}\.){3}\d{1,3}) | |
FIELDS = %i(xforward_for ip remotelog remoteuser _time _request status bytes _referer _ua) | |
def xforward_for | |
@xforward_for ||= if line.match /\A[,\S]+,\s/ | |
line.match(/\A#{IP_ADDR_PATTERN},\s#{IP_ADDR_PATTERN}/)[0] | |
else | |
line.match(/\A#{IP_ADDR_PATTERN}/)[0] | |
end | |
end | |
def time | |
@time ||= Time.parse _time | |
end | |
def request | |
@request ||= _request[1..-2] | |
end | |
def bytes | |
@bytest ||= offseted_line_for(:bytes).match(/\A\S+/)[0].to_i | |
end | |
def to_h | |
FIELDS.inject Hash.new do |hash, field| | |
field = field[1..-1] if field.to_s.start_with? ?_ | |
hash.merge field => send(field) | |
end | |
end | |
def to_json | |
to_h.to_json | |
end | |
%i(ip remotelog remoteuser status).each do |field| | |
define_method field do | |
instance_variable_get "@#{field}".intern or instance_variable_set "@#{field}".intern, offseted_line_for(field).match(/\A\S+/)[0] | |
end | |
end | |
%i(request referer ua).each do |field| | |
alt = (?_ + field.to_s).intern | |
define_method field do | |
instance_variable_get "@#{field}".intern or instance_variable_set "@#{field}".intern, send(alt)[1..-2] | |
end | |
define_method alt do | |
offseted_line_for(alt).match(/\A\"[^\"]+\"/)[0] | |
end | |
private alt | |
end | |
private | |
def offseted_line_for field | |
index = FIELDS.index field | |
precedents = FIELDS[0..index - 1] | |
offset = precedents.map {|field| send field}.join(?").size + 1 | |
offseted_line offset | |
end | |
def offseted_line offset | |
line[offset..-1] | |
end | |
def _time | |
offseted_line_for(:_time).match(/\A\[[^\]]+\]/)[0].sub ?:, ?\s | |
end | |
end | |
options = OptionParser.new do |o| | |
o.banner = "Usage: #{File.basename __FILE__} [options]" | |
options = Hash.new | |
o.on("-i", "--input FILE") {|v| options[:input] = v} | |
o.on("-o", "--output FILE") {|v| options[:output] = v} | |
o.parse! ARGV | |
break options | |
end | |
File.open options[:input] do |logs| | |
File.open options[:output], ?w do |json_logs| | |
logs.each do |line| | |
log = ApacheLog.new line | |
puts log.to_h | |
json_logs.puts ApacheLog.new(line).to_json | |
end | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment