Created
July 23, 2013 14:33
-
-
Save thbounzer/6062820 to your computer and use it in GitHub Desktop.
Quick and dirty glassfish log parser and stat analyzer
This file contains hidden or 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 '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