| 1 |
require 'benchmark' |
|---|
| 2 |
|
|---|
| 3 |
module ActionController |
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
module Benchmarking |
|---|
| 7 |
def self.included(base) |
|---|
| 8 |
base.extend(ClassMethods) |
|---|
| 9 |
|
|---|
| 10 |
base.class_eval do |
|---|
| 11 |
alias_method_chain :perform_action, :benchmark |
|---|
| 12 |
alias_method_chain :render, :benchmark |
|---|
| 13 |
end |
|---|
| 14 |
end |
|---|
| 15 |
|
|---|
| 16 |
module ClassMethods |
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
def benchmark(title, log_level = Logger::DEBUG, use_silence = true) |
|---|
| 24 |
if logger && logger.level == log_level |
|---|
| 25 |
result = nil |
|---|
| 26 |
seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield } |
|---|
| 27 |
logger.add(log_level, "#{title} (#{'%.5f' % seconds})") |
|---|
| 28 |
result |
|---|
| 29 |
else |
|---|
| 30 |
yield |
|---|
| 31 |
end |
|---|
| 32 |
end |
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 |
def silence |
|---|
| 36 |
old_logger_level, logger.level = logger.level, Logger::ERROR if logger |
|---|
| 37 |
yield |
|---|
| 38 |
ensure |
|---|
| 39 |
logger.level = old_logger_level if logger |
|---|
| 40 |
end |
|---|
| 41 |
end |
|---|
| 42 |
|
|---|
| 43 |
def render_with_benchmark(options = nil, deprecated_status = nil, &block) |
|---|
| 44 |
unless logger |
|---|
| 45 |
render_without_benchmark(options, deprecated_status, &block) |
|---|
| 46 |
else |
|---|
| 47 |
db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? |
|---|
| 48 |
|
|---|
| 49 |
render_output = nil |
|---|
| 50 |
@rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, deprecated_status, &block) }.real |
|---|
| 51 |
|
|---|
| 52 |
if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? |
|---|
| 53 |
@db_rt_before_render = db_runtime |
|---|
| 54 |
@db_rt_after_render = ActiveRecord::Base.connection.reset_runtime |
|---|
| 55 |
@rendering_runtime -= @db_rt_after_render |
|---|
| 56 |
end |
|---|
| 57 |
|
|---|
| 58 |
render_output |
|---|
| 59 |
end |
|---|
| 60 |
end |
|---|
| 61 |
|
|---|
| 62 |
def perform_action_with_benchmark |
|---|
| 63 |
unless logger |
|---|
| 64 |
perform_action_without_benchmark |
|---|
| 65 |
else |
|---|
| 66 |
runtime = [Benchmark::measure{ perform_action_without_benchmark }.real, 0.0001].max |
|---|
| 67 |
log_message = "Completed in #{sprintf("%.5f", runtime)} (#{(1 / runtime).floor} reqs/sec)" |
|---|
| 68 |
log_message << rendering_runtime(runtime) if defined?(@rendering_runtime) |
|---|
| 69 |
log_message << active_record_runtime(runtime) if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected? |
|---|
| 70 |
log_message << " | #{headers["Status"]}" |
|---|
| 71 |
log_message << " [#{complete_request_uri rescue "unknown"}]" |
|---|
| 72 |
logger.info(log_message) |
|---|
| 73 |
end |
|---|
| 74 |
end |
|---|
| 75 |
|
|---|
| 76 |
private |
|---|
| 77 |
def rendering_runtime(runtime) |
|---|
| 78 |
percentage = @rendering_runtime * 100 / runtime |
|---|
| 79 |
" | Rendering: %.5f (%d%%)" % [@rendering_runtime, percentage.to_i] |
|---|
| 80 |
end |
|---|
| 81 |
|
|---|
| 82 |
def active_record_runtime(runtime) |
|---|
| 83 |
db_runtime = ActiveRecord::Base.connection.reset_runtime |
|---|
| 84 |
db_runtime += @db_rt_before_render if @db_rt_before_render |
|---|
| 85 |
db_runtime += @db_rt_after_render if @db_rt_after_render |
|---|
| 86 |
db_percentage = db_runtime * 100 / runtime |
|---|
| 87 |
" | DB: %.5f (%d%%)" % [db_runtime, db_percentage.to_i] |
|---|
| 88 |
end |
|---|
| 89 |
end |
|---|
| 90 |
end |
|---|