mirror of
https://github.com/discourse/discourse.git
synced 2024-12-16 14:13:48 +08:00
30990006a9
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
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)
|