rails_mini_profiler 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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)