rails_mini_profiler 0.7.0 → 0.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/controllers/rails_mini_profiler/application_controller.rb +0 -9
  4. data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +16 -0
  5. data/app/models/rails_mini_profiler/profiled_request.rb +1 -1
  6. data/app/models/rails_mini_profiler/trace.rb +0 -15
  7. data/app/presenters/rails_mini_profiler/controller_trace_presenter.rb +10 -2
  8. data/app/presenters/rails_mini_profiler/instantiation_trace_presenter.rb +15 -3
  9. data/app/presenters/rails_mini_profiler/render_partial_trace_presenter.rb +6 -2
  10. data/app/presenters/rails_mini_profiler/render_template_trace_presenter.rb +6 -2
  11. data/app/presenters/rails_mini_profiler/sequel_trace_presenter.rb +16 -4
  12. data/app/presenters/rails_mini_profiler/trace_presenter.rb +1 -1
  13. data/app/views/rails_mini_profiler/profiled_requests/show/_trace.html.erb +1 -1
  14. data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +1 -1
  15. data/lib/rails_mini_profiler/badge.rb +20 -11
  16. data/lib/rails_mini_profiler/configuration/user_interface.rb +10 -2
  17. data/lib/rails_mini_profiler/configuration.rb +4 -0
  18. data/lib/rails_mini_profiler/middleware.rb +10 -10
  19. data/lib/rails_mini_profiler/request_context.rb +22 -18
  20. data/lib/rails_mini_profiler/request_wrapper.rb +12 -55
  21. data/lib/rails_mini_profiler/response_wrapper.rb +21 -17
  22. data/lib/rails_mini_profiler/{tracing → tracers}/controller_tracer.rb +15 -1
  23. data/lib/rails_mini_profiler/tracers/instantiation_tracer.rb +17 -0
  24. data/lib/rails_mini_profiler/{tracing → tracers}/null_trace.rb +1 -1
  25. data/lib/rails_mini_profiler/tracers/registry.rb +76 -0
  26. data/lib/rails_mini_profiler/tracers/rmp_tracer.rb +17 -0
  27. data/lib/rails_mini_profiler/{tracing → tracers}/sequel_tracer.rb +15 -1
  28. data/lib/rails_mini_profiler/{tracing → tracers}/sequel_tracker.rb +4 -1
  29. data/lib/rails_mini_profiler/{tracing → tracers}/subscriptions.rb +6 -12
  30. data/lib/rails_mini_profiler/{tracing → tracers}/trace.rb +2 -2
  31. data/lib/rails_mini_profiler/tracers/trace_factory.rb +27 -0
  32. data/lib/rails_mini_profiler/{tracing → tracers}/tracer.rb +15 -1
  33. data/lib/rails_mini_profiler/tracers/view_tracer.rb +29 -0
  34. data/lib/rails_mini_profiler/tracers.rb +14 -0
  35. data/lib/rails_mini_profiler/version.rb +1 -1
  36. data/lib/rails_mini_profiler.rb +1 -1
  37. metadata +15 -18
  38. data/app/models/rails_mini_profiler/controller_trace.rb +0 -37
  39. data/app/models/rails_mini_profiler/instantiation_trace.rb +0 -37
  40. data/app/models/rails_mini_profiler/render_partial_trace.rb +0 -37
  41. data/app/models/rails_mini_profiler/render_template_trace.rb +0 -37
  42. data/app/models/rails_mini_profiler/rmp_trace.rb +0 -35
  43. data/app/models/rails_mini_profiler/sequel_trace.rb +0 -37
  44. data/lib/rails_mini_profiler/tracing/trace_factory.rb +0 -37
  45. data/lib/rails_mini_profiler/tracing/view_tracer.rb +0 -12
  46. data/lib/rails_mini_profiler/tracing.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb1212a4d90c46143193b2173e9e136aa6757a74a6591137cba33169235d175d
4
- data.tar.gz: f799849a5d978c2c22d39b3fa1f4be6c02541f75b7a2312d98a510a1d69a195b
3
+ metadata.gz: '08b93a903a5bb3b16310b3a918a1a52555a9ce5fc2a60624d0f2bb8158e3ddb5'
4
+ data.tar.gz: 88af5220a54c4f91e4506cd0423a853512dcc67235c65a22990d1c4fc1d92c25
5
5
  SHA512:
6
- metadata.gz: ae143e874778e4af9560e5b6521003c5d4933ec86ffe5900a56c57b93791a3d0faa3ac18294cecccac12048dc35c38a70aa7a53ffa91b12d2025a89c0acc0384
7
- data.tar.gz: f2a8ca075571593f1cce9d1b59910ea5aac8f95a06c277298be9e0e93be5dcd1b013fbaefbef22bf173f6e2db40fed29068cfda44d422aa372cdde30818ec9cf
6
+ metadata.gz: 2a41fec13f04188e895769fcb17004fdd6436aaddd8942ff4657beaffb7c0f4b63ca64d60f9877d119c1e363194ebd3c97e629216d0bf675fceb82cd49b6dcda
7
+ data.tar.gz: f5c81dbc3b627e48a0d9097fb587b37c2c299476adb87d01ace6c697e234b32f8fceee942045656f82f8c4d6ef6c082e58ad2f5619ccf2b4114b32764dae8c8f
data/README.md CHANGED
@@ -153,7 +153,7 @@ Rails Mini Profiler allows you to configure various UI features.
153
153
  |---------------------|---------------------------|-------------------------------------------------------------------------------------------------|
154
154
  | `badge_enabled` | `true` | Should the hedgehog 🦔 badge be injected into pages? |
155
155
  | `badge_position` | `'top-left'` | Where to display the badge. Options are `'top-left', 'top-right', 'bottom-left, 'bottom-right'` |
156
- | `base_controller` | `ApplicationController` | Which controller UI controllers should inherit from. |
156
+ | `base_controller` | `ApplicationController` | Which controller UI controllers should inherit from. |
157
157
  | `page_size` | `25` | The page size for lists shown in the UI. |
158
158
  | `webpacker_enabled` | `true` | Use Webpacker if available? Disable to fall back to the asset pipeline. |
159
159
 
@@ -6,15 +6,6 @@ module RailsMiniProfiler
6
6
 
7
7
  before_action :check_rmp_user
8
8
 
9
- protected
10
-
11
- def present(model, presenter_class = nil, **kwargs)
12
- klass = presenter_class || "RailsMiniProfiler::#{model.class.to_s.demodulize}Presenter".constantize
13
- presenter = klass.new(model, view_context, **kwargs)
14
- yield(presenter) if block_given?
15
- presenter
16
- end
17
-
18
9
  private
19
10
 
20
11
  def handle(error, status = 500)
@@ -67,6 +67,22 @@ module RailsMiniProfiler
67
67
  @configuration ||= RailsMiniProfiler.configuration
68
68
  end
69
69
 
70
+ def registry
71
+ @registry ||= RailsMiniProfiler::Tracers::Registry.new(configuration)
72
+ end
73
+
74
+ def present(model, presenter_class = nil, **kwargs)
75
+ klass = presenter_class || presenter_class(model)
76
+ klass.new(model, view_context, **kwargs)
77
+ end
78
+
79
+ def presenter_class(model)
80
+ return ProfiledRequestPresenter if model.is_a?(ProfiledRequest)
81
+
82
+ presenters = registry.presenters
83
+ presenters[model.name] || TracePresenter
84
+ end
85
+
70
86
  def payload_column
71
87
  if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
72
88
  # Cast json field to text to have access to the LIKE operator
@@ -43,7 +43,7 @@ module RailsMiniProfiler
43
43
  def request=(request)
44
44
  self.request_body = request.body
45
45
  self.request_headers = request.headers
46
- self.request_method = request.method
46
+ self.request_method = request.request_method
47
47
  self.request_path = request.path
48
48
  self.request_query_string = request.query_string
49
49
  end
@@ -23,24 +23,9 @@
23
23
  module RailsMiniProfiler
24
24
  class Trace < RailsMiniProfiler::ApplicationRecord
25
25
  self.table_name = RailsMiniProfiler.storage_configuration.traces_table
26
- self.inheritance_column = :name
27
26
 
28
27
  belongs_to :profiled_request,
29
28
  class_name: 'RailsMiniProfiler::ProfiledRequest',
30
29
  foreign_key: :rmp_profiled_request_id
31
-
32
- class << self
33
- def find_sti_class(name)
34
- subclasses = {
35
- 'process_action.action_controller' => RailsMiniProfiler::ControllerTrace,
36
- 'sql.active_record' => RailsMiniProfiler::SequelTrace,
37
- 'instantiation.active_record' => RailsMiniProfiler::InstantiationTrace,
38
- 'rails_mini_profiler.total_time' => RailsMiniProfiler::RmpTrace,
39
- 'render_template.action_view' => RailsMiniProfiler::RenderTemplateTrace,
40
- 'render_partial.action_view' => RailsMiniProfiler::RenderPartialTrace
41
- }
42
- subclasses[name] || self
43
- end
44
- end
45
30
  end
46
31
  end
@@ -6,10 +6,18 @@ module RailsMiniProfiler
6
6
  'Action Controller'
7
7
  end
8
8
 
9
- def payload
9
+ def view_runtime
10
+ payload['view_runtime']
11
+ end
12
+
13
+ def db_runtime
14
+ payload['db_runtime']
15
+ end
16
+
17
+ def content
10
18
  content_tag('div') do
11
19
  content_tag('pre', class: 'trace-payload') do
12
- content_tag(:div, "View Time: #{model.view_runtime} ms, DB Time: #{model.db_runtime} ms",
20
+ content_tag(:div, "View Time: #{view_runtime} ms, DB Time: #{db_runtime} ms",
13
21
  class: 'sequel-trace-query')
14
22
  end
15
23
  end
@@ -3,12 +3,24 @@
3
3
  module RailsMiniProfiler
4
4
  class InstantiationTracePresenter < TracePresenter
5
5
  def label
6
- "#{model.class_name} Instantiation"
6
+ "#{class_name} Instantiation"
7
+ end
8
+
9
+ def class_name
10
+ payload['class_name']
11
+ end
12
+
13
+ def record_count
14
+ payload['record_count']
15
+ end
16
+
17
+ def db_runtime
18
+ payload['db_runtime']
7
19
  end
8
20
 
9
21
  def description
10
- record_string = 'Record'.pluralize(model.record_count)
11
- "Instantiated #{model.record_count} #{model.class_name} #{record_string}"
22
+ record_string = 'Record'.pluralize(record_count)
23
+ "Instantiated #{record_count} #{class_name} #{record_string}"
12
24
  end
13
25
  end
14
26
  end
@@ -2,10 +2,14 @@
2
2
 
3
3
  module RailsMiniProfiler
4
4
  class RenderPartialTracePresenter < TracePresenter
5
+ def identifier
6
+ payload['identifier']
7
+ end
8
+
5
9
  def label
6
10
  root = Rails.root.to_s.split('/').to_set
7
- identifier = model.identifier.split('/').to_set
8
- (root ^ identifier).drop(2).join('/').reverse.truncate(30).reverse
11
+ id = identifier.split('/').to_set
12
+ (root ^ id).drop(2).join('/').reverse.truncate(30).reverse
9
13
  end
10
14
  end
11
15
  end
@@ -2,10 +2,14 @@
2
2
 
3
3
  module RailsMiniProfiler
4
4
  class RenderTemplateTracePresenter < TracePresenter
5
+ def identifier
6
+ payload['identifier']
7
+ end
8
+
5
9
  def label
6
10
  root = Rails.root.to_s.split('/').to_set
7
- identifier = model.identifier.split('/').to_set
8
- (root ^ identifier).drop(2).join('/').reverse.truncate(30).reverse
11
+ id = identifier.split('/').to_set
12
+ (root ^ id).drop(2).join('/').reverse.truncate(30).reverse
9
13
  end
10
14
 
11
15
  def description
@@ -6,14 +6,26 @@ module RailsMiniProfiler
6
6
  sql_description
7
7
  end
8
8
 
9
+ def name
10
+ payload['name']
11
+ end
12
+
13
+ def sql
14
+ payload['sql']
15
+ end
16
+
17
+ def binds
18
+ payload['binds']
19
+ end
20
+
9
21
  alias description label
10
22
 
11
- def payload
23
+ def content
12
24
  return nil if transaction?
13
25
 
14
26
  content_tag('div') do
15
27
  content_tag('pre', class: 'trace-payload') do
16
- content_tag(:div, model.sql, class: 'sequel-trace-query')
28
+ content_tag(:div, sql, class: 'sequel-trace-query')
17
29
  end + binding_content
18
30
  end
19
31
  end
@@ -57,9 +69,9 @@ module RailsMiniProfiler
57
69
  end
58
70
 
59
71
  def simple_binds
60
- return [] if model.binds.nil? || model.binds.empty?
72
+ return [] if binds.nil? || binds.empty?
61
73
 
62
- model.binds.each_with_object({}) do |hash, object|
74
+ binds.each_with_object({}) do |hash, object|
63
75
  name = hash['name']
64
76
  value = hash['value']
65
77
  object[name] = value
@@ -18,7 +18,7 @@ module RailsMiniProfiler
18
18
  label
19
19
  end
20
20
 
21
- def payload
21
+ def content
22
22
  nil
23
23
  end
24
24
 
@@ -7,7 +7,7 @@
7
7
  <button class="popover-close">x</button>
8
8
  </section>
9
9
  <section class="popover-body">
10
- <%= trace.payload %>
10
+ <%= trace.content %>
11
11
 
12
12
  <% if trace.backtrace %>
13
13
  <section class="popover-footer">
@@ -22,7 +22,7 @@ RailsMiniProfiler.configure do |config|
22
22
  # Configure the Rails Mini Profiler User Interface
23
23
  # config.ui.badge_enabled = true
24
24
  # config.ui.badge_position = 'top-left'
25
- # config.ui.base_controller = 'ApplicationController'
25
+ # config.ui.base_controller = ApplicationController
26
26
  # config.ui.page_size = 25
27
27
  # config.ui.webpacker_enabled = true
28
28
 
@@ -23,30 +23,39 @@ module RailsMiniProfiler
23
23
  #
24
24
  # @return [ResponseWrapper] The modified response
25
25
  def render
26
- content_type = @original_response.headers['Content-Type']
27
- return @original_response unless content_type =~ %r{text/html}
28
-
29
- return @original_response unless @configuration.ui.badge_enabled
26
+ return @original_response unless render_badge?
30
27
 
31
- modified_response = Rack::Response.new([], @original_response.status, @original_response.headers)
28
+ modified_response = ResponseWrapper.new([], @original_response.status, @original_response.headers)
32
29
  modified_response.write(modified_body)
33
30
  modified_response.finish
34
31
 
35
- response = @original_response.response
36
- response.close if response.respond_to?(:close)
32
+ @original_response.close if @original_response.respond_to?(:close)
37
33
 
38
- ResponseWrapper.new(@original_response.status,
39
- @original_response.headers,
40
- modified_response)
34
+ modified_response
41
35
  end
42
36
 
43
37
  private
44
38
 
39
+ def render_badge?
40
+ content_type = @original_response.headers['Content-Type']
41
+ unless content_type =~ %r{text/html}
42
+ RailsMiniProfiler.logger.debug("badge not rendered, response has content type #{content_type}")
43
+ return false
44
+ end
45
+
46
+ unless @configuration.ui.badge_enabled
47
+ RailsMiniProfiler.logger.debug('badge not rendered, disabled in configuration')
48
+ return false
49
+ end
50
+
51
+ true
52
+ end
53
+
45
54
  # Modify the body of the original response
46
55
  #
47
56
  # @return String The modified body
48
57
  def modified_body
49
- body = @original_response.response.body
58
+ body = @original_response.body
50
59
  index = body.rindex(%r{</body>}i) || body.rindex(%r{</html>}i)
51
60
  if index
52
61
  body.dup.insert(index, badge_content)
@@ -35,10 +35,11 @@ module RailsMiniProfiler
35
35
 
36
36
  attr_accessor :badge_enabled,
37
37
  :badge_position,
38
- :base_controller,
39
38
  :page_size,
40
39
  :webpacker_enabled
41
40
 
41
+ attr_writer :base_controller
42
+
42
43
  def initialize(**kwargs)
43
44
  defaults!
44
45
  kwargs.each { |key, value| instance_variable_set("@#{key}", value) }
@@ -48,11 +49,18 @@ module RailsMiniProfiler
48
49
  def defaults!
49
50
  @badge_enabled = true
50
51
  @badge_position = 'top-left'
51
- @base_controller = default_base_controller
52
+ # We must not set base controller during when the app loads, aka during autoload time, as we are loading
53
+ # constants. Rather, we only load the base controller constants when any engine controllers are first initialized
54
+ # and call #base_controller
55
+ @base_controller = nil
52
56
  @page_size = 25
53
57
  @webpacker_enabled = true
54
58
  end
55
59
 
60
+ def base_controller
61
+ @base_controller ||= default_base_controller
62
+ end
63
+
56
64
  def default_base_controller
57
65
  app_controller_exists = class_exists?('::ApplicationController')
58
66
  return ::ApplicationController if app_controller_exists && ::ApplicationController < ActionController::Base
@@ -18,6 +18,8 @@ module RailsMiniProfiler
18
18
  # @return [Array<String>] a list of regex patterns for paths to skip
19
19
  # @!attribute storage
20
20
  # @return [Storage] the storage configuration
21
+ # @!attribute tracers
22
+ # @return [Array<Symbol>] the list of enabled tracers
21
23
  # @!attribute ui
22
24
  # @return [UserInterface] the ui configuration
23
25
  # @!attribute user_provider
@@ -30,6 +32,7 @@ module RailsMiniProfiler
30
32
  :flamegraph_sample_rate,
31
33
  :skip_paths,
32
34
  :storage,
35
+ :tracers,
33
36
  :ui,
34
37
  :user_provider
35
38
 
@@ -46,6 +49,7 @@ module RailsMiniProfiler
46
49
  @logger = RailsMiniProfiler::Logger.new(Rails.logger)
47
50
  @skip_paths = []
48
51
  @storage = Storage.new
52
+ @tracers = %i[controller instantiation sequel view rmp]
49
53
  @ui = UserInterface.new
50
54
  @user_provider = proc { |env| Rack::Request.new(env).ip }
51
55
  end
@@ -5,21 +5,23 @@ module RailsMiniProfiler
5
5
  def initialize(app)
6
6
  @app = app
7
7
  @config = RailsMiniProfiler.configuration
8
- Tracing::Subscriptions.setup! { |trace| track_trace(trace) }
8
+ @registry = Tracers::Registry.setup!(@config)
9
+ Tracers::Subscriptions.setup!(@registry.tracers.keys) { |trace| track_trace(trace) }
10
+ @trace_factory = Tracers::TraceFactory.new(@registry)
9
11
  end
10
12
 
11
13
  def call(env)
12
- request = RequestWrapper.new(env: env)
14
+ request = RequestWrapper.new(env)
13
15
  request_context = RequestContext.new(request)
14
16
  return @app.call(env) unless Guard.new(request_context).profile?
15
17
 
16
- request_context.profiled_request = ProfiledRequest.new
17
18
  result = with_tracing(request_context) { profile(request_context) }
18
19
  return result unless request_context.authorized?
19
20
 
20
- request_context.response = ResponseWrapper.new(*result)
21
+ status, headers, body = result
22
+ request_context.response = ResponseWrapper.new(body, status, headers)
21
23
  complete!(request_context)
22
- request_context.saved? ? render_response(request_context) : result
24
+ request_context.saved? ? render_response(request_context).to_a : result
23
25
  ensure
24
26
  User.current_user = nil
25
27
  end
@@ -35,14 +37,13 @@ module RailsMiniProfiler
35
37
  def track_trace(event)
36
38
  return if traces.nil?
37
39
 
38
- trace = RailsMiniProfiler::Tracing::TraceFactory.create(event)
39
- traces.append(trace) unless trace.is_a?(RailsMiniProfiler::Tracing::NullTrace)
40
+ trace = @trace_factory.create(event)
41
+ traces.append(trace) unless trace.is_a?(RailsMiniProfiler::Tracers::NullTrace)
40
42
  end
41
43
 
42
44
  private
43
45
 
44
46
  def complete!(request_context)
45
- request_context.complete_profiling!
46
47
  request_context.save_results!
47
48
  true
48
49
  rescue ActiveRecord::ActiveRecordError => e
@@ -54,8 +55,7 @@ module RailsMiniProfiler
54
55
  redirect = Redirect.new(request_context).render
55
56
  return redirect if redirect
56
57
 
57
- modified_response = Badge.new(request_context).render
58
- [modified_response.status, modified_response.headers, modified_response.response]
58
+ Badge.new(request_context).render
59
59
  end
60
60
 
61
61
  def profile(request_context)
@@ -10,7 +10,7 @@ module RailsMiniProfiler
10
10
  # @return [RequestWrapper] the request as sent to the application
11
11
  # @!attribute response
12
12
  # @return [ResponseWrapper] the response as rendered by the application
13
- # @!attribute profiled_request
13
+ # # @!attribute profiled_request
14
14
  # @return [ProfiledRequest] the profiling data as gathered during profiling
15
15
  # @!attribute traces
16
16
  # @return [Array<Models::Trace>] trace wrappers gathered during profiling
@@ -19,8 +19,10 @@ module RailsMiniProfiler
19
19
  class RequestContext
20
20
  attr_reader :request
21
21
 
22
- attr_accessor :response, :profiled_request, :traces, :flamegraph
22
+ attr_accessor :response, :traces, :flamegraph, :profiled_request
23
23
 
24
+ # Create a new request context
25
+ #
24
26
  # @param request [RequestWrapper] the request as sent to the application
25
27
  def initialize(request)
26
28
  @request = request
@@ -36,39 +38,41 @@ module RailsMiniProfiler
36
38
  @authorized ||= User.get(@env).present?
37
39
  end
38
40
 
39
- # Completes profiling, setting all data and preparing for saving it.
40
- def complete_profiling!
41
- profiled_request.user_id = User.current_user
42
- profiled_request.request = @request
43
- profiled_request.response = @response
44
- total_time = traces.find { |trace| trace.name == 'rails_mini_profiler.total_time' }
45
- profiled_request.total_time = total_time
46
- @complete = true
47
- end
48
-
49
41
  # Save profiling data in the database.
50
42
  #
51
43
  # This will store the profiled request, as well as any attached traces and Flamgraph.
52
44
  def save_results!
53
45
  ActiveRecord::Base.transaction do
46
+ profiled_request = build_profiled_request
54
47
  profiled_request.flamegraph = RailsMiniProfiler::Flamegraph.new(data: flamegraph) if flamegraph.present?
55
48
  profiled_request.save
56
- insert_traces unless traces.empty?
49
+ insert_traces(profiled_request) unless traces.empty?
50
+ @profiled_request = profiled_request
57
51
  end
58
52
  @saved = true
59
53
  end
60
54
 
61
- def complete?
62
- @complete
63
- end
64
-
55
+ # Check if profiling results have been saved
56
+ #
57
+ # @return [Boolean] true if profiling results have been saved
65
58
  def saved?
66
59
  @saved
67
60
  end
68
61
 
69
62
  private
70
63
 
71
- def insert_traces
64
+ def build_profiled_request
65
+ new_profiled_request = ProfiledRequest.new
66
+ new_profiled_request.user_id = User.current_user
67
+ new_profiled_request.request = @request
68
+ new_profiled_request.response = @response
69
+ total_time = traces.find { |trace| trace.name == 'rails_mini_profiler.total_time' }
70
+ new_profiled_request.total_time = total_time
71
+ new_profiled_request
72
+ end
73
+
74
+ # We insert multiple at once for performance reasons.
75
+ def insert_traces(profiled_request)
72
76
  return if traces.empty?
73
77
 
74
78
  timestamp = Time.zone.now
@@ -1,69 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsMiniProfiler
4
- # A convenience wrapper around [Rack::Env]
5
- #
6
- # @!attribute body
7
- # @return [String] the request body
8
- # @!attribute method
9
- # @return [String] the request method
10
- # @!attribute path
11
- # @return [String] the request path
12
- # @!attribute query_string
13
- # @return [String] the request query string
14
- # @!attribute env
15
- # @return [Rack::Env] the original env
4
+ # A convenience wrapper extending {Rack::Request}
16
5
  #
17
6
  # @api private
18
- class RequestWrapper
19
- attr_reader :body,
20
- :method,
21
- :path,
22
- :query_string,
23
- :env
7
+ class RequestWrapper < Rack::Request
8
+ # Convenience method to read the request body as String
9
+ #
10
+ # @return [String] the request body
11
+ def body
12
+ return '' unless super
24
13
 
25
- def initialize(*_args, **attributes)
26
- @attributes = attributes
27
- setup
14
+ body = super.read
15
+ super.rewind
16
+ body
28
17
  end
29
18
 
30
19
  # The request headers
31
20
  #
32
- # @return [Hash] the headers
21
+ # @return [Hash] the request headers
33
22
  def headers
34
- @attributes[:headers] || @env.select { |k, _v| k.start_with? 'HTTP_' } || {}
35
- end
36
-
37
- private
38
-
39
- def setup
40
- @env = @attributes[:env] || {}
41
- @method = setup_method
42
- @query_string = setup_query_string
43
- @path = setup_path
44
- @body = setup_body
45
- end
46
-
47
- def setup_method
48
- @attributes[:method] || @env['REQUEST_METHOD'] || 'GET'
49
- end
50
-
51
- def setup_query_string
52
- @attributes[:query_string] || @env['QUERY_STRING'] || ''
53
- end
54
-
55
- def setup_path
56
- @attributes[:path] || @env['PATH_INFO'] || '/'
57
- end
58
-
59
- def setup_body
60
- return @attributes[:body] if @attributes[:body]
61
-
62
- return '' unless @env['rack.input']
63
-
64
- body = @env['rack.input'].read
65
- @env['rack.input'].rewind
66
- body
23
+ env.select { |k, _v| k.start_with? 'HTTP_' } || {}
67
24
  end
68
25
  end
69
26
  end
@@ -1,24 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsMiniProfiler
4
- class ResponseWrapper
5
- attr_reader :response, :rack_response
6
-
7
- delegate :status, :headers, to: :rack_response
8
-
9
- def initialize(status, headers, response)
10
- @rack_response = Rack::Response.new(response, status, headers)
11
- @response = response
12
- end
13
-
4
+ # A convenience wrapper extending {Rack::Response}
5
+ #
6
+ # @api private
7
+ class ResponseWrapper < Rack::Response
8
+ # Return the response body as String
9
+ #
10
+ # Depending on preceding middleware, response bodies may be Strings, Arrays or literally anything else. This method
11
+ # converts whatever it is to a string so we can store it later.
12
+ #
13
+ # @return [String] of the response body
14
14
  def body
15
- return '' unless json? || xml?
16
-
17
- response&.body || ''
18
- end
19
-
20
- def media_type
21
- @media_type ||= @rack_response.media_type
15
+ body = super
16
+ case body
17
+ when String
18
+ body
19
+ when Array
20
+ body.join
21
+ when ActionDispatch::Response::RackBody
22
+ body.body
23
+ else
24
+ ''
25
+ end
22
26
  end
23
27
 
24
28
  def json?
@@ -1,8 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsMiniProfiler
4
- module Tracing
4
+ module Tracers
5
5
  class ControllerTracer < Tracer
6
+ class << self
7
+ def subscribes_to
8
+ 'process_action.action_controller'
9
+ end
10
+
11
+ def build_from(event)
12
+ new(event).trace
13
+ end
14
+
15
+ def presents
16
+ ControllerTracePresenter
17
+ end
18
+ end
19
+
6
20
  def trace
7
21
  @event[:payload] = @event[:payload]
8
22
  .slice(:view_runtime, :db_runtime)