discourse/plugins/discourse-nginx-performance-report/script/nginx_analyze.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

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)