mini-mini-profiler 0.1

Sign up to get free protection for your applications and to get access to all the features.
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