time_bandits 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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