Froze rails gems
[depot.git] / vendor / rails / actionpack / lib / action_controller / benchmarking.rb
1 require 'benchmark'
2
3 module ActionController #:nodoc:
4 # The benchmarking module times the performance of actions and reports to the logger. If the Active Record
5 # package has been included, a separate timing section for database calls will be added as well.
6 module Benchmarking #:nodoc:
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 # Log and benchmark the workings of a single block and silence whatever logging that may have happened inside it
18 # (unless <tt>use_silence</tt> is set to false).
19 #
20 # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it
21 # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
22 # will only be conducted if the log level is low enough.
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} (#{('%.1f' % (seconds * 1000))}ms)")
28 result
29 else
30 yield
31 end
32 end
33
34 # Silences the logger for the duration of the block.
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 protected
44 def render_with_benchmark(options = nil, extra_options = {}, &block)
45 if logger
46 if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
47 db_runtime = ActiveRecord::Base.connection.reset_runtime
48 end
49
50 render_output = nil
51 @view_runtime = Benchmark::realtime { render_output = render_without_benchmark(options, extra_options, &block) }
52
53 if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
54 @db_rt_before_render = db_runtime
55 @db_rt_after_render = ActiveRecord::Base.connection.reset_runtime
56 @view_runtime -= @db_rt_after_render
57 end
58
59 render_output
60 else
61 render_without_benchmark(options, extra_options, &block)
62 end
63 end
64
65 private
66 def perform_action_with_benchmark
67 if logger
68 seconds = [ Benchmark::measure{ perform_action_without_benchmark }.real, 0.0001 ].max
69 logging_view = defined?(@view_runtime)
70 logging_active_record = Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
71
72 log_message = "Completed in #{sprintf("%.0f", seconds * 1000)}ms"
73
74 if logging_view || logging_active_record
75 log_message << " ("
76 log_message << view_runtime if logging_view
77
78 if logging_active_record
79 log_message << ", " if logging_view
80 log_message << active_record_runtime + ")"
81 else
82 ")"
83 end
84 end
85
86 log_message << " | #{headers["Status"]}"
87 log_message << " [#{complete_request_uri rescue "unknown"}]"
88
89 logger.info(log_message)
90 response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
91 else
92 perform_action_without_benchmark
93 end
94 end
95
96 def view_runtime
97 "View: %.0f" % (@view_runtime * 1000)
98 end
99
100 def active_record_runtime
101 db_runtime = ActiveRecord::Base.connection.reset_runtime
102 db_runtime += @db_rt_before_render if @db_rt_before_render
103 db_runtime += @db_rt_after_render if @db_rt_after_render
104 "DB: %.0f" % (db_runtime * 1000)
105 end
106 end
107 end