142 lines
3.1 KiB
Ruby
142 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'date'
|
|
require_relative '../lib/log_analyzer'
|
|
|
|
args = ARGV.dup
|
|
|
|
if args[0] == "--limit"
|
|
args.shift
|
|
limit = args.shift.to_i
|
|
end
|
|
|
|
filenames = args if args[0]
|
|
filenames ||= ["/var/log/nginx/access.log", "/var/log/nginx/access.log.1"]
|
|
|
|
analyzer = LogAnalyzer.analyze(filenames, limit: limit)
|
|
|
|
SPACER = "-" * 100
|
|
|
|
# don't feel like pulling in active support
|
|
def map_with_index(ary, &block)
|
|
idx = 0
|
|
ary.map do |item|
|
|
v = block.call(item, idx)
|
|
idx += 1
|
|
v
|
|
end
|
|
end
|
|
|
|
def top(cols, aggregator, count, aggregator_formatter = nil)
|
|
sorted = aggregator.top(count, aggregator_formatter)
|
|
|
|
col_just = []
|
|
|
|
col_widths = map_with_index(cols) do |name, idx|
|
|
max_width = name.length
|
|
|
|
if cols[idx].respond_to? :align
|
|
col_just[idx] = cols[idx].align
|
|
skip_just_detection = true
|
|
else
|
|
col_just[idx] = :ljust
|
|
end
|
|
|
|
sorted.each do |row|
|
|
col_just[idx] = :rjust unless (String === row[idx] || row[idx].nil?) && !skip_just_detection
|
|
row[idx] = '%.2f' % row[idx] if Float === row[idx]
|
|
row[idx] = row[idx].to_s
|
|
max_width = row[idx].length if row[idx].length > max_width
|
|
end
|
|
[max_width, 80].min
|
|
end
|
|
|
|
puts(map_with_index(cols) do |name, idx|
|
|
name.ljust(col_widths[idx])
|
|
end.join(" "))
|
|
|
|
puts(map_with_index(cols) do |name, idx|
|
|
("-" * name.length).ljust(col_widths[idx])
|
|
end.join(" "))
|
|
|
|
sorted.each do |raw_row|
|
|
|
|
rows = []
|
|
idx = 0
|
|
raw_row.each do |col|
|
|
j = 0
|
|
col.to_s.scan(/(.{1,80}($|\s)|.{1,80})/).each do |r|
|
|
rows[j] ||= []
|
|
rows[j][idx] = r[0]
|
|
j += 1
|
|
end
|
|
idx += 1
|
|
end
|
|
|
|
if rows.length > 1
|
|
puts
|
|
end
|
|
|
|
rows.each do |row|
|
|
cols.length.times do |i|
|
|
print row[i].to_s.public_send(col_just[i], col_widths[i])
|
|
print " "
|
|
end
|
|
puts
|
|
end
|
|
|
|
if rows.length > 1
|
|
puts
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
class Column < String
|
|
attr_accessor :align
|
|
|
|
def initialize(val, align)
|
|
super(val)
|
|
@align = align
|
|
end
|
|
end
|
|
|
|
puts
|
|
puts "Analyzed: #{analyzer.filenames.join(",")} on #{`hostname`}"
|
|
if limit
|
|
puts "Limited to #{DateTime.now - (limit.to_f / (60 * 24.0))} - #{DateTime.now}"
|
|
end
|
|
puts SPACER
|
|
puts "#{analyzer.from_time} - #{analyzer.to_time}"
|
|
puts SPACER
|
|
puts "Total Requests: #{analyzer.total_requests} ( MessageBus: #{analyzer.message_bus_requests} )"
|
|
puts SPACER
|
|
puts "Top 30 IPs by Server Load"
|
|
puts
|
|
top(["IP Address", "Duration", "Reqs"], analyzer.ip_to_rails_duration, 30)
|
|
puts SPACER
|
|
puts
|
|
puts "Top 30 users by Server Load"
|
|
puts
|
|
top(["Username", "Duration", "Reqs", "Routes"], analyzer.username_to_rails_duration, 30)
|
|
puts SPACER
|
|
puts
|
|
puts "Top 100 routes by Server Load"
|
|
puts
|
|
top(["Route", "Duration", "Reqs", Column.new("Mobile", :rjust)], analyzer.route_to_rails_duration, 100, lambda {
|
|
|hash, name, total|
|
|
"#{hash["mobile"] || 0} (#{"%.2f" % (((hash["mobile"] || 0) / (total + 0.0)) * 100)})%"}
|
|
)
|
|
puts SPACER
|
|
puts
|
|
puts "Top 30 urls by Server Load"
|
|
puts
|
|
top(["Url", "Duration", "Reqs"], analyzer.url_to_rails_duration, 30)
|
|
|
|
puts "(all durations in seconds)"
|
|
puts SPACER
|
|
puts
|
|
puts "Top 30 not found urls (404s)"
|
|
puts
|
|
top(["Url", "Count"], analyzer.status_404_to_count, 30)
|