mini-mini-profiler 0.1

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.
Files changed (39) hide show
  1. data/Ruby/CHANGELOG +135 -0
  2. data/Ruby/README.md +161 -0
  3. data/Ruby/lib/html/flamegraph.html +325 -0
  4. data/Ruby/lib/html/includes.css +451 -0
  5. data/Ruby/lib/html/includes.js +945 -0
  6. data/Ruby/lib/html/includes.less +471 -0
  7. data/Ruby/lib/html/includes.tmpl +108 -0
  8. data/Ruby/lib/html/jquery.1.7.1.js +4 -0
  9. data/Ruby/lib/html/jquery.tmpl.js +486 -0
  10. data/Ruby/lib/html/list.css +9 -0
  11. data/Ruby/lib/html/list.js +38 -0
  12. data/Ruby/lib/html/list.tmpl +34 -0
  13. data/Ruby/lib/html/profile_handler.js +1 -0
  14. data/Ruby/lib/html/share.html +11 -0
  15. data/Ruby/lib/mini_profiler/client_settings.rb +65 -0
  16. data/Ruby/lib/mini_profiler/client_timer_struct.rb +78 -0
  17. data/Ruby/lib/mini_profiler/config.rb +57 -0
  18. data/Ruby/lib/mini_profiler/context.rb +11 -0
  19. data/Ruby/lib/mini_profiler/custom_timer_struct.rb +22 -0
  20. data/Ruby/lib/mini_profiler/flame_graph.rb +54 -0
  21. data/Ruby/lib/mini_profiler/gc_profiler.rb +107 -0
  22. data/Ruby/lib/mini_profiler/page_timer_struct.rb +58 -0
  23. data/Ruby/lib/mini_profiler/profiler.rb +544 -0
  24. data/Ruby/lib/mini_profiler/profiling_methods.rb +133 -0
  25. data/Ruby/lib/mini_profiler/request_timer_struct.rb +115 -0
  26. data/Ruby/lib/mini_profiler/sql_timer_struct.rb +58 -0
  27. data/Ruby/lib/mini_profiler/storage/abstract_store.rb +31 -0
  28. data/Ruby/lib/mini_profiler/storage/file_store.rb +111 -0
  29. data/Ruby/lib/mini_profiler/storage/memcache_store.rb +53 -0
  30. data/Ruby/lib/mini_profiler/storage/memory_store.rb +65 -0
  31. data/Ruby/lib/mini_profiler/storage/redis_store.rb +54 -0
  32. data/Ruby/lib/mini_profiler/timer_struct.rb +33 -0
  33. data/Ruby/lib/mini_profiler/version.rb +5 -0
  34. data/Ruby/lib/mini_profiler_rails/railtie.rb +107 -0
  35. data/Ruby/lib/patches/net_patches.rb +14 -0
  36. data/Ruby/lib/patches/sql_patches.rb +272 -0
  37. data/Ruby/lib/rack-mini-profiler.rb +7 -0
  38. data/mini-mini-profiler.gemspec +26 -0
  39. metadata +154 -0
@@ -0,0 +1,53 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ class MemcacheStore < AbstractStore
4
+
5
+ EXPIRES_IN_SECONDS = 60 * 60 * 24
6
+ MAX_RETRIES = 10
7
+
8
+ def initialize(args = nil)
9
+ require 'dalli' unless defined? Dalli
10
+ args ||= {}
11
+ @prefix = args[:prefix] || "MPMemcacheStore"
12
+ @client = args[:client] || Dalli::Client.new
13
+ @expires_in_seconds = args[:expires_in] || EXPIRES_IN_SECONDS
14
+ end
15
+
16
+ def save(page_struct)
17
+ @client.set("#{@prefix}#{page_struct['Id']}", Marshal::dump(page_struct), @expires_in_seconds)
18
+ end
19
+
20
+ def load(id)
21
+ raw = @client.get("#{@prefix}#{id}")
22
+ if raw
23
+ Marshal::load raw
24
+ end
25
+ end
26
+
27
+ def set_unviewed(user, id)
28
+ @client.add("#{@prefix}-#{user}-v", [], @expires_in_seconds)
29
+ MAX_RETRIES.times do
30
+ break if @client.cas("#{@prefix}-#{user}-v", @expires_in_seconds) do |ids|
31
+ ids << id unless ids.include?(id)
32
+ ids
33
+ end
34
+ end
35
+ end
36
+
37
+ def set_viewed(user, id)
38
+ @client.add("#{@prefix}-#{user}-v", [], @expires_in_seconds)
39
+ MAX_RETRIES.times do
40
+ break if @client.cas("#{@prefix}-#{user}-v", @expires_in_seconds) do |ids|
41
+ ids.delete id
42
+ ids
43
+ end
44
+ end
45
+ end
46
+
47
+ def get_unviewed_ids(user)
48
+ @client.get("#{@prefix}-#{user}-v") || []
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,65 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ class MemoryStore < AbstractStore
4
+
5
+ EXPIRES_IN_SECONDS = 60 * 60 * 24
6
+
7
+ def initialize(args = nil)
8
+ args ||= {}
9
+ @expires_in_seconds = args[:expires_in] || EXPIRES_IN_SECONDS
10
+ @timer_struct_lock = Mutex.new
11
+ @timer_struct_cache = {}
12
+ @user_view_lock = Mutex.new
13
+ @user_view_cache = {}
14
+
15
+ # TODO: fix it to use weak ref, trouble is may be broken in 1.9 so need to use the 'ref' gem
16
+ me = self
17
+ Thread.new do
18
+ while true do
19
+ me.cleanup_cache
20
+ sleep(3600)
21
+ end
22
+ end
23
+ end
24
+
25
+ def save(page_struct)
26
+ @timer_struct_lock.synchronize {
27
+ @timer_struct_cache[page_struct['Id']] = page_struct
28
+ }
29
+ end
30
+
31
+ def load(id)
32
+ @timer_struct_lock.synchronize {
33
+ @timer_struct_cache[id]
34
+ }
35
+ end
36
+
37
+ def set_unviewed(user, id)
38
+ @user_view_lock.synchronize {
39
+ @user_view_cache[user] ||= []
40
+ @user_view_cache[user] << id
41
+ }
42
+ end
43
+
44
+ def set_viewed(user, id)
45
+ @user_view_lock.synchronize {
46
+ @user_view_cache[user] ||= []
47
+ @user_view_cache[user].delete(id)
48
+ }
49
+ end
50
+
51
+ def get_unviewed_ids(user)
52
+ @user_view_lock.synchronize {
53
+ @user_view_cache[user]
54
+ }
55
+ end
56
+
57
+ def cleanup_cache
58
+ expire_older_than = ((Time.now.to_f - @expires_in_seconds) * 1000).to_i
59
+ @timer_struct_lock.synchronize {
60
+ @timer_struct_cache.delete_if { |k, v| v['Started'] < expire_older_than }
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,54 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ class RedisStore < AbstractStore
4
+
5
+ EXPIRES_IN_SECONDS = 60 * 60 * 24
6
+
7
+ def initialize(args = nil)
8
+ @args = args || {}
9
+ @prefix = @args.delete(:prefix) || 'MPRedisStore'
10
+ @redis_connection = @args.delete(:connection)
11
+ @expires_in_seconds = @args.delete(:expires_in) || EXPIRES_IN_SECONDS
12
+ end
13
+
14
+ def save(page_struct)
15
+ redis.setex "#{@prefix}#{page_struct['Id']}", @expires_in_seconds, Marshal::dump(page_struct)
16
+ end
17
+
18
+ def load(id)
19
+ raw = redis.get "#{@prefix}#{id}"
20
+ if raw
21
+ Marshal::load raw
22
+ end
23
+ end
24
+
25
+ def set_unviewed(user, id)
26
+ redis.sadd "#{@prefix}-#{user}-v", id
27
+ end
28
+
29
+ def set_viewed(user, id)
30
+ redis.srem "#{@prefix}-#{user}-v", id
31
+ end
32
+
33
+ def get_unviewed_ids(user)
34
+ redis.smembers "#{@prefix}-#{user}-v"
35
+ end
36
+
37
+ def diagnostics(user)
38
+ "Redis prefix: #{@prefix}
39
+ Redis location: #{redis.client.host}:#{redis.client.port} db: #{redis.client.db}
40
+ unviewed_ids: #{get_unviewed_ids(user)}
41
+ "
42
+ end
43
+
44
+ private
45
+
46
+ def redis
47
+ return @redis_connection if @redis_connection
48
+ require 'redis' unless defined? Redis
49
+ @redis_connection ||= Redis.new @args
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ module Rack
2
+ class MiniProfiler
3
+
4
+ # A base class for timing structures
5
+ class TimerStruct
6
+
7
+ def initialize(attrs={})
8
+ @attributes = attrs
9
+ end
10
+
11
+ def attributes
12
+ @attributes ||= {}
13
+ end
14
+
15
+ def [](name)
16
+ attributes[name]
17
+ end
18
+
19
+ def []=(name, val)
20
+ attributes[name] = val
21
+ self
22
+ end
23
+
24
+ def to_json(*a)
25
+ # this does could take in an option hash, but the only interesting there is max_nesting.
26
+ # if this becomes an option we could increase
27
+ ::JSON.generate( @attributes, :max_nesting => 100 )
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ VERSION = '6dd090de49f69e3ca9f7dcb5e7090010'.freeze
4
+ end
5
+ end
@@ -0,0 +1,107 @@
1
+ require 'fileutils'
2
+
3
+ module Rack::MiniProfilerRails
4
+
5
+ # call direct if needed to do a defer init
6
+ def self.initialize!(app)
7
+ c = Rack::MiniProfiler.config
8
+
9
+ # By default, only show the MiniProfiler in development mode, in production allow profiling if post_authorize_cb is set
10
+ c.pre_authorize_cb = lambda { |env|
11
+ !Rails.env.test?
12
+ }
13
+
14
+ c.skip_paths ||= []
15
+
16
+ if Rails.env.development?
17
+ c.skip_paths << "/assets/"
18
+ c.skip_schema_queries = true
19
+ end
20
+
21
+ if Rails.env.production?
22
+ c.authorization_mode = :whitelist
23
+ end
24
+
25
+ # The file store is just so much less flaky
26
+ tmp = Rails.root.to_s + "/tmp/miniprofiler"
27
+ FileUtils.mkdir_p(tmp) unless File.exists?(tmp)
28
+
29
+ c.storage_options = {:path => tmp}
30
+ c.storage = Rack::MiniProfiler::FileStore
31
+
32
+ # Quiet the SQL stack traces
33
+ c.backtrace_remove = Rails.root.to_s + "/"
34
+ c.backtrace_includes = [/^\/?(app|config|lib|test)/]
35
+ c.skip_schema_queries = Rails.env != 'production'
36
+
37
+ # Install the Middleware
38
+ app.middleware.insert(0, Rack::MiniProfiler)
39
+
40
+ # Attach to various Rails methods
41
+ ::Rack::MiniProfiler.profile_method(ActionController::Base, :process) {|action| "Controller: #{self.class.name} Action: #{action}"}
42
+ ::Rack::MiniProfiler.profile_method(ActionView::Template, :render) {|x,y| "View: #{@virtual_path}"}
43
+
44
+ # preload all model classes
45
+ Dir.glob("#{Rails.root}/app/models/**/*.rb").map{|file| file.match(/([^\/]+).rb/)[1].camelize.constantize}
46
+
47
+ ActiveRecord::Base.subclasses.each do |model_class|
48
+ (model_class.instance_methods - ActiveRecord::Base.instance_methods + [:save, :update_attributes, :initialize]).each do |method|
49
+ # ::Rack::MiniProfiler.profile_method(model_class, method){ |*args| "Model: #{self.class.name} Method: #{method}" }
50
+ unless method.to_s =~ /^_.*/
51
+ ::Rack::MiniProfiler.profile_method(model_class, method){ |*args| "Model: #{ self.class.name } Method: #{ method }" }
52
+ end
53
+ end
54
+
55
+ ((model_class.public_methods - ActiveRecord::Base.public_methods) + [:find, :where, :order, :all]).each do |method|
56
+ unless method.to_s =~ /^_.*/
57
+ ::Rack::MiniProfiler.profile_method(model_class, method, true){ |*args| "Model: #{ self.name } Method: #{ method }" }
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ class Railtie < ::Rails::Railtie
64
+
65
+ initializer "rack_mini_profiler.configure_rails_initialization" do |app|
66
+ Rack::MiniProfilerRails.initialize!(app)
67
+ end
68
+
69
+ # TODO: Implement something better here
70
+ # config.after_initialize do
71
+ #
72
+ # class ::ActionView::Helpers::AssetTagHelper::JavascriptIncludeTag
73
+ # alias_method :asset_tag_orig, :asset_tag
74
+ # def asset_tag(source,options)
75
+ # current = Rack::MiniProfiler.current
76
+ # return asset_tag_orig(source,options) unless current
77
+ # wrapped = ""
78
+ # unless current.mpt_init
79
+ # current.mpt_init = true
80
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
81
+ # end
82
+ # name = source.split('/')[-1]
83
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
84
+ # wrapped
85
+ # end
86
+ # end
87
+
88
+ # class ::ActionView::Helpers::AssetTagHelper::StylesheetIncludeTag
89
+ # alias_method :asset_tag_orig, :asset_tag
90
+ # def asset_tag(source,options)
91
+ # current = Rack::MiniProfiler.current
92
+ # return asset_tag_orig(source,options) unless current
93
+ # wrapped = ""
94
+ # unless current.mpt_init
95
+ # current.mpt_init = true
96
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
97
+ # end
98
+ # name = source.split('/')[-1]
99
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
100
+ # wrapped
101
+ # end
102
+ # end
103
+
104
+ # end
105
+
106
+ end
107
+ end
@@ -0,0 +1,14 @@
1
+ if (defined?(Net) && defined?(Net::HTTP))
2
+
3
+ Net::HTTP.class_eval do
4
+ def request_with_mini_profiler(*args, &block)
5
+ request = args[0]
6
+ Rack::MiniProfiler.step("Net::HTTP #{request.method} #{request.path}") do
7
+ request_without_mini_profiler(*args, &block)
8
+ end
9
+ end
10
+ alias request_without_mini_profiler request
11
+ alias request request_with_mini_profiler
12
+ end
13
+
14
+ end
@@ -0,0 +1,272 @@
1
+ class SqlPatches
2
+
3
+ def self.patched?
4
+ @patched
5
+ end
6
+
7
+ def self.patched=(val)
8
+ @patched = val
9
+ end
10
+
11
+ def self.class_exists?(name)
12
+ eval(name + ".class").to_s.eql?('Class')
13
+ rescue NameError
14
+ false
15
+ end
16
+
17
+ def self.module_exists?(name)
18
+ eval(name + ".class").to_s.eql?('Module')
19
+ rescue NameError
20
+ false
21
+ end
22
+ end
23
+
24
+ # The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
25
+ if SqlPatches.class_exists? "Mysql2::Client"
26
+
27
+ class Mysql2::Result
28
+ alias_method :each_without_profiling, :each
29
+ def each(*args, &blk)
30
+ return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
31
+
32
+ start = Time.now
33
+ result = each_without_profiling(*args,&blk)
34
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
35
+
36
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
37
+ result
38
+ end
39
+ end
40
+
41
+ class Mysql2::Client
42
+ alias_method :query_without_profiling, :query
43
+ def query(*args,&blk)
44
+ current = ::Rack::MiniProfiler.current
45
+ return query_without_profiling(*args,&blk) unless current && current.measure
46
+
47
+ start = Time.now
48
+ result = query_without_profiling(*args,&blk)
49
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
50
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
51
+
52
+ result
53
+
54
+ end
55
+ end
56
+
57
+ SqlPatches.patched = true
58
+ end
59
+
60
+
61
+ # PG patches, keep in mind exec and async_exec have a exec{|r| } semantics that is yet to be implemented
62
+ if SqlPatches.class_exists? "PG::Result"
63
+
64
+ class PG::Result
65
+ alias_method :each_without_profiling, :each
66
+ alias_method :values_without_profiling, :values
67
+
68
+ def values(*args, &blk)
69
+ return values_without_profiling(*args, &blk) unless @miniprofiler_sql_id
70
+
71
+ start = Time.now
72
+ result = values_without_profiling(*args,&blk)
73
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
74
+
75
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
76
+ result
77
+ end
78
+
79
+ def each(*args, &blk)
80
+ return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
81
+
82
+ start = Time.now
83
+ result = each_without_profiling(*args,&blk)
84
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
85
+
86
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
87
+ result
88
+ end
89
+ end
90
+
91
+ class PG::Connection
92
+ alias_method :exec_without_profiling, :exec
93
+ alias_method :async_exec_without_profiling, :async_exec
94
+ alias_method :exec_prepared_without_profiling, :exec_prepared
95
+ alias_method :send_query_prepared_without_profiling, :send_query_prepared
96
+ alias_method :prepare_without_profiling, :prepare
97
+
98
+ def prepare(*args,&blk)
99
+ # we have no choice but to do this here,
100
+ # if we do the check for profiling first, our cache may miss critical stuff
101
+
102
+ @prepare_map ||= {}
103
+ @prepare_map[args[0]] = args[1]
104
+ # dont leak more than 10k ever
105
+ @prepare_map = {} if @prepare_map.length > 1000
106
+
107
+ current = ::Rack::MiniProfiler.current
108
+ return prepare_without_profiling(*args,&blk) unless current && current.measure
109
+
110
+ prepare_without_profiling(*args,&blk)
111
+ end
112
+
113
+ def exec(*args,&blk)
114
+ current = ::Rack::MiniProfiler.current
115
+ return exec_without_profiling(*args,&blk) unless current && current.measure
116
+
117
+ start = Time.now
118
+ result = exec_without_profiling(*args,&blk)
119
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
120
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
121
+
122
+ result
123
+ end
124
+
125
+ def exec_prepared(*args,&blk)
126
+ current = ::Rack::MiniProfiler.current
127
+ return exec_prepared_without_profiling(*args,&blk) unless current && current.measure
128
+
129
+ start = Time.now
130
+ result = exec_prepared_without_profiling(*args,&blk)
131
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
132
+ mapped = args[0]
133
+ mapped = @prepare_map[mapped] || args[0] if @prepare_map
134
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(mapped, elapsed_time))
135
+
136
+ result
137
+ end
138
+
139
+ def send_query_prepared(*args,&blk)
140
+ current = ::Rack::MiniProfiler.current
141
+ return send_query_prepared_without_profiling(*args,&blk) unless current && current.measure
142
+
143
+ start = Time.now
144
+ result = send_query_prepared_without_profiling(*args,&blk)
145
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
146
+ mapped = args[0]
147
+ mapped = @prepare_map[mapped] || args[0] if @prepare_map
148
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(mapped, elapsed_time))
149
+
150
+ result
151
+ end
152
+
153
+ def async_exec(*args,&blk)
154
+ current = ::Rack::MiniProfiler.current
155
+ return exec_without_profiling(*args,&blk) unless current && current.measure
156
+
157
+ start = Time.now
158
+ result = exec_without_profiling(*args,&blk)
159
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
160
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
161
+
162
+ result
163
+ end
164
+
165
+ alias_method :query, :exec
166
+ end
167
+
168
+ SqlPatches.patched = true
169
+ end
170
+
171
+
172
+ # Mongoid 3 patches
173
+ if SqlPatches.class_exists?("Moped::Node")
174
+ class Moped::Node
175
+ alias_method :process_without_profiling, :process
176
+ def process(*args,&blk)
177
+ current = ::Rack::MiniProfiler.current
178
+ return process_without_profiling(*args,&blk) unless current && current.measure
179
+
180
+ start = Time.now
181
+ result = process_without_profiling(*args,&blk)
182
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
183
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0].log_inspect, elapsed_time))
184
+
185
+ result
186
+ end
187
+ end
188
+ end
189
+
190
+ if SqlPatches.class_exists?("RSolr::Connection") && RSolr::VERSION[0] != "0" # requires at least v1.0.0
191
+ class RSolr::Connection
192
+ alias_method :execute_without_profiling, :execute
193
+ def execute_with_profiling(client, request_context)
194
+ current = ::Rack::MiniProfiler.current
195
+ return execute_without_profiling(client, request_context) unless current && current.measure
196
+
197
+ start = Time.now
198
+ result = execute_without_profiling(client, request_context)
199
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
200
+
201
+ data = "#{request_context[:method].upcase} #{request_context[:uri]}"
202
+ if request_context[:method] == :post and request_context[:data]
203
+ data << "\n#{Rack::Utils.unescape(request_context[:data])}"
204
+ end
205
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(data, elapsed_time))
206
+
207
+ result
208
+ end
209
+ alias_method :execute, :execute_with_profiling
210
+ end
211
+ end
212
+
213
+
214
+ # Fallback for sequel
215
+ if SqlPatches.class_exists?("Sequel::Database") && !SqlPatches.patched?
216
+ module Sequel
217
+ class Database
218
+ alias_method :log_duration_original, :log_duration
219
+ def log_duration(duration, message)
220
+ ::Rack::MiniProfiler.record_sql(message, duration)
221
+ log_duration_original(duration, message)
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+
228
+ ## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
229
+ ## fallback for alls sorts of weird dbs
230
+ if SqlPatches.module_exists?('ActiveRecord') && !SqlPatches.patched?
231
+ module Rack
232
+ class MiniProfiler
233
+ module ActiveRecordInstrumentation
234
+ def self.included(instrumented_class)
235
+ instrumented_class.class_eval do
236
+ unless instrumented_class.method_defined?(:log_without_miniprofiler)
237
+ alias_method :log_without_miniprofiler, :log
238
+ alias_method :log, :log_with_miniprofiler
239
+ protected :log
240
+ end
241
+ end
242
+ end
243
+
244
+ def log_with_miniprofiler(*args, &block)
245
+ current = ::Rack::MiniProfiler.current
246
+ return log_without_miniprofiler(*args, &block) unless current && current.measure
247
+
248
+ sql, name, binds = args
249
+ t0 = Time.now
250
+ rval = log_without_miniprofiler(*args, &block)
251
+
252
+ # Don't log schema queries if the option is set
253
+ return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
254
+
255
+ elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
256
+ Rack::MiniProfiler.record_sql(sql, elapsed_time)
257
+ rval
258
+ end
259
+ end
260
+ end
261
+
262
+ def self.insert_instrumentation
263
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
264
+ include ::Rack::MiniProfiler::ActiveRecordInstrumentation
265
+ end
266
+ end
267
+
268
+ if defined?(::Rails) && !SqlPatches.patched?
269
+ insert_instrumentation
270
+ end
271
+ end
272
+ end