Skip to content

Instantly share code, notes, and snippets.

@thbounzer
Created July 23, 2013 14:33
Show Gist options
  • Save thbounzer/6062820 to your computer and use it in GitHub Desktop.
Save thbounzer/6062820 to your computer and use it in GitHub Desktop.
Quick and dirty glassfish log parser and stat analyzer
require 'date'
require 'colorize'
# Parse glassfish default log files
# "X.X.X.X" "NULL-AUTH-USER" "22/Jul/2013:09:39:33 +0000" "POST /url/address/id HTTP/1.1" 200 7
# group things inside "" (?<=")(.*?)(?=")
# group things inside whitespaces (?<=\s)(.*?)(?=\s)
# last two digits parser
class LogLine
attr_accessor :ip,:timestamp,:action,:post,:reply_code,:reply_size,:user
def set_time timestring
@timestamp = DateTime.strptime(timestring,"%d/%b/%Y:%H:%M:%S %z")
end
end
def self.incr_hash_value hash,key
if hash.include? key
v = hash[key]
hash[key] = (v+1)
else
hash[key] = 1
end
end
def self.readfile filename
log_lines =[]
lines = 0
IO.foreach(filename) do |log_line|
line_sections_raw = log_line.scan(/(?<=")(.*?)(?=")/i)
reply_part = log_line.scan(/".*"\s{1}(\d*)\s{1}(\d*)/)
line_sections = []
line_sections_raw.each do |line_section|
if line_section.first.size >= 2
line_sections << line_section.first
end
end
ll = LogLine.new()
ll.ip = line_sections[0]
ll.user = line_sections[1]
ll.set_time line_sections[2]
ll.action = line_sections[3]
ll.reply_code = reply_part[0][0]
ll.reply_size = reply_part[0][1]
log_lines << ll
lines += 1
print "Reading line:#{lines} from #{filename}\r".white
end
puts
return log_lines
end
def self.hits_per_min log_lines
hash_ip_minutes = {}
log_lines.each do |log_line|
key = log_line.timestamp.strftime("%d%m%Y%H%M")
self.incr_hash_value hash_ip_minutes,key
end
per_min_hits = []
hash_ip_minutes.each_key do |key|
tstamp = DateTime.strptime(key,"%d%m%Y%H%M")
hits = hash_ip_minutes[key]
str = "TIME: #{tstamp}".yellow
str += " HITS: #{hits}".red
per_min_hits << hits
puts str
end
size = per_min_hits.size
avg_hits = per_min_hits.inject{ |sum, el| sum + el }.to_f / size
puts "\n >>> AVG HITS x MINUTE: #{avg_hits.round} <<<".white
hash_ip_minutes = hash_ip_minutes.sort_by{|k,v| v.to_i}.reverse
puts "\n*** TOP 10 HITTED MINUTES***".yellow
if hash_ip_minutes.size > 10
10.times do |i|
time_hits = hash_ip_minutes[i]
time = DateTime.strptime(time_hits[0],"%d%m%Y%H%M")
msg = "#{i+1} -> TIME: #{time} ".white
msg += "HITS: #{time_hits[1]}".yellow
puts msg
end
else
i = 1
hash_ip_minutes.each do |time_hit|
time = DateTime.strptime(time_hits[0],"%d%m%Y%H%M")
msg = "#{i} -> TIME: #{time} ".white
msg += "HITS: #{time_hit[1]}".yellow
i += 1
puts msg
end
end
end
def self.hits_per_ip log_lines
hash_ip = {}
log_lines.each do |log_line|
key = log_line.ip
self.incr_hash_value hash_ip,key
end
hash_ip.each_key do |key|
hits = hash_ip[key]
str = "IP: #{key}".yellow
str += " HITS: #{hits}".red
puts str
end
end
def self.reply_code_analysis log_lines
bad_replies = {}
good_replies = {}
log_lines.each do |ll|
key = ll.ip
if ll.reply_code == "200"
self.incr_hash_value good_replies,key
else
self.incr_hash_value bad_replies,key
end
end
t_good = 0
t_bad = 0
bad_replies.each_key do |key|
t_bad += bad_replies[key]
end
good_replies.each_key do |key|
t_good += good_replies[key]
end
total_reqs = t_good+t_bad
per_good = (t_good*100.0)/total_reqs
per_bad = (t_bad*100.0)/total_reqs
msg = "TOTAL KO: #{t_bad}\t".red
msg += "TOTAL OK: #{t_good}\t".green
msg += "PERC KO: #{per_bad}%".yellow
bad_replies = bad_replies.sort_by{|k,v| v.to_i}
good_replies = good_replies.sort_by{|k,v| v.to_i}
bad_replies = bad_replies.reverse
good_replies = good_replies.reverse
puts "** TOP TEN OK CLIENTS: **".green
puts
if good_replies.size <= 10
i = 1
good_replies.each do |rep|
puts "#{i} -> IP: #{rep[0]} REQS: #{rep[1]}".green
end
else
10.times do |x|
rep = good_replies[x]
puts "#{x+1} -> IP: #{rep[0]} OK REQS: #{rep[1]}".green
end
end
puts
puts "** TOP TEN KO CLIENTS: **".red
puts
if bad_replies.size <= 10
i = 1
bad_replies.each do |rep|
puts "#{i} -> IP: #{rep[0]} REQS: #{rep[1]}".red
end
else
10.times do |x|
rep = bad_replies[x]
puts "#{x+1} -> IP: #{rep[0]} REQS: #{rep[1]}".red
end
end
puts
puts msg
end
if ARGV.size == 0
puts "No arguments, dude? Are you fucking crazy?! C'mon!".upcase.red
puts "I need an access filename to work.".white
exit
end
@columns = `/usr/bin/env tput cols`.to_i
breakline = "=".green*@columns
filename = ARGV.first
#while true
log_lines = self.readfile filename
puts "HITS per MINUTE".blue
puts breakline
self.hits_per_min log_lines
puts
#puts "IPs and HITS"
#puts breakline
#self.hits_per_ip log_lines
puts "REPLIES".blue
puts breakline
self.reply_code_analysis log_lines
#sleep 60
#end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment