rack-mini-profiler 0.1.20 → 0.1.25

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.

Potentially problematic release.


This version of rack-mini-profiler might be problematic. Click here for more details.

Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Ruby/CHANGELOG +130 -0
  3. data/{README.md → Ruby/README.md} +40 -9
  4. data/Ruby/lib/html/flamegraph.html +325 -0
  5. data/Ruby/lib/html/includes.css +451 -0
  6. data/{lib → Ruby/lib}/html/includes.js +135 -24
  7. data/{lib → Ruby/lib}/html/includes.less +38 -35
  8. data/{lib → Ruby/lib}/html/includes.tmpl +40 -15
  9. data/{lib → Ruby/lib}/html/jquery.1.7.1.js +1 -1
  10. data/{lib → Ruby/lib}/html/jquery.tmpl.js +1 -1
  11. data/{lib → Ruby/lib}/html/list.css +0 -0
  12. data/{lib → Ruby/lib}/html/list.js +7 -6
  13. data/{lib → Ruby/lib}/html/list.tmpl +0 -0
  14. data/Ruby/lib/html/profile_handler.js +1 -0
  15. data/{lib → Ruby/lib}/html/share.html +0 -0
  16. data/{lib → Ruby/lib}/mini_profiler/client_settings.rb +0 -0
  17. data/{lib → Ruby/lib}/mini_profiler/client_timer_struct.rb +1 -1
  18. data/{lib → Ruby/lib}/mini_profiler/config.rb +57 -52
  19. data/{lib → Ruby/lib}/mini_profiler/context.rb +11 -10
  20. data/Ruby/lib/mini_profiler/custom_timer_struct.rb +22 -0
  21. data/Ruby/lib/mini_profiler/flame_graph.rb +54 -0
  22. data/Ruby/lib/mini_profiler/gc_profiler.rb +107 -0
  23. data/{lib → Ruby/lib}/mini_profiler/page_timer_struct.rb +7 -2
  24. data/{lib → Ruby/lib}/mini_profiler/profiler.rb +206 -196
  25. data/{lib → Ruby/lib}/mini_profiler/profiling_methods.rb +131 -100
  26. data/{lib → Ruby/lib}/mini_profiler/request_timer_struct.rb +20 -1
  27. data/{lib → Ruby/lib}/mini_profiler/sql_timer_struct.rb +0 -0
  28. data/{lib → Ruby/lib}/mini_profiler/storage/abstract_store.rb +31 -27
  29. data/{lib → Ruby/lib}/mini_profiler/storage/file_store.rb +111 -109
  30. data/Ruby/lib/mini_profiler/storage/memcache_store.rb +53 -0
  31. data/{lib → Ruby/lib}/mini_profiler/storage/memory_store.rb +65 -63
  32. data/Ruby/lib/mini_profiler/storage/redis_store.rb +54 -0
  33. data/{lib → Ruby/lib}/mini_profiler/timer_struct.rb +0 -0
  34. data/Ruby/lib/mini_profiler/version.rb +5 -0
  35. data/{lib → Ruby/lib}/mini_profiler_rails/railtie.rb +3 -2
  36. data/Ruby/lib/patches/net_patches.rb +14 -0
  37. data/{lib → Ruby/lib}/patches/sql_patches.rb +89 -48
  38. data/{lib → Ruby/lib}/rack-mini-profiler.rb +2 -1
  39. data/rack-mini-profiler.gemspec +8 -6
  40. metadata +56 -65
  41. data/CHANGELOG +0 -93
  42. data/lib/html/includes.css +0 -75
  43. data/lib/html/profile_handler.js +0 -62
  44. data/lib/mini_profiler/storage/redis_store.rb +0 -44
@@ -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
@@ -1,63 +1,65 @@
1
- module Rack
2
- class MiniProfiler
3
- class MemoryStore < AbstractStore
4
-
5
- EXPIRE_TIMER_CACHE = 3600 * 24
6
-
7
- def initialize(args)
8
- @timer_struct_lock = Mutex.new
9
- @timer_struct_cache = {}
10
- @user_view_lock = Mutex.new
11
- @user_view_cache = {}
12
-
13
- # TODO: fix it to use weak ref, trouble is may be broken in 1.9 so need to use the 'ref' gem
14
- me = self
15
- Thread.new do
16
- while true do
17
- me.cleanup_cache
18
- sleep(3600)
19
- end
20
- end
21
- end
22
-
23
- def save(page_struct)
24
- @timer_struct_lock.synchronize {
25
- @timer_struct_cache[page_struct['Id']] = page_struct
26
- }
27
- end
28
-
29
- def load(id)
30
- @timer_struct_lock.synchronize {
31
- @timer_struct_cache[id]
32
- }
33
- end
34
-
35
- def set_unviewed(user, id)
36
- @user_view_lock.synchronize {
37
- @user_view_cache[user] ||= []
38
- @user_view_cache[user] << id
39
- }
40
- end
41
-
42
- def set_viewed(user, id)
43
- @user_view_lock.synchronize {
44
- @user_view_cache[user] ||= []
45
- @user_view_cache[user].delete(id)
46
- }
47
- end
48
-
49
- def get_unviewed_ids(user)
50
- @user_view_lock.synchronize {
51
- @user_view_cache[user]
52
- }
53
- end
54
-
55
- def cleanup_cache
56
- expire_older_than = ((Time.now.to_f - MiniProfiler::MemoryStore::EXPIRE_TIMER_CACHE) * 1000).to_i
57
- @timer_struct_lock.synchronize {
58
- @timer_struct_cache.delete_if { |k, v| v['Started'] < expire_older_than }
59
- }
60
- end
61
- end
62
- end
63
- end
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,5 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ VERSION = 'e777c6e0fdfb9a725e857c8ca3eab18f'.freeze
4
+ end
5
+ end
@@ -9,11 +9,12 @@ module MiniProfilerRails
9
9
 
10
10
  # By default, only show the MiniProfiler in development mode, in production allow profiling if post_authorize_cb is set
11
11
  c.pre_authorize_cb = lambda { |env|
12
- Rails.env.development? || Rails.env.production?
12
+ !Rails.env.test?
13
13
  }
14
14
 
15
+ c.skip_paths ||= []
16
+
15
17
  if Rails.env.development?
16
- c.skip_paths ||= []
17
18
  c.skip_paths << "/assets/"
18
19
  c.skip_schema_queries = true
19
20
  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
@@ -8,32 +8,32 @@ class SqlPatches
8
8
  @patched = val
9
9
  end
10
10
 
11
- def self.class_exists?(name)
12
- eval(name + ".class").to_s.eql?('Class')
13
- rescue NameError
14
- false
15
- end
16
-
11
+ def self.class_exists?(name)
12
+ eval(name + ".class").to_s.eql?('Class')
13
+ rescue NameError
14
+ false
15
+ end
16
+
17
17
  def self.module_exists?(name)
18
- eval(name + ".class").to_s.eql?('Module')
19
- rescue NameError
20
- false
21
- end
18
+ eval(name + ".class").to_s.eql?('Module')
19
+ rescue NameError
20
+ false
21
+ end
22
22
  end
23
23
 
24
24
  # The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
25
25
  if SqlPatches.class_exists? "Mysql2::Client"
26
-
26
+
27
27
  class Mysql2::Result
28
28
  alias_method :each_without_profiling, :each
29
29
  def each(*args, &blk)
30
30
  return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
31
31
 
32
32
  start = Time.now
33
- result = each_without_profiling(*args,&blk)
33
+ result = each_without_profiling(*args,&blk)
34
34
  elapsed_time = ((Time.now - start).to_f * 1000).round(1)
35
35
 
36
- @miniprofiler_sql_id.report_reader_duration(elapsed_time)
36
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
37
37
  result
38
38
  end
39
39
  end
@@ -42,7 +42,7 @@ if SqlPatches.class_exists? "Mysql2::Client"
42
42
  alias_method :query_without_profiling, :query
43
43
  def query(*args,&blk)
44
44
  current = ::Rack::MiniProfiler.current
45
- return query_without_profiling(*args,&blk) unless current
45
+ return query_without_profiling(*args,&blk) unless current && current.measure
46
46
 
47
47
  start = Time.now
48
48
  result = query_without_profiling(*args,&blk)
@@ -53,14 +53,14 @@ if SqlPatches.class_exists? "Mysql2::Client"
53
53
 
54
54
  end
55
55
  end
56
-
56
+
57
57
  SqlPatches.patched = true
58
58
  end
59
59
 
60
60
 
61
- # PG patches, keep in mind exec and async_exec have a exec{|r| } semantics that is yet to be implemented
61
+ # PG patches, keep in mind exec and async_exec have a exec{|r| } semantics that is yet to be implemented
62
62
  if SqlPatches.class_exists? "PG::Result"
63
-
63
+
64
64
  class PG::Result
65
65
  alias_method :each_without_profiling, :each
66
66
  alias_method :values_without_profiling, :values
@@ -69,10 +69,10 @@ if SqlPatches.class_exists? "PG::Result"
69
69
  return values_without_profiling(*args, &blk) unless @miniprofiler_sql_id
70
70
 
71
71
  start = Time.now
72
- result = values_without_profiling(*args,&blk)
72
+ result = values_without_profiling(*args,&blk)
73
73
  elapsed_time = ((Time.now - start).to_f * 1000).round(1)
74
74
 
75
- @miniprofiler_sql_id.report_reader_duration(elapsed_time)
75
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
76
76
  result
77
77
  end
78
78
 
@@ -80,10 +80,10 @@ if SqlPatches.class_exists? "PG::Result"
80
80
  return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
81
81
 
82
82
  start = Time.now
83
- result = each_without_profiling(*args,&blk)
83
+ result = each_without_profiling(*args,&blk)
84
84
  elapsed_time = ((Time.now - start).to_f * 1000).round(1)
85
85
 
86
- @miniprofiler_sql_id.report_reader_duration(elapsed_time)
86
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
87
87
  result
88
88
  end
89
89
  end
@@ -96,23 +96,23 @@ if SqlPatches.class_exists? "PG::Result"
96
96
  alias_method :prepare_without_profiling, :prepare
97
97
 
98
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
-
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
102
  @prepare_map ||= {}
103
103
  @prepare_map[args[0]] = args[1]
104
104
  # dont leak more than 10k ever
105
105
  @prepare_map = {} if @prepare_map.length > 1000
106
106
 
107
107
  current = ::Rack::MiniProfiler.current
108
- return prepare_without_profiling(*args,&blk) unless current
108
+ return prepare_without_profiling(*args,&blk) unless current && current.measure
109
109
 
110
- prepare_without_profiling(*args,&blk)
110
+ prepare_without_profiling(*args,&blk)
111
111
  end
112
112
 
113
113
  def exec(*args,&blk)
114
114
  current = ::Rack::MiniProfiler.current
115
- return exec_without_profiling(*args,&blk) unless current
115
+ return exec_without_profiling(*args,&blk) unless current && current.measure
116
116
 
117
117
  start = Time.now
118
118
  result = exec_without_profiling(*args,&blk)
@@ -124,7 +124,7 @@ if SqlPatches.class_exists? "PG::Result"
124
124
 
125
125
  def exec_prepared(*args,&blk)
126
126
  current = ::Rack::MiniProfiler.current
127
- return exec_prepared_without_profiling(*args,&blk) unless current
127
+ return exec_prepared_without_profiling(*args,&blk) unless current && current.measure
128
128
 
129
129
  start = Time.now
130
130
  result = exec_prepared_without_profiling(*args,&blk)
@@ -135,10 +135,10 @@ if SqlPatches.class_exists? "PG::Result"
135
135
 
136
136
  result
137
137
  end
138
-
138
+
139
139
  def send_query_prepared(*args,&blk)
140
140
  current = ::Rack::MiniProfiler.current
141
- return send_query_prepared_without_profiling(*args,&blk) unless current
141
+ return send_query_prepared_without_profiling(*args,&blk) unless current && current.measure
142
142
 
143
143
  start = Time.now
144
144
  result = send_query_prepared_without_profiling(*args,&blk)
@@ -149,10 +149,10 @@ if SqlPatches.class_exists? "PG::Result"
149
149
 
150
150
  result
151
151
  end
152
-
152
+
153
153
  def async_exec(*args,&blk)
154
154
  current = ::Rack::MiniProfiler.current
155
- return exec_without_profiling(*args,&blk) unless current
155
+ return exec_without_profiling(*args,&blk) unless current && current.measure
156
156
 
157
157
  start = Time.now
158
158
  result = exec_without_profiling(*args,&blk)
@@ -161,34 +161,75 @@ if SqlPatches.class_exists? "PG::Result"
161
161
 
162
162
  result
163
163
  end
164
-
164
+
165
165
  alias_method :query, :exec
166
166
  end
167
-
167
+
168
168
  SqlPatches.patched = true
169
169
  end
170
170
 
171
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
+
172
213
 
173
214
  # Fallback for sequel
174
215
  if SqlPatches.class_exists?("Sequel::Database") && !SqlPatches.patched?
175
- module Sequel
176
- class Database
177
- alias_method :log_duration_original, :log_duration
178
- def log_duration(duration, message)
179
- ::Rack::MiniProfiler.record_sql(message, duration)
180
- log_duration_original(duration, message)
181
- end
182
- end
183
- end
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
184
225
  end
185
226
 
186
227
 
187
228
  ## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
188
229
  ## fallback for alls sorts of weird dbs
189
- if SqlPatches.module_exists?('ActiveRecord')
230
+ if SqlPatches.module_exists?('ActiveRecord') && !SqlPatches.patched?
190
231
  module Rack
191
- class MiniProfiler
232
+ class MiniProfiler
192
233
  module ActiveRecordInstrumentation
193
234
  def self.included(instrumented_class)
194
235
  instrumented_class.class_eval do
@@ -202,12 +243,12 @@ if SqlPatches.module_exists?('ActiveRecord')
202
243
 
203
244
  def log_with_miniprofiler(*args, &block)
204
245
  current = ::Rack::MiniProfiler.current
205
- return log_without_miniprofiler(*args, &block) unless current
246
+ return log_without_miniprofiler(*args, &block) unless current && current.measure
206
247
 
207
248
  sql, name, binds = args
208
249
  t0 = Time.now
209
250
  rval = log_without_miniprofiler(*args, &block)
210
-
251
+
211
252
  # Don't log schema queries if the option is set
212
253
  return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
213
254
 
@@ -218,7 +259,7 @@ if SqlPatches.module_exists?('ActiveRecord')
218
259
  end
219
260
  end
220
261
 
221
- def self.insert_instrumentation
262
+ def self.insert_instrumentation
222
263
  ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
223
264
  include ::Rack::MiniProfiler::ActiveRecordInstrumentation
224
265
  end