time_bandits 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/init.rb DELETED
@@ -1,12 +0,0 @@
1
- # this file gets only loaded for rails2
2
- require 'time_bandits'
3
- require 'time_bandits/monkey_patches/active_record_rails2'
4
- require 'time_bandits/monkey_patches/action_controller_rails2'
5
-
6
- ActionController::Base.send :include, ActionController::TimeBanditry
7
-
8
- TimeBandits::TimeConsumers::GarbageCollection.heap_dumps_enabled = %w(production development).include?(RAILS_ENV)
9
-
10
- # TimeBandits.add TimeBandits::TimeConsumers::Memcached if defined?(Memcached)
11
- # TimeBandits.add TimeBandits::TimeConsumers::GarbageCollection.instance if GC.respond_to? :enable_stats
12
- # TimeBandits.add TimeBandits::TimeConsumers::JMX.instance if defined? JRUBY_VERSION
@@ -1,162 +0,0 @@
1
- # =========================================================================================================
2
- # IMPORTANT: the plugin changes the ActionController#process method chain
3
- #
4
- # the original rails stack looks like this:
5
- #
6
- # ActionController::SessionManagement#process_with_session_management_support
7
- # ActionController::Filters#process_with_filters
8
- # ActionController::Base#process
9
- # ActionController::Caching::SqlCache#perform_action_with_caching
10
- # ActionController::Rescue#perform_action_with_rescue
11
- # *** ActionController::Benchmarking#perform_action_with_benchmark ***
12
- # ActionController::Filters#perform_action_with_filters (==> this runs the filters)
13
- # ActionController::Base#perform_action (==> run the action and eventually call render)
14
- # ActionController::Benchmarking#render_with_benchmark (==> this is where the rendering time gets computed)
15
- # ActionController::Base::render
16
- #
17
- # with the plugin installed, the stack looks like this:
18
- #
19
- # ActionController::SessionManagement#process_with_session_management_support
20
- # ActionController::Filters#process_with_filters
21
- # ActionController::Base#process
22
- # *** ActionController::Benchmarking#perform_action_with_time_bandits *** <=========== !!!!
23
- # ActionController::Caching::SqlCache#perform_action_with_caching
24
- # ActionController::Rescue#perform_action_with_rescue
25
- # ActionController::Filters#perform_action_with_filters (==> this runs the filters)
26
- # ActionController::Base#perform_action (==> run the action and eventually call render)
27
- # ActionController::Benchmarking#render_with_benchmark (==> this is where the rendering time gets computed)
28
- # ActionController::Base::render
29
- # =========================================================================================================
30
-
31
- module ActionController #:nodoc:
32
-
33
- class Base
34
- # this ugly hack is used to get the started_at and ip information into time bandits metrics
35
- def request_origin
36
- # this *needs* to be cached!
37
- # otherwise you'd get different results if calling it more than once
38
- @request_origin ||=
39
- begin
40
- remote_ip = request.remote_ip
41
- t = Time.now
42
- started_at = "#{t.to_s(:db)}.#{t.usec}"
43
- request.env["time_bandits.metrics"] = {:ip => remote_ip, :started_at => started_at}
44
- "#{remote_ip} at #{started_at}"
45
- end
46
- end
47
- end
48
-
49
- module TimeBanditry #:nodoc:
50
- def self.included(base)
51
- base.class_eval do
52
- alias_method_chain :perform_action, :time_bandits
53
- alias_method_chain :rescue_action, :time_bandits
54
-
55
- # if timebandits are used, the default benchmarking is
56
- # disabled. As alias_method_chain is unfriendly to extensions,
57
- # this is done by skipping perform_action_with_benchmarks by
58
- # calling perform_action_without_benchmarks at the appropriate
59
- # place.
60
- def perform_action_without_rescue
61
- perform_action_without_benchmark
62
- end
63
-
64
- alias_method :render, :render_with_benchmark
65
- end
66
-
67
- TimeBandits.add TimeBandits::TimeConsumers::Database.instance
68
- end
69
-
70
- def render_with_benchmark(options = nil, extra_options = {}, &block)
71
- if logger
72
- before_rendering = TimeBandits.consumed
73
-
74
- render_output = nil
75
- @view_runtime = Benchmark::realtime { render_output = render_without_benchmark(options, extra_options, &block) }
76
-
77
- other_time_consumed_during_rendering = TimeBandits.consumed - before_rendering
78
- @view_runtime -= other_time_consumed_during_rendering
79
-
80
- render_output
81
- else
82
- render_without_benchmark(options, extra_options, &block)
83
- end
84
- end
85
-
86
- def perform_action_with_time_bandits
87
- if logger
88
- TimeBandits.reset
89
-
90
- seconds = [ Benchmark::measure{ perform_action_without_time_bandits }.real, 0.0001 ].max
91
-
92
- # need to call this to compute DB time/calls
93
- TimeBandits.consumed
94
-
95
- log_message = "Completed in #{sprintf("%.3f", seconds * 1000)}ms"
96
-
97
- log_message << " ("
98
- log_message << view_runtime
99
- TimeBandits.time_bandits.each do |bandit|
100
- log_message << ", #{bandit.runtime}"
101
- end
102
- log_message << ")"
103
-
104
- log_message << " | #{response.status}"
105
- log_message << " [#{complete_request_uri rescue "unknown"}]"
106
-
107
- logger.info(log_message)
108
- response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
109
- merge_metrics(seconds)
110
- else
111
- perform_action_without_time_bandits
112
- end
113
- end
114
-
115
- def rescue_action_with_time_bandits(exception)
116
- # HACK!
117
- if logger && !caller.any?{|c| c =~ /perform_action_without_time_bandits/ }
118
- TimeBandits.reset
119
-
120
- seconds = [ Benchmark::measure{ rescue_action_without_time_bandits(exception) }.real, 0.0001 ].max
121
-
122
- # need to call this to compute DB time/calls
123
- TimeBandits.consumed
124
-
125
- log_message = "Completed in #{sprintf("%.3f", seconds * 1000)}ms"
126
-
127
- log_message << " ("
128
- log_message << view_runtime
129
- TimeBandits.time_bandits.each do |bandit|
130
- log_message << ", #{bandit.runtime}"
131
- end
132
- log_message << ")"
133
-
134
- log_message << " | #{response.status}"
135
- log_message << " [#{complete_request_uri rescue "unknown"}]"
136
-
137
- logger.info(log_message)
138
- response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
139
- merge_metrics(seconds)
140
- else
141
- rescue_action_without_time_bandits(exception)
142
- end
143
- end
144
-
145
- private
146
-
147
- def merge_metrics(total_time_seconds)
148
- basic_request_metrics = {
149
- :total_time => total_time_seconds * 1000,
150
- :view_time => (@view_runtime||0) * 1000,
151
- :code => response.status.to_i,
152
- :action => "#{self.class.name}\##{action_name}",
153
- }
154
- request.env["time_bandits.metrics"].merge!(TimeBandits.metrics).merge!(basic_request_metrics)
155
- end
156
-
157
- def view_runtime
158
- "View: %.3f" % ((@view_runtime||0) * 1000)
159
- end
160
-
161
- end
162
- end
@@ -1,86 +0,0 @@
1
- # this file monkey patches class ActiveRecord::ConnectionAdapters::AbstractAdapter
2
- # and the module module ActiveRecord::ConnectionAdapters::QueryCache
3
- # to count the number of sql statements being executed.
4
- # it needs to be adapted to each new rails version
5
-
6
- raise "AR abstract adapter monkey patch for custom benchmarking is not compatible with your rails version" unless
7
- %w(2.3.2 2.3.3 2.3.4 2.3.8 2.3.9 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14).include?(Rails::VERSION::STRING)
8
-
9
- module ActiveRecord
10
- module ConnectionAdapters
11
- class ConnectionPool
12
- attr_reader :connections
13
- end
14
-
15
- class AbstractAdapter
16
- attr_accessor :call_count, :query_cache_hits
17
-
18
- def initialize(connection, logger = nil) #:nodoc:
19
- @connection, @logger = connection, logger
20
- @runtime = 0
21
- @call_count = 0
22
- @last_verification = 0
23
- @query_cache_enabled = false
24
- @query_cache_hits = 0
25
- end
26
-
27
- def reset_call_count
28
- calls = @call_count
29
- @call_count = 0
30
- calls
31
- end
32
-
33
- def reset_query_cache_hits
34
- hits = @query_cache_hits
35
- @query_cache_hits = 0
36
- hits
37
- end
38
-
39
- protected
40
- def log(sql, name)
41
- if block_given?
42
- result = nil
43
- seconds = Benchmark.realtime { result = yield }
44
- @runtime += seconds
45
- @call_count += 1
46
- log_info(sql, name, seconds * 1000)
47
- result
48
- else
49
- log_info(sql, name, 0)
50
- nil
51
- end
52
- rescue Exception => e
53
- # Log message and raise exception.
54
- # Set last_verification to 0, so that connection gets verified
55
- # upon reentering the request loop
56
- @last_verification = 0
57
- message = "#{e.class.name}: #{e.message}: #{sql}"
58
- log_info(message, name, 0)
59
- raise ActiveRecord::StatementInvalid, message
60
- end
61
- end
62
-
63
- module QueryCache
64
- private
65
- def cache_sql(sql)
66
- result =
67
- if @query_cache.has_key?(sql)
68
- @query_cache_hits += 1
69
- log_info(sql, "CACHE", 0.0)
70
- @query_cache[sql]
71
- else
72
- @query_cache[sql] = yield
73
- end
74
-
75
- if Array === result
76
- result.collect { |row| row.dup }
77
- else
78
- result.duplicable? ? result.dup : result
79
- end
80
- rescue TypeError
81
- result
82
- end
83
- end
84
- end
85
- end
86
-
@@ -1,61 +0,0 @@
1
- # Database time consumer for Rails2. You need to add it via
2
- #
3
- # TimeBandits.add TimeBandits::TimeConsumers::Database.instance
4
- #
5
-
6
- module TimeBandits
7
- module TimeConsumers
8
- # provide a time consumer interface to ActiveRecord for perform_action_with_benchmark and render_with_benchmark
9
- class Database
10
- def initialize
11
- @consumed = 0.0
12
- @call_count = 0
13
- @query_cache_hits = 0
14
- end
15
- private :initialize
16
-
17
- def self.instance
18
- @instance ||= new
19
- end
20
-
21
- def reset
22
- reset_stats
23
- @call_count = 0
24
- @consumed = 0.0
25
- @query_cache_hits = 0
26
- end
27
-
28
- def consumed
29
- hits, calls, time = reset_stats
30
- @query_cache_hits += hits
31
- @call_count += calls
32
- @consumed += time
33
- end
34
-
35
- def runtime
36
- sprintf "DB: %.3f(%d,%d)", @consumed * 1000, @call_count, @query_cache_hits
37
- end
38
-
39
- def metrics
40
- {
41
- :db_calls => @call_count,
42
- :db_sql_query_cache_hits => @query_cache_hits,
43
- :db_time => @consumed * 1000
44
- }
45
- end
46
-
47
- private
48
- def all_connections
49
- ActiveRecord::Base.connection_handler.connection_pools.values.map{|pool| pool.connections}.flatten
50
- end
51
-
52
- def reset_stats
53
- connections = all_connections
54
- hits = connections.map{|c| c.reset_query_cache_hits}.sum
55
- calls = connections.map{|c| c.reset_call_count}.sum
56
- time = connections.map{|c| c.reset_runtime}.sum
57
- [hits, calls, time]
58
- end
59
- end
60
- end
61
- end