rack-mini-profiler 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

@@ -0,0 +1,26 @@
1
+ 28-June-2012 - Sam
2
+
3
+ * Started change log
4
+ * Corrected profiler so it properly captures POST requests (was supressing non 200s)
5
+ * Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
6
+ * Fixed bug where unviewed missing ids never got cleared
7
+ * Supress all '/assets/' in the rails tie (makes debugging easier)
8
+ * record_sql was mega buggy
9
+
10
+ 9-July-2012 - Sam
11
+
12
+ * Cleaned up mechanism for profiling in production, all you need to do now
13
+ is call Rack::MiniProfiler.authorize_request to get profiling working in
14
+ production
15
+ * Added option to display full backtraces pp=full-backtrace
16
+ * Cleaned up railties, got rid of the post authorize callback
17
+ * Version 0.1.3
18
+
19
+ 12-July-2012 - Sam
20
+
21
+ * Fixed incorrect profiling steps (was not indenting or measuring start time right
22
+ * Implemented native PG and MySql2 interceptors, this gives way more accurate times
23
+ * Refactored context so its a proper class and not a hash
24
+ * Added some more client probing built in to rails
25
+ * More tests
26
+
data/README.md CHANGED
@@ -1,27 +1,31 @@
1
1
  # rack-mini-profiler
2
2
 
3
- Middleware that displays speed badge for every html page.
3
+ Middleware that displays speed badge for every html page. Designed to work both in production and in development.
4
4
 
5
- ## What does it do
6
-
7
- MiniProfiler keeps you aware of your site's performance as you are developing it.
8
- It does this by....
9
-
10
- `env['profiler.mini']` is the profiler
11
-
12
- ## Using mini-profiler in your app
5
+ ## Using rack-mini-profiler in your app
13
6
 
14
7
  Install/add to Gemfile
15
8
 
16
9
  ```ruby
17
10
  gem 'rack-mini-profiler'
18
11
  ```
12
+ Using Rails:
19
13
 
20
- Add it to your middleware stack:
14
+ All you have to do is include the Gem and you're good to go in development.
21
15
 
22
- Using Rails:
16
+ rack-mini-profiler is designed with production profiling in mind. To enable that just run `Rack::MiniProfiler.authorize_request` once you know a request is allowed to profile.
17
+
18
+ For example:
19
+
20
+ ```ruby
21
+ # A hook in your ApplicationController
22
+ def authorize
23
+ if current_user.is_admin?
24
+ Rack::MiniProfiler.authorize_request
25
+ end
26
+ end
27
+ ````
23
28
 
24
- All you have to do is include the Gem and you're good to go.
25
29
 
26
30
  Using Builder:
27
31
 
@@ -58,15 +62,18 @@ You can set configuration options using the configuration accessor on Rack::Mini
58
62
 
59
63
  ```
60
64
  # Have Mini Profiler show up on the right
61
- Rack::MiniProfiler.configuration[:position] = 'right'
65
+ Rack::MiniProfiler.config.position = 'right'
62
66
  ```
63
67
 
64
68
  In a Rails app, this can be done conveniently in an initializer such as config/initializers/mini_profiler.rb.
65
69
 
66
70
  ## Available Options
67
71
 
68
- * authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
72
+ * pre_authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
69
73
  * position - Can either be 'right' or 'left'. Default is 'left'.
70
- * skip_schema_queries - Whether or not you want to log the queries about the schema of your tables. Default is 'true'
74
+ * skip_schema_queries - Whether or not you want to log the queries about the schema of your tables. Default is 'false', 'true' in rails development.
75
+
76
+ ## Special query strings
71
77
 
78
+ If you include the query string `pp=help` at the end of your request you will see the various option you have. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
72
79
 
@@ -475,6 +475,18 @@ var MiniProfiler = (function ($) {
475
475
  })();
476
476
  }
477
477
 
478
+ // also fetch results after ExtJS requests, in case it is being used
479
+ if (typeof (Ext) != 'undefined' && typeof (Ext.Ajax) != 'undefined' && typeof (Ext.Ajax.on) != 'undefined') {
480
+ // Ext.Ajax is a singleton, so we just have to attach to its 'requestcomplete' event
481
+ Ext.Ajax.on('requestcomplete', function(e, xhr, settings) {
482
+ var stringIds = xhr.getResponseHeader('X-MiniProfiler-Ids');
483
+ if (stringIds) {
484
+ var ids = typeof JSON != 'undefined' ? JSON.parse(stringIds) : eval(stringIds);
485
+ fetchResults(ids);
486
+ }
487
+ });
488
+ }
489
+
478
490
  // some elements want to be hidden on certain doc events
479
491
  bindDocumentEvents();
480
492
  };
@@ -6,6 +6,19 @@ module Rack
6
6
  # This class holds the client timings
7
7
  class ClientTimerStruct < TimerStruct
8
8
 
9
+ def self.init_instrumentation
10
+ "<script type=\"text/javascript\">mPt=function(){var t=[];return{t:t,probe:function(n){t.push({d:new Date(),n:n})}}}()</script>"
11
+ end
12
+
13
+ def self.instrument(name,orig)
14
+ probe = "<script>mPt.probe('#{name}')</script>"
15
+ wrapped = probe
16
+ wrapped << orig
17
+ wrapped << probe
18
+ wrapped
19
+ end
20
+
21
+
9
22
  def initialize(env={})
10
23
  super
11
24
  end
@@ -21,6 +34,26 @@ module Rack
21
34
  baseTime = clientTimes['navigationStart'].to_i if clientTimes
22
35
  return unless clientTimes && baseTime
23
36
 
37
+ probes = form['clientProbes']
38
+ translated = {}
39
+ if probes && probes != "null"
40
+ probes.each do |id, val|
41
+ name = val["n"]
42
+ translated[name] ||= {}
43
+ if translated[name][:start]
44
+ translated[name][:finish] = val["d"]
45
+ else
46
+ translated[name][:start] = val["d"]
47
+ end
48
+ end
49
+ end
50
+
51
+ translated.each do |name, data|
52
+ h = {"Name" => name, "Start" => data[:start].to_i - baseTime}
53
+ h["Duration"] = data[:finish].to_i - data[:start].to_i if data[:finish]
54
+ timings.push(h)
55
+ end
56
+
24
57
  clientTimes.keys.find_all{|k| k =~ /Start$/ }.each do |k|
25
58
  start = clientTimes[k].to_i - baseTime
26
59
  finish = clientTimes[k.sub(/Start$/, "End")].to_i - baseTime
@@ -0,0 +1,51 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ class Config
4
+
5
+ def self.attr_accessor(*vars)
6
+ @attributes ||= []
7
+ @attributes.concat vars
8
+ super(*vars)
9
+ end
10
+
11
+ def self.attributes
12
+ @attributes
13
+ end
14
+
15
+ attr_accessor :auto_inject, :base_url_path, :pre_authorize_cb, :position,
16
+ :backtrace_remove, :backtrace_filter, :skip_schema_queries,
17
+ :storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode
18
+
19
+ def self.default
20
+ new.instance_eval {
21
+ @auto_inject = true # automatically inject on every html page
22
+ @base_url_path = "/mini-profiler-resources/"
23
+
24
+ # called prior to rack chain, to ensure we are allowed to profile
25
+ @pre_authorize_cb = lambda {|env| true}
26
+
27
+ # called after rack chain, to ensure we are REALLY allowed to profile
28
+ @position = 'left' # Where it is displayed
29
+ @skip_schema_queries = false
30
+ @storage = MiniProfiler::MemoryStore
31
+ @user_provider = Proc.new{|env| Rack::Request.new(env).ip}
32
+ @authorization_mode = :allow_all
33
+ self
34
+ }
35
+ end
36
+
37
+ def merge!(config)
38
+ return unless config
39
+ if Hash === config
40
+ config.each{|k,v| instance_variable_set "@#{k}",v}
41
+ else
42
+ self.class.attributes.each{ |k|
43
+ v = config.send k
44
+ instance_variable_set "@#{k}", v if v
45
+ }
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ class Rack::MiniProfiler::Context
2
+ attr_accessor :inject_js,:current_timer,:page_struct,:skip_backtrace,:full_backtrace,:discard, :mpt_init
3
+
4
+ def initialize(opts = {})
5
+ opts.each do |k,v|
6
+ self.instance_variable_set('@' + k, v)
7
+ end
8
+ end
9
+
10
+ end
@@ -35,15 +35,19 @@ module Rack
35
35
  def duration_ms
36
36
  @attributes['Root']['DurationMilliseconds']
37
37
  end
38
+
39
+ def root
40
+ @attributes['Root']
41
+ end
38
42
 
39
43
  def to_json(*a)
40
44
  attribs = @attributes.merge(
41
45
  "Started" => '/Date(%d)/' % @attributes['Started'],
42
46
  "DurationMilliseconds" => @attributes['Root']['DurationMilliseconds']
43
47
  )
44
- ::JSON.generate(attribs, a[0])
48
+ ::JSON.generate(attribs, :max_nesting => 100)
45
49
  end
46
50
  end
47
51
 
48
52
  end
49
- end
53
+ end
@@ -11,67 +11,102 @@ require 'mini_profiler/storage/abstract_store'
11
11
  require 'mini_profiler/storage/memory_store'
12
12
  require 'mini_profiler/storage/redis_store'
13
13
  require 'mini_profiler/storage/file_store'
14
+ require 'mini_profiler/config'
15
+ require 'mini_profiler/profiling_methods'
16
+ require 'mini_profiler/context'
14
17
 
15
18
  module Rack
16
19
 
17
20
  class MiniProfiler
18
21
 
19
- VERSION = 'rZlycOOTnzxZvxTmFuOEV0dSmu4P5m5bLrCtwJHVXPA='.freeze
20
- @@instance = nil
22
+ VERSION = 'rZlycOOTnzxZvxTmFuOEV0dSmu4P5m5bLrCtwJHVXPA=A'.freeze
21
23
 
22
- def self.instance
23
- @@instance
24
- end
24
+ class << self
25
+
26
+ include Rack::MiniProfiler::ProfilingMethods
25
27
 
26
- def self.generate_id
27
- rand(36**20).to_s(36)
28
- end
28
+ def generate_id
29
+ rand(36**20).to_s(36)
30
+ end
29
31
 
30
- # Defaults for MiniProfiler's configuration
31
- def self.configuration_defaults
32
- {
33
- :auto_inject => true, # automatically inject on every html page
34
- :base_url_path => "/mini-profiler-resources/",
35
- :authorize_cb => lambda {|env| true}, # callback returns true if this request is authorized to profile
36
- :position => 'left', # Where it is displayed
37
- :backtrace_remove => nil,
38
- :backtrace_filter => nil,
39
- :skip_schema_queries => true,
40
- :storage => MiniProfiler::MemoryStore,
41
- :user_provider => Proc.new{|env| Rack::Request.new(env).ip }
42
- }
43
- end
32
+ def reset_config
33
+ @config = Config.default
34
+ end
44
35
 
45
- def self.reset_configuration
46
- @configuration = configuration_defaults
47
- end
36
+ # So we can change the configuration if we want
37
+ def config
38
+ @config ||= Config.default
39
+ end
48
40
 
49
- # So we can change the configuration if we want
50
- def self.configuration
51
- @configuration ||= configuration_defaults.dup
52
- end
41
+ def share_template
42
+ return @share_template unless @share_template.nil?
43
+ @share_template = ::File.read(::File.expand_path("../html/share.html", ::File.dirname(__FILE__)))
44
+ end
45
+
46
+ def current
47
+ Thread.current[:mini_profiler_private]
48
+ end
49
+
50
+ def current=(c)
51
+ # we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
52
+ Thread.current[:mini_profiler_private]= c
53
+ end
54
+
55
+ # discard existing results, don't track this request
56
+ def discard_results
57
+ self.current.discard = true if current
58
+ end
59
+
60
+ # user has the mini profiler cookie, only used when config.authorization_mode == :whitelist
61
+ def has_profiling_cookie?(env)
62
+ env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin=stylin")
63
+ end
64
+
65
+ # remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
66
+ def remove_profiling_cookie(headers)
67
+ Rack::Utils.delete_cookie_header!(headers, '__profilin')
68
+ end
53
69
 
54
- def self.share_template
55
- return @share_template unless @share_template.nil?
56
- @share_template = ::File.read(::File.expand_path("../html/share.html", ::File.dirname(__FILE__)))
70
+ def set_profiling_cookie(headers)
71
+ Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
72
+ end
73
+
74
+ def create_current(env={}, options={})
75
+ # profiling the request
76
+ self.current = Context.new
77
+ self.current.inject_js = config.auto_inject && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
78
+ self.current.page_struct = PageTimerStruct.new(env)
79
+ self.current.current_timer = current.page_struct['Root']
80
+ end
81
+
82
+ def authorize_request
83
+ Thread.current[:mp_authorized] = true
84
+ end
85
+
86
+ def deauthorize_request
87
+ Thread.current[:mp_authorized] = nil
88
+ end
89
+
90
+ def request_authorized?
91
+ Thread.current[:mp_authorized]
92
+ end
57
93
  end
58
94
 
59
95
  #
60
96
  # options:
61
97
  # :auto_inject - should script be automatically injected on every html page (not xhr)
62
- def initialize(app, opts={})
63
- @@instance = self
64
- MiniProfiler.configuration.merge!(opts)
65
- @options = MiniProfiler.configuration
98
+ def initialize(app, config = nil)
99
+ MiniProfiler.config.merge!(config)
100
+ @config = MiniProfiler.config
66
101
  @app = app
67
- @options[:base_url_path] << "/" unless @options[:base_url_path].end_with? "/"
68
- unless @options[:storage_instance]
69
- @storage = @options[:storage_instance] = @options[:storage].new(@options[:storage_options])
102
+ @config.base_url_path << "/" unless @config.base_url_path.end_with? "/"
103
+ unless @config.storage_instance
104
+ @storage = @config.storage_instance = @config.storage.new(@config.storage_options)
70
105
  end
71
106
  end
72
107
 
73
108
  def user(env)
74
- options[:user_provider].call(env)
109
+ @config.user_provider.call(env)
75
110
  end
76
111
 
77
112
  def serve_results(env)
@@ -97,7 +132,7 @@ module Rack
97
132
 
98
133
  # Otherwise give the HTML back
99
134
  html = MiniProfiler.share_template.dup
100
- html.gsub!(/\{path\}/, @options[:base_url_path])
135
+ html.gsub!(/\{path\}/, @config.base_url_path)
101
136
  html.gsub!(/\{version\}/, MiniProfiler::VERSION)
102
137
  html.gsub!(/\{json\}/, result_json)
103
138
  html.gsub!(/\{includes\}/, get_profile_script(env))
@@ -110,7 +145,7 @@ module Rack
110
145
  end
111
146
 
112
147
  def serve_html(env)
113
- file_name = env['PATH_INFO'][(@options[:base_url_path].length)..1000]
148
+ file_name = env['PATH_INFO'][(@config.base_url_path.length)..1000]
114
149
  return serve_results(env) if file_name.eql?('results')
115
150
  full_path = ::File.expand_path("../html/#{file_name}", ::File.dirname(__FILE__))
116
151
  return [404, {}, ["Not found"]] unless ::File.exists? full_path
@@ -120,15 +155,7 @@ module Rack
120
155
  f.serving env
121
156
  end
122
157
 
123
- def self.current
124
- Thread.current['profiler.mini.private']
125
- end
126
-
127
- def self.current=(c)
128
- # we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
129
- Thread.current['profiler.mini.private'] = c
130
- end
131
-
158
+
132
159
  def current
133
160
  MiniProfiler.current
134
161
  end
@@ -137,54 +164,73 @@ module Rack
137
164
  MiniProfiler.current=c
138
165
  end
139
166
 
140
- def options
141
- @options
142
- end
143
167
 
144
- def self.create_current(env={}, options={})
145
- # profiling the request
146
- self.current = {}
147
- self.current['inject_js'] = options[:auto_inject] && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
148
- self.current['page_struct'] = PageTimerStruct.new(env)
149
- self.current['current_timer'] = current['page_struct']['Root']
168
+ def config
169
+ @config
150
170
  end
151
171
 
172
+
152
173
  def call(env)
153
- status = headers = body = nil
174
+ status = headers = body = nil
175
+ path = env['PATH_INFO']
154
176
 
155
- # only profile if authorized
156
- return @app.call(env) unless @options[:authorize_cb].call(env)
177
+ skip_it = (@config.pre_authorize_cb && !@config.pre_authorize_cb.call(env)) ||
178
+ (@config.skip_paths && @config.skip_paths.any?{ |p| path[0,p.length] == p}) ||
179
+ env["QUERY_STRING"] =~ /pp=skip/
180
+
181
+ has_profiling_cookie = MiniProfiler.has_profiling_cookie?(env)
182
+
183
+ if skip_it || (@config.authorization_mode == :whitelist && !has_profiling_cookie)
184
+ status,headers,body = @app.call(env)
185
+ if !skip_it && @config.authorization_mode == :whitelist && !has_profiling_cookie && MiniProfiler.request_authorized?
186
+ MiniProfiler.set_profiling_cookie(headers)
187
+ end
188
+ return [status,headers,body]
189
+ end
157
190
 
158
- # handle all /mini-profiler requests here
159
- return serve_html(env) if env['PATH_INFO'].start_with? @options[:base_url_path]
191
+ # handle all /mini-profiler requests here
192
+ return serve_html(env) if env['PATH_INFO'].start_with? @config.base_url_path
160
193
 
161
- MiniProfiler.create_current(env, @options)
162
- if env["QUERY_STRING"] =~ /pp=skip-backtrace/
163
- current['skip-backtrace'] = true
194
+ MiniProfiler.create_current(env, @config)
195
+ MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
196
+ if env["QUERY_STRING"] =~ /pp=no-backtrace/
197
+ current.skip_backtrace = true
198
+ elsif env["QUERY_STRING"] =~ /pp=full-backtrace/
199
+ current.full_backtrace = true
164
200
  end
165
201
 
166
- start = Time.now
167
-
168
202
  done_sampling = false
169
203
  quit_sampler = false
170
204
  backtraces = nil
205
+ missing_stacktrace = false
171
206
  if env["QUERY_STRING"] =~ /pp=sample/
172
207
  backtraces = []
173
208
  t = Thread.current
174
209
  Thread.new {
175
- i = 10000 # for sanity never grab more than 10k samples
176
- unless done_sampling || i < 0
177
- i -= 1
178
- backtraces << t.backtrace
179
- sleep 0.001
210
+ begin
211
+ require 'stacktrace' rescue nil
212
+ if !t.respond_to? :stacktrace
213
+ missing_stacktrace = true
214
+ quit_sampler = true
215
+ return
216
+ end
217
+ i = 10000 # for sanity never grab more than 10k samples
218
+ while i > 0
219
+ break if done_sampling
220
+ i -= 1
221
+ backtraces << t.stacktrace
222
+ sleep 0.001
223
+ end
224
+ ensure
225
+ quit_sampler = true
180
226
  end
181
- quit_sampler = true
182
227
  }
183
228
  end
184
229
 
185
230
  status, headers, body = nil
231
+ start = Time.now
186
232
  begin
187
- status,headers, body = @app.call(env)
233
+ status,headers,body = @app.call(env)
188
234
  ensure
189
235
  if backtraces
190
236
  done_sampling = true
@@ -192,9 +238,35 @@ module Rack
192
238
  end
193
239
  end
194
240
 
195
- page_struct = current['page_struct']
241
+ skip_it = current.discard
242
+ if (config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
243
+ MiniProfiler.remove_profiling_cookie(headers)
244
+ skip_it = true
245
+ end
246
+
247
+ return [status,headers,body] if skip_it
248
+
249
+ # we must do this here, otherwise current[:discard] is not being properly treated
250
+ if env["QUERY_STRING"] =~ /pp=env/
251
+ body.close if body.respond_to? :close
252
+ return dump_env env
253
+ end
254
+
255
+ if env["QUERY_STRING"] =~ /pp=help/
256
+ body.close if body.respond_to? :close
257
+ return help
258
+ end
259
+
260
+ page_struct = current.page_struct
196
261
  page_struct['Root'].record_time((Time.now - start) * 1000)
197
262
 
263
+ if backtraces
264
+ body.close if body.respond_to? :close
265
+ return help(:stacktrace) if missing_stacktrace
266
+ return analyze(backtraces, page_struct)
267
+ end
268
+
269
+
198
270
  # no matter what it is, it should be unviewed, otherwise we will miss POST
199
271
  @storage.set_unviewed(user(env), page_struct['Id'])
200
272
  @storage.save(page_struct)
@@ -208,7 +280,7 @@ module Rack
208
280
  end
209
281
 
210
282
  # inject script
211
- if current['inject_js'] \
283
+ if current.inject_js \
212
284
  && headers.has_key?('Content-Type') \
213
285
  && !headers['Content-Type'].match(/text\/html/).nil? then
214
286
  body = MiniProfiler::BodyAddProxy.new(body, self.get_profile_script(env))
@@ -226,8 +298,68 @@ module Rack
226
298
  current = nil
227
299
  end
228
300
 
301
+ def dump_env(env)
302
+ headers = {'Content-Type' => 'text/plain'}
303
+ body = ""
304
+ env.each do |k,v|
305
+ body << "#{k}: #{v}\n"
306
+ end
307
+ [200, headers, [body]]
308
+ end
309
+
310
+ def help(category = nil)
311
+ headers = {'Content-Type' => 'text/plain'}
312
+ body = "Append the following to your query string:
313
+
314
+ pp=help : display this screen
315
+ pp=env : display the rack environment
316
+ pp=skip : skip mini profiler for this request
317
+ pp=no-backtrace : don't collect stack traces from all the SQL executed
318
+ pp=full-backtrace : enable full backtrace for SQL executed
319
+ pp=sample : sample stack traces and return a report isolating heavy usage (requires the stacktrace gem)
320
+ "
321
+ if (category == :stacktrace)
322
+ body = "pp=stacktrace requires the stacktrace gem - add gem 'stacktrace' to your Gemfile"
323
+ end
324
+
325
+ [200, headers, [body]]
326
+ end
327
+
328
+ def analyze(traces, page_struct)
329
+ headers = {'Content-Type' => 'text/plain'}
330
+ body = "Collected: #{traces.count} stack traces. Duration(ms): #{page_struct.duration_ms}"
331
+
332
+ seen = {}
333
+ fulldump = ""
334
+ traces.each do |trace|
335
+ fulldump << "\n\n"
336
+ distinct = {}
337
+ trace.each do |frame|
338
+ name = "#{frame.klass} #{frame.method}"
339
+ unless distinct[name]
340
+ distinct[name] = true
341
+ seen[name] ||= 0
342
+ seen[name] += 1
343
+ end
344
+ fulldump << name << "\n"
345
+ end
346
+ end
347
+
348
+ body << "\n\nStack Trace Analysis\n"
349
+ seen.to_a.sort{|x,y| y[1] <=> x[1]}.each do |name, count|
350
+ if count > traces.count / 10
351
+ body << "#{name} x #{count}\n"
352
+ end
353
+ end
354
+
355
+ body << "\n\n\nRaw traces \n"
356
+ body << fulldump
357
+
358
+ [200, headers, [body]]
359
+ end
360
+
229
361
  def ids_json(env)
230
- ids = [current['page_struct']["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])
362
+ ids = [current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])
231
363
  ::JSON.generate(ids.uniq)
232
364
  end
233
365
 
@@ -239,14 +371,14 @@ module Rack
239
371
  # * you do not want script to be automatically appended for the current page. You can also call cancel_auto_inject
240
372
  def get_profile_script(env)
241
373
  ids = ids_json(env)
242
- path = @options[:base_url_path]
374
+ path = @config.base_url_path
243
375
  version = MiniProfiler::VERSION
244
- position = @options[:position]
376
+ position = @config.position
245
377
  showTrivial = false
246
378
  showChildren = false
247
379
  maxTracesToShow = 10
248
380
  showControls = false
249
- currentId = current['page_struct']["Id"]
381
+ currentId = current.page_struct["Id"]
250
382
  authorized = true
251
383
  useExistingjQuery = false
252
384
  # TODO : cache this snippet
@@ -258,52 +390,13 @@ module Rack
258
390
  end
259
391
  # replace the '{{' and '}}''
260
392
  script.gsub!(/\{\{/, '{').gsub!(/\}\}/, '}')
261
- current['inject_js'] = false
393
+ current.inject_js = false
262
394
  script
263
395
  end
264
396
 
265
397
  # cancels automatic injection of profile script for the current page
266
398
  def cancel_auto_inject(env)
267
- current['inject_js'] = false
268
- end
269
-
270
- # perform a profiling step on given block
271
- def self.step(name)
272
- if current
273
- old_timer = current['current_timer']
274
- new_step = RequestTimerStruct.new(name, current['page_struct'])
275
- current['current_timer'] = new_step
276
- new_step['Name'] = name
277
- start = Time.now
278
- result = yield if block_given?
279
- new_step.record_time((Time.now - start)*1000)
280
- old_timer.add_child(new_step)
281
- current['current_timer'] = old_timer
282
- result
283
- else
284
- yield if block_given?
285
- end
286
- end
287
-
288
- def self.profile_method(klass, method, &blk)
289
- default_name = klass.to_s + " " + method.to_s
290
- with_profiling = (method.to_s + "_with_mini_profiler").intern
291
- without_profiling = (method.to_s + "_without_mini_profiler").intern
292
-
293
- klass.send :alias_method, without_profiling, method
294
- klass.send :define_method, with_profiling do |*args, &orig|
295
- name = default_name
296
- name = blk.bind(self).call(*args) if blk
297
- ::Rack::MiniProfiler.step name do
298
- self.send without_profiling, *args, &orig
299
- end
300
- end
301
- klass.send :alias_method, method, with_profiling
302
- end
303
-
304
- def record_sql(query, elapsed_ms)
305
- c = current
306
- c['current_timer'].add_sql(query, elapsed_ms, c['page_struct'], c['skip-backtrace']) if (c && c['current_timer'])
399
+ current.inject_js = false
307
400
  end
308
401
 
309
402
  end
@@ -0,0 +1,73 @@
1
+ module Rack
2
+ class MiniProfiler
3
+ module ProfilingMethods
4
+
5
+ def record_sql(query, elapsed_ms)
6
+ c = current
7
+ return unless c
8
+ c.current_timer.add_sql(query, elapsed_ms, c.page_struct, c.skip_backtrace, c.full_backtrace) if (c && c.current_timer)
9
+ end
10
+
11
+ # perform a profiling step on given block
12
+ def step(name)
13
+ if current
14
+ parent_timer = current.current_timer
15
+ result = nil
16
+ current.current_timer = current_timer = current.current_timer.add_child(name)
17
+ begin
18
+ result = yield if block_given?
19
+ ensure
20
+ current_timer.record_time
21
+ current.current_timer = parent_timer
22
+ end
23
+ result
24
+ else
25
+ yield if block_given?
26
+ end
27
+ end
28
+
29
+ def unprofile_method(klass, method)
30
+ with_profiling = (method.to_s + "_with_mini_profiler").intern
31
+ without_profiling = (method.to_s + "_without_mini_profiler").intern
32
+
33
+ if klass.send :method_defined?, with_profiling
34
+ klass.send :alias_method, method, without_profiling
35
+ klass.send :remove_method, with_profiling
36
+ klass.send :remove_method, without_profiling
37
+ end
38
+ end
39
+
40
+ def profile_method(klass, method, &blk)
41
+ default_name = klass.to_s + " " + method.to_s
42
+ with_profiling = (method.to_s + "_with_mini_profiler").intern
43
+ without_profiling = (method.to_s + "_without_mini_profiler").intern
44
+
45
+ if klass.send :method_defined?, with_profiling
46
+ return # dont double profile
47
+ end
48
+
49
+ klass.send :alias_method, without_profiling, method
50
+ klass.send :define_method, with_profiling do |*args, &orig|
51
+ return self.send without_profiling, *args, &orig unless Rack::MiniProfiler.current
52
+
53
+ name = default_name
54
+ name = blk.bind(self).call(*args) if blk
55
+
56
+ parent_timer = Rack::MiniProfiler.current.current_timer
57
+ page_struct = Rack::MiniProfiler.current.page_struct
58
+ result = nil
59
+
60
+ Rack::MiniProfiler.current.current_timer = current_timer = parent_timer.add_child(name)
61
+ begin
62
+ result = self.send without_profiling, *args, &orig
63
+ ensure
64
+ current_timer.record_time
65
+ Rack::MiniProfiler.current.current_timer = parent_timer
66
+ end
67
+ result
68
+ end
69
+ klass.send :alias_method, method, with_profiling
70
+ end
71
+ end
72
+ end
73
+ end
@@ -6,14 +6,14 @@ module Rack
6
6
  class RequestTimerStruct < TimerStruct
7
7
 
8
8
  def self.createRoot(name, page)
9
- rt = RequestTimerStruct.new(name, page)
9
+ rt = RequestTimerStruct.new(name, page, nil)
10
10
  rt["IsRoot"]= true
11
11
  rt
12
12
  end
13
13
 
14
- attr_reader :children_duration
14
+ attr_accessor :children_duration
15
15
 
16
- def initialize(name, page)
16
+ def initialize(name, page, parent)
17
17
  super("Id" => MiniProfiler.generate_id,
18
18
  "Name" => name,
19
19
  "DurationMilliseconds" => 0,
@@ -30,34 +30,65 @@ module Rack
30
30
  "SqlTimingsDurationMilliseconds"=> 0,
31
31
  "IsTrivial"=> false,
32
32
  "IsRoot"=> false,
33
- "Depth"=> 0,
33
+ "Depth"=> parent ? parent.depth + 1 : 0,
34
34
  "ExecutedReaders"=> 0,
35
35
  "ExecutedScalars"=> 0,
36
36
  "ExecutedNonQueries"=> 0)
37
37
  @children_duration = 0
38
+ @start = Time.now
39
+ @parent = parent
40
+ @page = page
38
41
  end
39
42
 
40
- def add_child(request_timer)
43
+ def duration_ms
44
+ self['DurationMilliseconds']
45
+ end
46
+
47
+ def start_ms
48
+ self['StartMilliseconds']
49
+ end
50
+
51
+ def start
52
+ @start
53
+ end
54
+
55
+ def depth
56
+ self['Depth']
57
+ end
58
+
59
+ def children
60
+ self['Children']
61
+ end
62
+
63
+ def add_child(name)
64
+ request_timer = RequestTimerStruct.new(name, @page, self)
41
65
  self['Children'].push(request_timer)
42
66
  self['HasChildren'] = true
43
67
  request_timer['ParentTimingId'] = self['Id']
44
68
  request_timer['Depth'] = self['Depth'] + 1
45
- @children_duration += request_timer['DurationMilliseconds']
69
+ request_timer
46
70
  end
47
71
 
48
- def add_sql(query, elapsed_ms, page, skip_backtrace = false)
49
- timer = SqlTimerStruct.new(query, elapsed_ms, page, skip_backtrace)
72
+ def add_sql(query, elapsed_ms, page, skip_backtrace = false, full_backtrace = false)
73
+ timer = SqlTimerStruct.new(query, elapsed_ms, page, self , skip_backtrace, full_backtrace)
50
74
  timer['ParentTimingId'] = self['Id']
51
75
  self['SqlTimings'].push(timer)
52
76
  self['HasSqlTimings'] = true
53
77
  self['SqlTimingsDurationMilliseconds'] += elapsed_ms
54
78
  page['DurationMillisecondsInSql'] += elapsed_ms
79
+ timer
55
80
  end
56
81
 
57
- def record_time(milliseconds)
82
+ def record_time(milliseconds = nil)
83
+ milliseconds ||= (Time.now - @start) * 1000
58
84
  self['DurationMilliseconds'] = milliseconds
59
85
  self['IsTrivial'] = true if milliseconds < self["TrivialDurationThresholdMilliseconds"]
60
86
  self['DurationWithoutChildrenMilliseconds'] = milliseconds - @children_duration
87
+
88
+ if @parent
89
+ @parent.children_duration += milliseconds
90
+ end
91
+
61
92
  end
62
93
  end
63
94
  end
@@ -5,7 +5,7 @@ module Rack
5
5
 
6
6
  # Timing system for a SQL query
7
7
  class SqlTimerStruct < TimerStruct
8
- def initialize(query, duration_ms, page, skip_backtrace = false)
8
+ def initialize(query, duration_ms, page, parent, skip_backtrace = false, full_backtrace = false)
9
9
 
10
10
  stack_trace = nil
11
11
  unless skip_backtrace
@@ -13,24 +13,35 @@ module Rack
13
13
  stack_trace = ""
14
14
  # Clean up the stack trace if there are options to do so
15
15
  Kernel.caller.each do |ln|
16
- ln.gsub!(Rack::MiniProfiler.configuration[:backtrace_remove], '') if Rack::MiniProfiler.configuration[:backtrace_remove]
17
- if Rack::MiniProfiler.configuration[:backtrace_filter].nil? or ln =~ Rack::MiniProfiler.configuration[:backtrace_filter]
16
+ ln.gsub!(Rack::MiniProfiler.config.backtrace_remove, '') if Rack::MiniProfiler.config.backtrace_remove and !full_backtrace
17
+ if full_backtrace or Rack::MiniProfiler.config.backtrace_filter.nil? or ln =~ Rack::MiniProfiler.config.backtrace_filter
18
18
  stack_trace << ln << "\n"
19
19
  end
20
20
  end
21
21
  end
22
22
 
23
+ @parent = parent
24
+ @page = page
25
+
23
26
  super("ExecuteType" => 3, # TODO
24
27
  "FormattedCommandString" => query,
25
28
  "StackTraceSnippet" => stack_trace,
26
- "StartMilliseconds" => (Time.now.to_f * 1000).to_i - page['Started'],
29
+ "StartMilliseconds" => ((Time.now.to_f * 1000).to_i - page['Started']) - duration_ms,
27
30
  "DurationMilliseconds" => duration_ms,
28
- "FirstFetchDurationMilliseconds" => 0,
31
+ "FirstFetchDurationMilliseconds" => duration_ms,
29
32
  "Parameters" => nil,
30
33
  "ParentTimingId" => nil,
31
34
  "IsDuplicate" => false)
32
35
  end
33
36
 
37
+ def report_reader_duration(elapsed_ms)
38
+ return if @reported
39
+ @reported = true
40
+ self["DurationMilliseconds"] += elapsed_ms
41
+ @parent["SqlTimingsDurationMilliseconds"] += elapsed_ms
42
+ @page["DurationMillisecondsInSql"] += elapsed_ms
43
+ end
44
+
34
45
  end
35
46
 
36
47
  end
@@ -1,33 +1,82 @@
1
1
  module MiniProfilerRails
2
+
2
3
  class Railtie < ::Rails::Railtie
3
4
 
4
5
  initializer "rack_mini_profiler.configure_rails_initialization" do |app|
6
+ c = Rack::MiniProfiler.config
5
7
 
6
- # By default, only show the MiniProfiler in development mode
7
- Rack::MiniProfiler.configuration[:authorize_cb] = lambda { |env|
8
- Rails.env.development? && !(env['PATH_INFO'] =~ /^\/assets\//)
8
+ # By default, only show the MiniProfiler in development mode, in production allow profiling if post_authorize_cb is set
9
+ c.pre_authorize_cb = lambda { |env|
10
+ Rails.env.development? || Rails.env.production?
9
11
  }
10
12
 
13
+ if Rails.env.development?
14
+ c.skip_paths ||= []
15
+ c.skip_paths << "/assets/"
16
+ c.skip_schema_queries = true
17
+ end
18
+
19
+ if Rails.env.production?
20
+ c.authorization_mode = :whitelist
21
+ end
22
+
11
23
  # The file store is just so much less flaky
12
24
  tmp = Rails.root.to_s + "/tmp/miniprofiler"
13
25
  Dir::mkdir(tmp) unless File.exists?(tmp)
14
-
15
- Rack::MiniProfiler.configuration[:storage_options] = {:path => tmp}
16
- Rack::MiniProfiler.configuration[:storage] = Rack::MiniProfiler::FileStore
26
+
27
+ c.storage_options = {:path => tmp}
28
+ c.storage = Rack::MiniProfiler::FileStore
17
29
 
18
30
  # Quiet the SQL stack traces
19
- Rack::MiniProfiler.configuration[:backtrace_remove] = Rails.root.to_s + "/"
20
- Rack::MiniProfiler.configuration[:backtrace_filter] = /^\/?(app|config|lib|test)/
31
+ c.backtrace_remove = Rails.root.to_s + "/"
32
+ c.backtrace_filter = /^\/?(app|config|lib|test)/
33
+ c.skip_schema_queries = Rails.env != 'production'
21
34
 
22
35
  # Install the Middleware
23
- app.middleware.insert_before 'Rack::Lock', 'Rack::MiniProfiler'
36
+ app.middleware.insert(0, Rack::MiniProfiler)
24
37
 
25
38
  # Attach to various Rails methods
26
39
  ::Rack::MiniProfiler.profile_method(ActionController::Base, :process) {|action| "Executing action: #{action}"}
27
40
  ::Rack::MiniProfiler.profile_method(ActionView::Template, :render) {|x,y| "Rendering: #{@virtual_path}"}
28
41
 
29
-
30
42
  end
31
43
 
44
+ # TODO: Implement something better here
45
+ # config.after_initialize do
46
+ #
47
+ # class ::ActionView::Helpers::AssetTagHelper::JavascriptIncludeTag
48
+ # alias_method :asset_tag_orig, :asset_tag
49
+ # def asset_tag(source,options)
50
+ # current = Rack::MiniProfiler.current
51
+ # return asset_tag_orig(source,options) unless current
52
+ # wrapped = ""
53
+ # unless current.mpt_init
54
+ # current.mpt_init = true
55
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
56
+ # end
57
+ # name = source.split('/')[-1]
58
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
59
+ # wrapped
60
+ # end
61
+ # end
62
+
63
+ # class ::ActionView::Helpers::AssetTagHelper::StylesheetIncludeTag
64
+ # alias_method :asset_tag_orig, :asset_tag
65
+ # def asset_tag(source,options)
66
+ # current = Rack::MiniProfiler.current
67
+ # return asset_tag_orig(source,options) unless current
68
+ # wrapped = ""
69
+ # unless current.mpt_init
70
+ # current.mpt_init = true
71
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
72
+ # end
73
+ # name = source.split('/')[-1]
74
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
75
+ # wrapped
76
+ # end
77
+ # end
78
+
79
+ # end
80
+
32
81
  end
33
82
  end
@@ -1,4 +1,13 @@
1
- module SqlPatches
1
+ class SqlPatches
2
+
3
+ def self.patched?
4
+ @patched
5
+ end
6
+
7
+ def self.patched=(val)
8
+ @patched = val
9
+ end
10
+
2
11
  def self.class_exists?(name)
3
12
  eval(name + ".class").to_s.eql?('Class')
4
13
  rescue NameError
@@ -6,12 +15,116 @@ module SqlPatches
6
15
  end
7
16
  end
8
17
 
9
- if SqlPatches.class_exists? "Sequel::Database" then
18
+ # The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
19
+ if SqlPatches.class_exists? "Mysql2::Client"
20
+
21
+ class Mysql2::Result
22
+ alias_method :each_without_profiling, :each
23
+ def each(*args, &blk)
24
+ return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
25
+
26
+ start = Time.now
27
+ result = each_without_profiling(*args,&blk)
28
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
29
+
30
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
31
+ result
32
+ end
33
+ end
34
+
35
+ class Mysql2::Client
36
+ alias_method :query_without_profiling, :query
37
+ def query(*args,&blk)
38
+ current = ::Rack::MiniProfiler.current
39
+ return query_without_profiling(*args,&blk) unless current
40
+
41
+ start = Time.now
42
+ result = query_without_profiling(*args,&blk)
43
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
44
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
45
+
46
+ result
47
+
48
+ end
49
+ end
50
+
51
+ SqlPatches.patched = true
52
+ end
53
+
54
+
55
+ # PG patches, keep in mind exec and async_exec have a exec{|r| } semantics that is yet to be implemented
56
+ if SqlPatches.class_exists? "PG::Result"
57
+
58
+ class PG::Result
59
+ alias_method :each_without_profiling, :each
60
+ alias_method :values_without_profiling, :values
61
+
62
+ def values(*args, &blk)
63
+ return values_without_profiling(*args, &blk) unless @miniprofiler_sql_id
64
+
65
+ start = Time.now
66
+ result = values_without_profiling(*args,&blk)
67
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
68
+
69
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
70
+ result
71
+ end
72
+
73
+ def each(*args, &blk)
74
+ return each_without_profiling(*args, &blk) unless @miniprofiler_sql_id
75
+
76
+ start = Time.now
77
+ result = each_without_profiling(*args,&blk)
78
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
79
+
80
+ @miniprofiler_sql_id.report_reader_duration(elapsed_time)
81
+ result
82
+ end
83
+ end
84
+
85
+ class PG::Connection
86
+ alias_method :exec_without_profiling, :exec
87
+ alias_method :async_exec_without_profiling, :async_exec
88
+
89
+ def exec(*args,&blk)
90
+ current = ::Rack::MiniProfiler.current
91
+ return exec_without_profiling(*args,&blk) unless current
92
+
93
+ start = Time.now
94
+ result = exec_without_profiling(*args,&blk)
95
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
96
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
97
+
98
+ result
99
+ end
100
+
101
+ def async_exec(*args,&blk)
102
+ current = ::Rack::MiniProfiler.current
103
+ return exec_without_profiling(*args,&blk) unless current
104
+
105
+ start = Time.now
106
+ result = exec_without_profiling(*args,&blk)
107
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
108
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
109
+
110
+ result
111
+ end
112
+
113
+ alias_method :query, :exec
114
+ end
115
+
116
+ SqlPatches.patched = true
117
+ end
118
+
119
+
120
+
121
+ # Fallback for sequel
122
+ if SqlPatches.class_exists?("Sequel::Database") && !SqlPatches.patched?
10
123
  module Sequel
11
124
  class Database
12
125
  alias_method :log_duration_original, :log_duration
13
126
  def log_duration(duration, message)
14
- ::Rack::MiniProfiler.instance.record_sql(message, duration) if ::Rack::MiniProfiler.instance
127
+ ::Rack::MiniProfiler.record_sql(message, duration)
15
128
  log_duration_original(duration, message)
16
129
  end
17
130
  end
@@ -20,6 +133,7 @@ end
20
133
 
21
134
 
22
135
  ## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
136
+ ## fallback for alls sorts of weird dbs
23
137
  module Rack
24
138
  class MiniProfiler
25
139
  module ActiveRecordInstrumentation
@@ -34,19 +148,18 @@ module Rack
34
148
  end
35
149
 
36
150
  def log_with_miniprofiler(*args, &block)
151
+ current = ::Rack::MiniProfiler.current
152
+ return log_without_miniprofiler(*args, &block) unless current
153
+
37
154
  sql, name, binds = args
38
155
  t0 = Time.now
39
156
  rval = log_without_miniprofiler(*args, &block)
40
-
41
- # Get our MP Instance
42
- instance = ::Rack::MiniProfiler.instance
43
- return rval unless instance
44
-
157
+
45
158
  # Don't log schema queries if the option is set
46
- return rval if instance.options[:skip_schema_queries] and name =~ /SCHEMA/
159
+ return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
47
160
 
48
161
  elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
49
- instance.record_sql(sql, elapsed_time)
162
+ Rack::MiniProfiler.record_sql(sql, elapsed_time)
50
163
  rval
51
164
  end
52
165
  end
@@ -58,15 +171,8 @@ module Rack
58
171
  end
59
172
  end
60
173
 
61
- if defined?(::Rails)
62
- if ::Rails::VERSION::MAJOR.to_i == 3
63
- # in theory this is the right thing to do for rails 3 ... but it seems to work anyway
64
- #Rails.configuration.after_initialize do
65
- insert_instrumentation
66
- #end
67
- else
68
- insert_instrumentation
69
- end
174
+ if defined?(::Rails) && !SqlPatches.patched?
175
+ insert_instrumentation
70
176
  end
71
177
  end
72
178
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack-mini-profiler"
3
- s.version = "0.1.1"
3
+ s.version = "0.1.6"
4
4
  s.summary = "Profiles loading speed for rack applications."
5
5
  s.authors = ["Aleks Totic","Sam Saffron", "Robin Ward"]
6
6
  s.date = "2012-04-02"
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  ].concat( Dir.glob('lib/**/*').reject {|f| File.directory?(f) || f =~ /~$/ } )
13
13
  s.extra_rdoc_files = [
14
14
  "README.md",
15
- "CHANGELOG.md"
15
+ "CHANGELOG"
16
16
  ]
17
17
  s.add_runtime_dependency 'rack', '>= 1.1.3'
18
18
  if RUBY_VERSION < "1.9"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-mini-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -84,14 +84,17 @@ executables: []
84
84
  extensions: []
85
85
  extra_rdoc_files:
86
86
  - README.md
87
- - CHANGELOG.md
87
+ - CHANGELOG
88
88
  files:
89
89
  - rack-mini-profiler.gemspec
90
90
  - lib/mini_profiler/sql_timer_struct.rb
91
91
  - lib/mini_profiler/request_timer_struct.rb
92
92
  - lib/mini_profiler/timer_struct.rb
93
93
  - lib/mini_profiler/page_timer_struct.rb
94
+ - lib/mini_profiler/context.rb
95
+ - lib/mini_profiler/config.rb
94
96
  - lib/mini_profiler/body_add_proxy.rb
97
+ - lib/mini_profiler/profiling_methods.rb
95
98
  - lib/mini_profiler/client_timer_struct.rb
96
99
  - lib/mini_profiler/profiler.rb
97
100
  - lib/mini_profiler/storage/memory_store.rb
@@ -114,7 +117,7 @@ files:
114
117
  - lib/mini_profiler_rails/railtie.rb
115
118
  - lib/patches/sql_patches.rb
116
119
  - README.md
117
- - CHANGELOG.md
120
+ - CHANGELOG
118
121
  homepage: http://miniprofiler.com
119
122
  licenses: []
120
123
  post_install_message:
@@ -129,7 +132,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
132
  version: '0'
130
133
  segments:
131
134
  - 0
132
- hash: -779964803
135
+ hash: -974819475
133
136
  required_rubygems_version: !ruby/object:Gem::Requirement
134
137
  none: false
135
138
  requirements:
@@ -138,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
141
  version: '0'
139
142
  segments:
140
143
  - 0
141
- hash: -779964803
144
+ hash: -974819475
142
145
  requirements: []
143
146
  rubyforge_project:
144
147
  rubygems_version: 1.8.24
@@ -1,7 +0,0 @@
1
- 28-June-2012 - Sam
2
-
3
- * Started change log
4
- * Corrected profiler so it properly captures POST requests (was supressing non 200s)
5
- * Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
6
- * Fixed bug where unviewed missing ids never got cleared
7
- * Supress all '/assets/' in the rails tie (makes debugging easier)