rack-mini-profiler 0.1.1 → 0.1.8

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.
@@ -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
@@ -39,9 +39,14 @@ module Rack
39
39
 
40
40
  me = self
41
41
  Thread.new do
42
- while true do
43
- me.cleanup_cache if MiniProfiler.instance
44
- sleep(3600)
42
+ begin
43
+ while true do
44
+ # TODO: a sane retry count before bailing
45
+ me.cleanup_cache
46
+ sleep(3600)
47
+ end
48
+ rescue
49
+ # don't crash the thread, we can clean up next time
45
50
  end
46
51
  end
47
52
  end
@@ -83,10 +88,6 @@ module Rack
83
88
  }
84
89
  end
85
90
 
86
-
87
- private
88
-
89
-
90
91
  def cleanup_cache
91
92
  files = Dir.entries(@path)
92
93
  @timer_struct_lock.synchronize {
@@ -52,10 +52,6 @@ module Rack
52
52
  }
53
53
  end
54
54
 
55
-
56
- private
57
-
58
-
59
55
  def cleanup_cache
60
56
  expire_older_than = ((Time.now.to_f - MiniProfiler::MemoryStore::EXPIRE_TIMER_CACHE) * 1000).to_i
61
57
  @timer_struct_lock.synchronize {
@@ -1,33 +1,84 @@
1
+ require 'fileutils'
2
+
1
3
  module MiniProfilerRails
4
+
2
5
  class Railtie < ::Rails::Railtie
3
6
 
4
7
  initializer "rack_mini_profiler.configure_rails_initialization" do |app|
8
+ c = Rack::MiniProfiler.config
5
9
 
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\//)
10
+ # By default, only show the MiniProfiler in development mode, in production allow profiling if post_authorize_cb is set
11
+ c.pre_authorize_cb = lambda { |env|
12
+ Rails.env.development? || Rails.env.production?
9
13
  }
10
14
 
15
+ if Rails.env.development?
16
+ c.skip_paths ||= []
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
+
11
25
  # The file store is just so much less flaky
12
26
  tmp = Rails.root.to_s + "/tmp/miniprofiler"
13
- Dir::mkdir(tmp) unless File.exists?(tmp)
14
-
15
- Rack::MiniProfiler.configuration[:storage_options] = {:path => tmp}
16
- Rack::MiniProfiler.configuration[:storage] = Rack::MiniProfiler::FileStore
27
+ FileUtils.mkdir_p(tmp) unless File.exists?(tmp)
28
+
29
+ c.storage_options = {:path => tmp}
30
+ c.storage = Rack::MiniProfiler::FileStore
17
31
 
18
32
  # 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)/
33
+ c.backtrace_remove = Rails.root.to_s + "/"
34
+ c.backtrace_filter = /^\/?(app|config|lib|test)/
35
+ c.skip_schema_queries = Rails.env != 'production'
21
36
 
22
37
  # Install the Middleware
23
- app.middleware.insert_before 'Rack::Lock', 'Rack::MiniProfiler'
38
+ app.middleware.insert(0, Rack::MiniProfiler)
24
39
 
25
40
  # Attach to various Rails methods
26
41
  ::Rack::MiniProfiler.profile_method(ActionController::Base, :process) {|action| "Executing action: #{action}"}
27
42
  ::Rack::MiniProfiler.profile_method(ActionView::Template, :render) {|x,y| "Rendering: #{@virtual_path}"}
28
43
 
29
-
30
44
  end
31
45
 
46
+ # TODO: Implement something better here
47
+ # config.after_initialize do
48
+ #
49
+ # class ::ActionView::Helpers::AssetTagHelper::JavascriptIncludeTag
50
+ # alias_method :asset_tag_orig, :asset_tag
51
+ # def asset_tag(source,options)
52
+ # current = Rack::MiniProfiler.current
53
+ # return asset_tag_orig(source,options) unless current
54
+ # wrapped = ""
55
+ # unless current.mpt_init
56
+ # current.mpt_init = true
57
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
58
+ # end
59
+ # name = source.split('/')[-1]
60
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
61
+ # wrapped
62
+ # end
63
+ # end
64
+
65
+ # class ::ActionView::Helpers::AssetTagHelper::StylesheetIncludeTag
66
+ # alias_method :asset_tag_orig, :asset_tag
67
+ # def asset_tag(source,options)
68
+ # current = Rack::MiniProfiler.current
69
+ # return asset_tag_orig(source,options) unless current
70
+ # wrapped = ""
71
+ # unless current.mpt_init
72
+ # current.mpt_init = true
73
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
74
+ # end
75
+ # name = source.split('/')[-1]
76
+ # wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
77
+ # wrapped
78
+ # end
79
+ # end
80
+
81
+ # end
82
+
32
83
  end
33
84
  end
@@ -1,17 +1,136 @@
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
5
14
  false
6
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
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
7
58
  end
8
59
 
9
- if SqlPatches.class_exists? "Sequel::Database" then
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
+
95
+ def exec(*args,&blk)
96
+ current = ::Rack::MiniProfiler.current
97
+ return exec_without_profiling(*args,&blk) unless current
98
+
99
+ start = Time.now
100
+ result = exec_without_profiling(*args,&blk)
101
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
102
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
103
+
104
+ result
105
+ end
106
+
107
+ def async_exec(*args,&blk)
108
+ current = ::Rack::MiniProfiler.current
109
+ return exec_without_profiling(*args,&blk) unless current
110
+
111
+ start = Time.now
112
+ result = exec_without_profiling(*args,&blk)
113
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
114
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(args[0], elapsed_time))
115
+
116
+ result
117
+ end
118
+
119
+ alias_method :query, :exec
120
+ end
121
+
122
+ SqlPatches.patched = true
123
+ end
124
+
125
+
126
+
127
+ # Fallback for sequel
128
+ if SqlPatches.class_exists?("Sequel::Database") && !SqlPatches.patched?
10
129
  module Sequel
11
130
  class Database
12
131
  alias_method :log_duration_original, :log_duration
13
132
  def log_duration(duration, message)
14
- ::Rack::MiniProfiler.instance.record_sql(message, duration) if ::Rack::MiniProfiler.instance
133
+ ::Rack::MiniProfiler.record_sql(message, duration)
15
134
  log_duration_original(duration, message)
16
135
  end
17
136
  end
@@ -20,53 +139,47 @@ end
20
139
 
21
140
 
22
141
  ## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
23
- module Rack
24
- class MiniProfiler
25
- module ActiveRecordInstrumentation
26
- def self.included(instrumented_class)
27
- instrumented_class.class_eval do
28
- unless instrumented_class.method_defined?(:log_without_miniprofiler)
29
- alias_method :log_without_miniprofiler, :log
30
- alias_method :log, :log_with_miniprofiler
31
- protected :log
142
+ ## fallback for alls sorts of weird dbs
143
+ if SqlPatches.module_exists?('ActiveRecord')
144
+ module Rack
145
+ class MiniProfiler
146
+ module ActiveRecordInstrumentation
147
+ def self.included(instrumented_class)
148
+ instrumented_class.class_eval do
149
+ unless instrumented_class.method_defined?(:log_without_miniprofiler)
150
+ alias_method :log_without_miniprofiler, :log
151
+ alias_method :log, :log_with_miniprofiler
152
+ protected :log
153
+ end
32
154
  end
33
155
  end
34
- end
35
156
 
36
- def log_with_miniprofiler(*args, &block)
37
- sql, name, binds = args
38
- t0 = Time.now
39
- rval = log_without_miniprofiler(*args, &block)
157
+ def log_with_miniprofiler(*args, &block)
158
+ current = ::Rack::MiniProfiler.current
159
+ return log_without_miniprofiler(*args, &block) unless current
40
160
 
41
- # Get our MP Instance
42
- instance = ::Rack::MiniProfiler.instance
43
- return rval unless instance
161
+ sql, name, binds = args
162
+ t0 = Time.now
163
+ rval = log_without_miniprofiler(*args, &block)
164
+
165
+ # Don't log schema queries if the option is set
166
+ return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
44
167
 
45
- # Don't log schema queries if the option is set
46
- return rval if instance.options[:skip_schema_queries] and name =~ /SCHEMA/
47
-
48
- elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
49
- instance.record_sql(sql, elapsed_time)
50
- rval
168
+ elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
169
+ Rack::MiniProfiler.record_sql(sql, elapsed_time)
170
+ rval
171
+ end
51
172
  end
52
173
  end
53
- end
54
174
 
55
- def self.insert_instrumentation
56
- ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
57
- include ::Rack::MiniProfiler::ActiveRecordInstrumentation
175
+ def self.insert_instrumentation
176
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
177
+ include ::Rack::MiniProfiler::ActiveRecordInstrumentation
178
+ end
58
179
  end
59
- end
60
180
 
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
181
+ if defined?(::Rails) && !SqlPatches.patched?
68
182
  insert_instrumentation
69
183
  end
70
184
  end
71
185
  end
72
-
@@ -1,6 +1,6 @@
1
- require File.expand_path('mini_profiler/profiler', File.dirname(__FILE__) )
2
- require File.expand_path('patches/sql_patches', File.dirname(__FILE__) )
1
+ require 'mini_profiler/profiler'
2
+ require 'patches/sql_patches'
3
3
 
4
4
  if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3
5
- require File.expand_path('mini_profiler_rails/railtie', File.dirname(__FILE__) )
5
+ require 'mini_profiler_rails/railtie'
6
6
  end
@@ -1,9 +1,8 @@
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.8"
4
4
  s.summary = "Profiles loading speed for rack applications."
5
5
  s.authors = ["Aleks Totic","Sam Saffron", "Robin Ward"]
6
- s.date = "2012-04-02"
7
6
  s.description = "Page loading speed displayed on every page. Optimize while you develop, performance is a feature."
8
7
  s.email = "sam.saffron@gmail.com"
9
8
  s.homepage = "http://miniprofiler.com"
@@ -12,11 +11,11 @@ Gem::Specification.new do |s|
12
11
  ].concat( Dir.glob('lib/**/*').reject {|f| File.directory?(f) || f =~ /~$/ } )
13
12
  s.extra_rdoc_files = [
14
13
  "README.md",
15
- "CHANGELOG.md"
14
+ "CHANGELOG"
16
15
  ]
17
- s.add_runtime_dependency 'rack', '>= 1.1.3'
16
+ s.add_runtime_dependency 'rack', '>= 1.1.3'
18
17
  if RUBY_VERSION < "1.9"
19
- s.add_runtime_dependency 'json', '>= 1.6'
18
+ s.add_runtime_dependency 'json', '>= 1.6'
20
19
  end
21
20
 
22
21
  s.add_development_dependency 'rake'
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.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-04-02 00:00:00.000000000 Z
14
+ date: 2012-07-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rack
@@ -84,14 +84,16 @@ 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/body_add_proxy.rb
94
+ - lib/mini_profiler/context.rb
95
+ - lib/mini_profiler/config.rb
96
+ - lib/mini_profiler/profiling_methods.rb
95
97
  - lib/mini_profiler/client_timer_struct.rb
96
98
  - lib/mini_profiler/profiler.rb
97
99
  - lib/mini_profiler/storage/memory_store.rb
@@ -104,7 +106,6 @@ files:
104
106
  - lib/html/share.html
105
107
  - lib/html/includes.less
106
108
  - lib/html/list.css
107
- - lib/html/MiniProfilerHandler.cs
108
109
  - lib/html/includes.js
109
110
  - lib/html/jquery.tmpl.js
110
111
  - lib/html/list.tmpl
@@ -114,7 +115,7 @@ files:
114
115
  - lib/mini_profiler_rails/railtie.rb
115
116
  - lib/patches/sql_patches.rb
116
117
  - README.md
117
- - CHANGELOG.md
118
+ - CHANGELOG
118
119
  homepage: http://miniprofiler.com
119
120
  licenses: []
120
121
  post_install_message:
@@ -129,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
130
  version: '0'
130
131
  segments:
131
132
  - 0
132
- hash: -779964803
133
+ hash: -902573215
133
134
  required_rubygems_version: !ruby/object:Gem::Requirement
134
135
  none: false
135
136
  requirements:
@@ -138,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
139
  version: '0'
139
140
  segments:
140
141
  - 0
141
- hash: -779964803
142
+ hash: -902573215
142
143
  requirements: []
143
144
  rubyforge_project:
144
145
  rubygems_version: 1.8.24
data/CHANGELOG.md DELETED
@@ -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)