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.
- data/Ruby/CHANGELOG +135 -0
- data/Ruby/README.md +161 -0
- data/Ruby/lib/html/flamegraph.html +325 -0
- data/Ruby/lib/html/includes.css +451 -0
- data/Ruby/lib/html/includes.js +945 -0
- data/Ruby/lib/html/includes.less +471 -0
- data/Ruby/lib/html/includes.tmpl +108 -0
- data/Ruby/lib/html/jquery.1.7.1.js +4 -0
- data/Ruby/lib/html/jquery.tmpl.js +486 -0
- data/Ruby/lib/html/list.css +9 -0
- data/Ruby/lib/html/list.js +38 -0
- data/Ruby/lib/html/list.tmpl +34 -0
- data/Ruby/lib/html/profile_handler.js +1 -0
- data/Ruby/lib/html/share.html +11 -0
- data/Ruby/lib/mini_profiler/client_settings.rb +65 -0
- data/Ruby/lib/mini_profiler/client_timer_struct.rb +78 -0
- data/Ruby/lib/mini_profiler/config.rb +57 -0
- data/Ruby/lib/mini_profiler/context.rb +11 -0
- data/Ruby/lib/mini_profiler/custom_timer_struct.rb +22 -0
- data/Ruby/lib/mini_profiler/flame_graph.rb +54 -0
- data/Ruby/lib/mini_profiler/gc_profiler.rb +107 -0
- data/Ruby/lib/mini_profiler/page_timer_struct.rb +58 -0
- data/Ruby/lib/mini_profiler/profiler.rb +544 -0
- data/Ruby/lib/mini_profiler/profiling_methods.rb +133 -0
- data/Ruby/lib/mini_profiler/request_timer_struct.rb +115 -0
- data/Ruby/lib/mini_profiler/sql_timer_struct.rb +58 -0
- data/Ruby/lib/mini_profiler/storage/abstract_store.rb +31 -0
- data/Ruby/lib/mini_profiler/storage/file_store.rb +111 -0
- data/Ruby/lib/mini_profiler/storage/memcache_store.rb +53 -0
- data/Ruby/lib/mini_profiler/storage/memory_store.rb +65 -0
- data/Ruby/lib/mini_profiler/storage/redis_store.rb +54 -0
- data/Ruby/lib/mini_profiler/timer_struct.rb +33 -0
- data/Ruby/lib/mini_profiler/version.rb +5 -0
- data/Ruby/lib/mini_profiler_rails/railtie.rb +107 -0
- data/Ruby/lib/patches/net_patches.rb +14 -0
- data/Ruby/lib/patches/sql_patches.rb +272 -0
- data/Ruby/lib/rack-mini-profiler.rb +7 -0
- data/mini-mini-profiler.gemspec +26 -0
- 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,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
|