Skip to content

Instantly share code, notes, and snippets.

@y13i
Created April 30, 2014 07:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save y13i/7144f5026989c5b8626d to your computer and use it in GitHub Desktop.
Save y13i/7144f5026989c5b8626d to your computer and use it in GitHub Desktop.
ApacheのアクセスログをJSONに変換する
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