miniprofiler 0.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +32 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +64 -0
  5. data/README.md +110 -0
  6. data/Rakefile +40 -0
  7. data/autotest/discover.rb +2 -0
  8. data/lib/mini_profiler/body_add_proxy.rb +45 -0
  9. data/lib/mini_profiler/client_timer_struct.rb +76 -0
  10. data/lib/mini_profiler/config.rb +52 -0
  11. data/lib/mini_profiler/context.rb +10 -0
  12. data/lib/mini_profiler/page_timer_struct.rb +53 -0
  13. data/lib/mini_profiler/profiler.rb +405 -0
  14. data/lib/mini_profiler/profiling_methods.rb +73 -0
  15. data/lib/mini_profiler/request_timer_struct.rb +96 -0
  16. data/lib/mini_profiler/sql_timer_struct.rb +48 -0
  17. data/lib/mini_profiler/storage/abstract_store.rb +27 -0
  18. data/lib/mini_profiler/storage/file_store.rb +108 -0
  19. data/lib/mini_profiler/storage/memory_store.rb +68 -0
  20. data/lib/mini_profiler/storage/redis_store.rb +44 -0
  21. data/lib/mini_profiler/timer_struct.rb +31 -0
  22. data/lib/mini_profiler_rails/railtie.rb +84 -0
  23. data/lib/patches/sql_patches.rb +185 -0
  24. data/lib/rack-mini-profiler.rb +6 -0
  25. data/rack-mini-profiler.gemspec +23 -0
  26. data/spec/components/body_add_proxy_spec.rb +90 -0
  27. data/spec/components/client_timer_struct_spec.rb +165 -0
  28. data/spec/components/file_store_spec.rb +47 -0
  29. data/spec/components/memory_store_spec.rb +40 -0
  30. data/spec/components/page_timer_struct_spec.rb +33 -0
  31. data/spec/components/profiler_spec.rb +126 -0
  32. data/spec/components/redis_store_spec.rb +44 -0
  33. data/spec/components/request_timer_struct_spec.rb +148 -0
  34. data/spec/components/sql_timer_struct_spec.rb +63 -0
  35. data/spec/components/timer_struct_spec.rb +47 -0
  36. data/spec/fixtures/simple_client_request.yml +17 -0
  37. data/spec/fixtures/weird_client_request.yml +13 -0
  38. data/spec/integration/mini_profiler_spec.rb +142 -0
  39. data/spec/spec_helper.rb +31 -0
  40. data/spec/support/expand_each_to_matcher.rb +8 -0
  41. data/test_old/config.ru +41 -0
  42. metadata +155 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ lib/html
2
+ pkg/
3
+ tmp/
4
+ *.gem
data/CHANGELOG ADDED
@@ -0,0 +1,32 @@
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
+
27
+ 18-July-2012 - Sam
28
+
29
+ * Added First Paint time for chrome
30
+ * Bug fix to ensure non Rails installs have mini profiler
31
+ * Version 0.1.7
32
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'therubyracer', :require => 'v8'
6
+ gem 'less'
7
+
8
+ group :test do
9
+ gem 'rake'
10
+ gem 'rack'
11
+ gem 'rspec'
12
+ gem 'ZenTest'
13
+ gem 'autotest'
14
+ gem 'redis'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ miniprofiler (0.1.7.1)
5
+ rack (>= 1.1.3)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ ZenTest (4.8.1)
11
+ activemodel (3.2.6)
12
+ activesupport (= 3.2.6)
13
+ builder (~> 3.0.0)
14
+ activerecord (3.2.6)
15
+ activemodel (= 3.2.6)
16
+ activesupport (= 3.2.6)
17
+ arel (~> 3.0.2)
18
+ tzinfo (~> 0.3.29)
19
+ activesupport (3.2.6)
20
+ i18n (~> 0.6)
21
+ multi_json (~> 1.0)
22
+ arel (3.0.2)
23
+ autotest (4.4.6)
24
+ ZenTest (>= 4.4.1)
25
+ builder (3.0.0)
26
+ commonjs (0.2.6)
27
+ diff-lcs (1.1.3)
28
+ i18n (0.6.0)
29
+ less (2.2.1)
30
+ commonjs (~> 0.2.6)
31
+ libv8 (3.3.10.4)
32
+ multi_json (1.3.6)
33
+ rack (1.4.1)
34
+ rack-test (0.6.1)
35
+ rack (>= 1.0)
36
+ rake (0.9.2.2)
37
+ redis (3.0.1)
38
+ rspec (2.11.0)
39
+ rspec-core (~> 2.11.0)
40
+ rspec-expectations (~> 2.11.0)
41
+ rspec-mocks (~> 2.11.0)
42
+ rspec-core (2.11.0)
43
+ rspec-expectations (2.11.1)
44
+ diff-lcs (~> 1.1.3)
45
+ rspec-mocks (2.11.1)
46
+ therubyracer (0.10.1)
47
+ libv8 (~> 3.3.10)
48
+ tzinfo (0.3.33)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ ZenTest
55
+ activerecord (~> 3.0)
56
+ autotest
57
+ less
58
+ miniprofiler!
59
+ rack
60
+ rack-test
61
+ rake
62
+ redis
63
+ rspec
64
+ therubyracer
data/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # NOTE FOR THIS GEM FORK
2
+
3
+ This is a fork the Ruby folder of https://github.com/SamSaffron/MiniProfiler which includes some quick fixes to make the original rack-mini-profiler gem a little more usable. I will consolidate any useful changes here into pull requests for the original repo.
4
+
5
+ * Add `gem 'miniprofiler'` to your Gemfile (install of 'rack-mini-profiler')
6
+ * `miniprofiler`'s version uses `x.y.z.t` syntax in order to more easily sync with `rack-mini-profiler`'s `x.y.z` SemVer versioning. I will increase `t` whenever I make a patch
7
+ * This gem fork will work in staging, not just development and production
8
+ * Gem release date will be correct (as of now 'rack-mini-profiler' hardcodes the release date to be 04/02/2012, which is very confusing: https://rubygems.org/gems/rack-mini-profiler -- I will report to them)
9
+ * Allow turning off loading jquery if the app already uses jquery
10
+ * More to come
11
+
12
+ # Original README below:
13
+
14
+ # rack-mini-profiler
15
+
16
+ Middleware that displays speed badge for every html page. Designed to work both in production and in development.
17
+
18
+ ## Using rack-mini-profiler in your app
19
+
20
+ Install/add to Gemfile
21
+
22
+ ```ruby
23
+ gem 'rack-mini-profiler'
24
+ ```
25
+ Using Rails:
26
+
27
+ All you have to do is include the Gem and you're good to go in development.
28
+
29
+ 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.
30
+
31
+ For example:
32
+
33
+ ```ruby
34
+ # A hook in your ApplicationController
35
+ def authorize
36
+ if current_user.is_admin?
37
+ Rack::MiniProfiler.authorize_request
38
+ end
39
+ end
40
+ ````
41
+
42
+
43
+ Using Builder:
44
+
45
+ ```ruby
46
+ require 'rack-mini-profiler'
47
+ builder = Rack::Builder.new do
48
+ use Rack::MiniProfiler
49
+
50
+ map('/') { run get }
51
+ end
52
+ ```
53
+
54
+ Using Sinatra:
55
+
56
+ ```ruby
57
+ require 'rack-mini-profiler'
58
+ class MyApp < Sinatra::Base
59
+ use Rack::MiniProfiler
60
+ end
61
+ ```
62
+
63
+ ## Storage
64
+
65
+ By default, rack-mini-profiler stores its results in a memory store:
66
+
67
+ ```ruby
68
+ # our default
69
+ Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
70
+ ```
71
+
72
+ There are 2 other available storage engines, `RedisStore` and `FileStore`.
73
+
74
+ MemoryStore is stores results in a processes heap - something that does not work well in a multi process environment.
75
+ FileStore stores results in the file system - something that may not work well in a multi machine environment.
76
+
77
+ Additionally you may implement an AbstractStore for your own provider.
78
+
79
+ Rails hooks up a FileStore for all environments.
80
+
81
+ ## Running the Specs
82
+
83
+ ```
84
+ $ rake build
85
+ $ rake spec
86
+ ```
87
+
88
+ Additionally you can also run `autotest` if you like.
89
+
90
+ ## Configuration Options
91
+
92
+ You can set configuration options using the configuration accessor on Rack::MiniProfiler:
93
+
94
+ ```
95
+ # Have Mini Profiler show up on the right
96
+ Rack::MiniProfiler.config.position = 'right'
97
+ ```
98
+
99
+ In a Rails app, this can be done conveniently in an initializer such as config/initializers/mini_profiler.rb.
100
+
101
+ ## Available Options
102
+
103
+ * 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.
104
+ * position - Can either be 'right' or 'left'. Default is 'left'.
105
+ * 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.
106
+
107
+ ## Special query strings
108
+
109
+ 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.
110
+
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ # Rakefile
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup(:default, :test)
5
+ require "bundler/gem_tasks"
6
+
7
+ task :default => [:spec]
8
+
9
+ require 'rspec/core'
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec) do |spec|
12
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
+ end
14
+
15
+ desc "builds a gem"
16
+ task :build => :compile_less do
17
+ `gem build rack-mini-profiler.gemspec 1>&2`
18
+ end
19
+
20
+ desc "compile less"
21
+ task :compile_less => :copy_files do
22
+ `lessc lib/html/includes.less > lib/html/includes.css`
23
+ end
24
+
25
+
26
+ desc "copy files from other parts of the tree"
27
+ task :copy_files do
28
+ `rm -R -f lib/html && mkdir lib/html 1>&2`
29
+ path = File.expand_path('../StackExchange.Profiling/UI')
30
+ `ln -s #{path}/includes.less lib/html/includes.less`
31
+ `ln -s #{path}/includes.js lib/html/includes.js`
32
+ `ln -s #{path}/includes.tmpl lib/html/includes.tmpl`
33
+ `ln -s #{path}/jquery.1.7.1.js lib/html/jquery.1.7.1.js`
34
+ `ln -s #{path}/jquery.tmpl.js lib/html/jquery.tmpl.js`
35
+ `ln -s #{path}/list.css lib/html/list.css`
36
+ `ln -s #{path}/list.js lib/html/list.js`
37
+ `ln -s #{path}/list.tmpl lib/html/list.tmpl`
38
+ `ln -s #{path}/include.partial.html lib/html/profile_handler.js`
39
+ end
40
+
@@ -0,0 +1,2 @@
1
+ Autotest.add_discovery { "rspec2" }
2
+
@@ -0,0 +1,45 @@
1
+ module Rack
2
+ class MiniProfiler
3
+
4
+ # This class acts as a proxy to the Body so that we can
5
+ # safely append to the end without knowing about the internals
6
+ # of the body class.
7
+ class BodyAddProxy
8
+ def initialize(body, additional_text)
9
+ @body = body
10
+ @additional_text = additional_text
11
+ end
12
+
13
+ def respond_to?(*args)
14
+ super or @body.respond_to?(*args)
15
+ end
16
+
17
+ def method_missing(*args, &block)
18
+ @body.__send__(*args, &block)
19
+ end
20
+
21
+ # In the case of to_str we don't want to use method_missing as it might avoid
22
+ # a call to each (such as in Rack::Test)
23
+ def to_str
24
+ result = ""
25
+ each {|token| result << token}
26
+ result
27
+ end
28
+
29
+ def each(&block)
30
+
31
+ # In ruby 1.9 we don't support String#each
32
+ if @body.is_a?(String)
33
+ yield @body
34
+ else
35
+ @body.each(&block)
36
+ end
37
+
38
+ yield @additional_text
39
+ self
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,76 @@
1
+ require 'mini_profiler/timer_struct'
2
+
3
+ module Rack
4
+ class MiniProfiler
5
+
6
+ # This class holds the client timings
7
+ class ClientTimerStruct < TimerStruct
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
+
22
+ def initialize(env={})
23
+ super
24
+ end
25
+
26
+ def init_from_form_data(env, page_struct)
27
+ timings = []
28
+ clientTimes, clientPerf, baseTime = nil
29
+ form = env['rack.request.form_hash']
30
+
31
+ clientPerf = form['clientPerformance'] if form
32
+ clientTimes = clientPerf['timing'] if clientPerf
33
+
34
+ baseTime = clientTimes['navigationStart'].to_i if clientTimes
35
+ return unless clientTimes && baseTime
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
+
57
+ clientTimes.keys.find_all{|k| k =~ /Start$/ }.each do |k|
58
+ start = clientTimes[k].to_i - baseTime
59
+ finish = clientTimes[k.sub(/Start$/, "End")].to_i - baseTime
60
+ duration = 0
61
+ duration = finish - start if finish > start
62
+ name = k.sub(/Start$/, "").split(/(?=[A-Z])/).map{|s| s.capitalize}.join(' ')
63
+ timings.push({"Name" => name, "Start" => start, "Duration" => duration}) if start >= 0
64
+ end
65
+
66
+ clientTimes.keys.find_all{|k| !(k =~ /(End|Start)$/)}.each do |k|
67
+ timings.push("Name" => k, "Start" => clientTimes[k].to_i - baseTime, "Duration" => -1)
68
+ end
69
+
70
+ self['RedirectCount'] = env['rack.request.form_hash']['clientPerformance']['navigation']['redirectCount']
71
+ self['Timings'] = timings
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,52 @@
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, :use_existing_jquery
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
+ @use_existing_jquery = false
34
+ self
35
+ }
36
+ end
37
+
38
+ def merge!(config)
39
+ return unless config
40
+ if Hash === config
41
+ config.each{|k,v| instance_variable_set "@#{k}",v}
42
+ else
43
+ self.class.attributes.each{ |k|
44
+ v = config.send k
45
+ instance_variable_set "@#{k}", v if v
46
+ }
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ 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
@@ -0,0 +1,53 @@
1
+ require 'mini_profiler/timer_struct'
2
+
3
+ module Rack
4
+ class MiniProfiler
5
+
6
+ # PageTimerStruct
7
+ # Root: RequestTimer
8
+ # :has_many RequestTimer children
9
+ # :has_many SqlTimer children
10
+ class PageTimerStruct < TimerStruct
11
+ def initialize(env)
12
+ super("Id" => MiniProfiler.generate_id,
13
+ "Name" => env['PATH_INFO'],
14
+ "Started" => (Time.now.to_f * 1000).to_i,
15
+ "MachineName" => env['SERVER_NAME'],
16
+ "Level" => 0,
17
+ "User" => "unknown user",
18
+ "HasUserViewed" => false,
19
+ "ClientTimings" => ClientTimerStruct.new,
20
+ "DurationMilliseconds" => 0,
21
+ "HasTrivialTimings" => true,
22
+ "HasAllTrivialTimigs" => false,
23
+ "TrivialDurationThresholdMilliseconds" => 2,
24
+ "Head" => nil,
25
+ "DurationMillisecondsInSql" => 0,
26
+ "HasSqlTimings" => true,
27
+ "HasDuplicateSqlTimings" => false,
28
+ "ExecutedReaders" => 0,
29
+ "ExecutedScalars" => 0,
30
+ "ExecutedNonQueries" => 0)
31
+ name = "#{env['REQUEST_METHOD']} http://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
32
+ self['Root'] = RequestTimerStruct.createRoot(name, self)
33
+ end
34
+
35
+ def duration_ms
36
+ @attributes['Root']['DurationMilliseconds']
37
+ end
38
+
39
+ def root
40
+ @attributes['Root']
41
+ end
42
+
43
+ def to_json(*a)
44
+ attribs = @attributes.merge(
45
+ "Started" => '/Date(%d)/' % @attributes['Started'],
46
+ "DurationMilliseconds" => @attributes['Root']['DurationMilliseconds']
47
+ )
48
+ ::JSON.generate(attribs, :max_nesting => 100)
49
+ end
50
+ end
51
+
52
+ end
53
+ end