rails_mini_profiler 0.1.0
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.
- checksums.yaml +7 -0
- data/README.md +220 -0
- data/Rakefile +18 -0
- data/app/assets/config/rails_mini_profiler_manifest.js +1 -0
- data/app/assets/images/rails_mini_profiler/bookmark.svg +10 -0
- data/app/assets/images/rails_mini_profiler/chart.svg +12 -0
- data/app/assets/images/rails_mini_profiler/delete.svg +9 -0
- data/app/assets/images/rails_mini_profiler/graph.svg +11 -0
- data/app/assets/images/rails_mini_profiler/logo.svg +18 -0
- data/app/assets/images/rails_mini_profiler/logo_variant.svg +32 -0
- data/app/assets/images/rails_mini_profiler/search.svg +10 -0
- data/app/assets/images/rails_mini_profiler/setting.svg +10 -0
- data/app/assets/images/rails_mini_profiler/show.svg +11 -0
- data/app/assets/javascripts/rails_mini_profiler.js +90 -0
- data/app/assets/stylesheets/rails_mini_profiler/application.css +164 -0
- data/app/assets/stylesheets/rails_mini_profiler/flamegraph.css +14 -0
- data/app/assets/stylesheets/rails_mini_profiler/flashes.css +17 -0
- data/app/assets/stylesheets/rails_mini_profiler/navbar.css +50 -0
- data/app/assets/stylesheets/rails_mini_profiler/profiled_requests.css +180 -0
- data/app/assets/stylesheets/rails_mini_profiler/traces.css +87 -0
- data/app/controllers/rails_mini_profiler/application_controller.rb +28 -0
- data/app/controllers/rails_mini_profiler/flamegraphs_controller.rb +23 -0
- data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +55 -0
- data/app/helpers/rails_mini_profiler/application_helper.rb +12 -0
- data/app/helpers/rails_mini_profiler/profiled_requests_helper.rb +16 -0
- data/app/models/rails_mini_profiler/application_record.rb +17 -0
- data/app/models/rails_mini_profiler/controller_trace.rb +33 -0
- data/app/models/rails_mini_profiler/flamegraph.rb +33 -0
- data/app/models/rails_mini_profiler/instantiation_trace.rb +33 -0
- data/app/models/rails_mini_profiler/profiled_request.rb +59 -0
- data/app/models/rails_mini_profiler/render_partial_trace.rb +33 -0
- data/app/models/rails_mini_profiler/render_template_trace.rb +33 -0
- data/app/models/rails_mini_profiler/rmp_trace.rb +31 -0
- data/app/models/rails_mini_profiler/sequel_trace.rb +33 -0
- data/app/models/rails_mini_profiler/trace.rb +42 -0
- data/app/presenters/rails_mini_profiler/base_presenter.rb +25 -0
- data/app/presenters/rails_mini_profiler/controller_trace_presenter.rb +18 -0
- data/app/presenters/rails_mini_profiler/instantiation_trace_presenter.rb +14 -0
- data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +45 -0
- data/app/presenters/rails_mini_profiler/render_partial_trace_presenter.rb +11 -0
- data/app/presenters/rails_mini_profiler/render_template_trace_presenter.rb +15 -0
- data/app/presenters/rails_mini_profiler/rmp_trace_presenter.rb +9 -0
- data/app/presenters/rails_mini_profiler/sequel_trace_presenter.rb +69 -0
- data/app/presenters/rails_mini_profiler/trace_presenter.rb +61 -0
- data/app/views/layouts/rails_mini_profiler/application.html.erb +26 -0
- data/app/views/layouts/rails_mini_profiler/flamegraph.html.erb +18 -0
- data/app/views/rails_mini_profiler/badge.html.erb +37 -0
- data/app/views/rails_mini_profiler/flamegraphs/show.html.erb +13 -0
- data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +59 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/_trace.html.erb +40 -0
- data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +40 -0
- data/app/views/rails_mini_profiler/shared/_flashes.html.erb +8 -0
- data/app/views/rails_mini_profiler/shared/_navbar.html.erb +15 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20210621185018_create_rmp.rb +44 -0
- data/lib/generators/rails_mini_profiler/USAGE +2 -0
- data/lib/generators/rails_mini_profiler/install_generator.rb +16 -0
- data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +13 -0
- data/lib/rails_mini_profiler.rb +55 -0
- data/lib/rails_mini_profiler/badge.rb +62 -0
- data/lib/rails_mini_profiler/configuration.rb +41 -0
- data/lib/rails_mini_profiler/engine.rb +23 -0
- data/lib/rails_mini_profiler/errors.rb +8 -0
- data/lib/rails_mini_profiler/flamegraph_guard.rb +47 -0
- data/lib/rails_mini_profiler/guard.rb +46 -0
- data/lib/rails_mini_profiler/logger.rb +20 -0
- data/lib/rails_mini_profiler/middleware.rb +74 -0
- data/lib/rails_mini_profiler/models/base_model.rb +18 -0
- data/lib/rails_mini_profiler/models/trace.rb +9 -0
- data/lib/rails_mini_profiler/redirect.rb +25 -0
- data/lib/rails_mini_profiler/request_context.rb +62 -0
- data/lib/rails_mini_profiler/request_wrapper.rb +33 -0
- data/lib/rails_mini_profiler/response_wrapper.rb +32 -0
- data/lib/rails_mini_profiler/storage.rb +29 -0
- data/lib/rails_mini_profiler/tracers.rb +85 -0
- data/lib/rails_mini_profiler/user.rb +40 -0
- data/lib/rails_mini_profiler/version.rb +5 -0
- data/lib/tasks/rails_mini_profiler_tasks.rake +8 -0
- metadata +151 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class Guard
|
|
5
|
+
def initialize(request_context, configuration: RailsMiniProfiler.configuration)
|
|
6
|
+
@request_context = request_context
|
|
7
|
+
@request = request_context.request
|
|
8
|
+
@configuration = configuration
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def profile?
|
|
12
|
+
return false unless enabled?
|
|
13
|
+
|
|
14
|
+
return false if ignored_path?
|
|
15
|
+
|
|
16
|
+
true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def store?
|
|
20
|
+
return false unless @request_context.user
|
|
21
|
+
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def ignored_path?
|
|
28
|
+
return true if /#{Engine.routes.find_script_name({})}/.match?(@request.path)
|
|
29
|
+
|
|
30
|
+
return true if /assets/.match?(@request.path)
|
|
31
|
+
|
|
32
|
+
ignored_paths = @configuration.skip_paths
|
|
33
|
+
|
|
34
|
+
return true if Regexp.union(ignored_paths).match?(@request.path)
|
|
35
|
+
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def enabled?
|
|
40
|
+
enabled = @configuration.enabled
|
|
41
|
+
return enabled unless enabled.respond_to?(:call)
|
|
42
|
+
|
|
43
|
+
enabled.call(@request.env)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
module Logger
|
|
5
|
+
def self.new(logger)
|
|
6
|
+
logger = logger.dup
|
|
7
|
+
|
|
8
|
+
logger.formatter = logger.formatter ? logger.formatter.dup : ActiveSupport::Logger::SimpleFormatter.new
|
|
9
|
+
|
|
10
|
+
logger.formatter.extend Formatter
|
|
11
|
+
logger.extend(self)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Formatter
|
|
15
|
+
def call(severity, timestamp, progname, msg)
|
|
16
|
+
super(severity, timestamp, progname, "[RailsMiniProfiler] #{msg}")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class Middleware
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
@config = RailsMiniProfiler.configuration
|
|
8
|
+
Tracers.setup! { |trace| track_trace(trace) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call(env)
|
|
12
|
+
request = RequestWrapper.new(env)
|
|
13
|
+
request_context = RequestContext.new(request)
|
|
14
|
+
return @app.call(env) unless Guard.new(request_context).profile?
|
|
15
|
+
|
|
16
|
+
request_context.profiled_request = ProfiledRequest.new
|
|
17
|
+
result = with_tracing(request_context) { profile(request_context) }
|
|
18
|
+
return result unless request_context.authorized?
|
|
19
|
+
|
|
20
|
+
request_context.response = ResponseWrapper.new(*result)
|
|
21
|
+
complete!(request_context)
|
|
22
|
+
request_context.saved? ? render_response(request_context) : result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def traces
|
|
26
|
+
Thread.current[:rails_mini_profiler_traces]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def traces=(traces)
|
|
30
|
+
Thread.current[:rails_mini_profiler_traces] = traces
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def track_trace(event)
|
|
34
|
+
return if traces.nil?
|
|
35
|
+
|
|
36
|
+
trace = Tracers.build_trace(event)
|
|
37
|
+
traces.append(trace)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def complete!(request_context)
|
|
43
|
+
request_context.complete_profiling!
|
|
44
|
+
request_context.save_results!
|
|
45
|
+
true
|
|
46
|
+
rescue ActiveRecord::ActiveRecordError => e
|
|
47
|
+
RailsMiniProfiler.logger.error("Could not save profile: #{e}")
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def render_response(request_context)
|
|
52
|
+
redirect = Redirect.new(request_context).render
|
|
53
|
+
return redirect if redirect
|
|
54
|
+
|
|
55
|
+
modified_response = Badge.new(request_context).render
|
|
56
|
+
[modified_response.status, modified_response.headers, modified_response.response]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def profile(request_context)
|
|
60
|
+
ActiveSupport::Notifications.instrument('rails_mini_profiler.total_time') do
|
|
61
|
+
request = request_context.request
|
|
62
|
+
FlamegraphGuard.new(request_context).record { @app.call(request.env) }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def with_tracing(request_context)
|
|
67
|
+
self.traces = []
|
|
68
|
+
result = yield
|
|
69
|
+
request_context.traces = traces
|
|
70
|
+
self.traces = nil
|
|
71
|
+
result
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
module Models
|
|
5
|
+
class BaseModel
|
|
6
|
+
include ActiveModel::Model
|
|
7
|
+
|
|
8
|
+
def initialize(*_args, **attributes)
|
|
9
|
+
super(attributes)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_h
|
|
13
|
+
instance_variables
|
|
14
|
+
.each_with_object({}) { |var, hash| hash[var.to_s.delete('@')] = instance_variable_get(var) }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class Redirect
|
|
5
|
+
include Engine.routes.url_helpers
|
|
6
|
+
|
|
7
|
+
def initialize(request_context)
|
|
8
|
+
@request = request_context.request
|
|
9
|
+
@profiled_request = request_context.profiled_request
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def render
|
|
13
|
+
params = CGI.parse(@request.query_string).transform_values(&:first).with_indifferent_access
|
|
14
|
+
return redirect_to(flamegraph_path(@profiled_request.id)) if params[:rmp_flamegraph]
|
|
15
|
+
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def redirect_to(location)
|
|
22
|
+
[302, { 'Location' => location, 'Content-Type' => 'text/html' }, ['Moved Temporarily']]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class RequestContext
|
|
5
|
+
attr_reader :request
|
|
6
|
+
|
|
7
|
+
attr_accessor :response, :profiled_request, :traces, :flamegraph
|
|
8
|
+
|
|
9
|
+
def initialize(request)
|
|
10
|
+
@request = request
|
|
11
|
+
@env = request.env
|
|
12
|
+
@saved = false
|
|
13
|
+
@complete = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def user_id
|
|
17
|
+
@user_id ||= User.current_user
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def authorized?
|
|
21
|
+
@authorized ||= User.get(@env).present?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def complete_profiling!
|
|
25
|
+
profiled_request.user_id = user_id
|
|
26
|
+
profiled_request.request = @request
|
|
27
|
+
profiled_request.response = @response
|
|
28
|
+
total_time = traces.find { |trace| trace.name == 'rails_mini_profiler.total_time' }
|
|
29
|
+
profiled_request.total_time = total_time
|
|
30
|
+
@complete = true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def save_results!
|
|
34
|
+
ActiveRecord::Base.transaction do
|
|
35
|
+
profiled_request.flamegraph = Flamegraph.new(data: flamegraph) if flamegraph.present?
|
|
36
|
+
profiled_request.save
|
|
37
|
+
insert_traces unless traces.empty?
|
|
38
|
+
end
|
|
39
|
+
@saved = true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def complete?
|
|
43
|
+
@complete
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def saved?
|
|
47
|
+
@saved
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def insert_traces
|
|
53
|
+
return if traces.empty?
|
|
54
|
+
|
|
55
|
+
timestamp = Time.zone.now
|
|
56
|
+
inserts = traces.map do |trace|
|
|
57
|
+
{ rmp_profiled_request_id: profiled_request.id, **trace.to_h, created_at: timestamp, updated_at: timestamp }
|
|
58
|
+
end
|
|
59
|
+
RailsMiniProfiler::Trace.insert_all(inserts)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class RequestWrapper
|
|
5
|
+
attr_reader :body,
|
|
6
|
+
:method,
|
|
7
|
+
:path,
|
|
8
|
+
:query_string,
|
|
9
|
+
:env
|
|
10
|
+
|
|
11
|
+
def initialize(env = {})
|
|
12
|
+
@env = env
|
|
13
|
+
@method = @env['REQUEST_METHOD'] || 'GET'
|
|
14
|
+
@query_string = @env['QUERY_STRING'] || ''
|
|
15
|
+
@path = @env['PATH_INFO'] || '/'
|
|
16
|
+
@body = read_body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def headers
|
|
20
|
+
@env.select { |k, _v| k.start_with? 'HTTP_' } || []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def read_body
|
|
26
|
+
return '' unless @env['rack.input']
|
|
27
|
+
|
|
28
|
+
body = @env['rack.input'].read
|
|
29
|
+
@env['rack.input'].rewind
|
|
30
|
+
body
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
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
|
+
|
|
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
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def json?
|
|
25
|
+
media_type =~ %r{application/json}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def xml?
|
|
29
|
+
media_type =~ %r{application/xml}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class Storage
|
|
5
|
+
class << self
|
|
6
|
+
def configuration
|
|
7
|
+
@configuration ||= new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def configure
|
|
11
|
+
yield(configuration)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_accessor :database, :profiled_requests_table, :traces_table, :flamegraphs_table
|
|
16
|
+
|
|
17
|
+
def initialize(**kwargs)
|
|
18
|
+
defaults!
|
|
19
|
+
kwargs.each { |key, value| instance_variable_set("@#{key}", value) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def defaults!
|
|
23
|
+
@database = nil
|
|
24
|
+
@profiled_requests_table = 'rmp_profiled_requests'
|
|
25
|
+
@flamegraphs_table = 'rmp_flamegraphs'
|
|
26
|
+
@traces_table = 'rmp_traces'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsMiniProfiler
|
|
4
|
+
class Tracers
|
|
5
|
+
DEFAULT_SUBSCRIPTIONS = %w[
|
|
6
|
+
sql.active_record
|
|
7
|
+
instantiation.active_record
|
|
8
|
+
render_template.action_view
|
|
9
|
+
render_partial.action_view
|
|
10
|
+
process_action.action_controller
|
|
11
|
+
rails_mini_profiler.total_time
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def setup!(&callback)
|
|
16
|
+
DEFAULT_SUBSCRIPTIONS.each do |event|
|
|
17
|
+
subscribe(event, &callback)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_trace(event)
|
|
22
|
+
start = (event.time.to_f * 100_000).to_i
|
|
23
|
+
finish = (event.end.to_f * 100_000).to_i
|
|
24
|
+
Models::Trace.new(
|
|
25
|
+
name: event.name,
|
|
26
|
+
start: start,
|
|
27
|
+
finish: finish,
|
|
28
|
+
duration: finish - start,
|
|
29
|
+
allocations: event.allocations,
|
|
30
|
+
backtrace: Rails.backtrace_cleaner.clean(caller),
|
|
31
|
+
payload: format_payload(event)
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def subscribe(*subscriptions, &callback)
|
|
38
|
+
subscriptions.each do |subscription|
|
|
39
|
+
ActiveSupport::Notifications.subscribe(subscription) do |event|
|
|
40
|
+
callback.call(event)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def format_payload(event)
|
|
46
|
+
case event.name
|
|
47
|
+
when 'sql.active_record'
|
|
48
|
+
transform_sql_event(event)
|
|
49
|
+
when 'render_template.action_view', 'render_partial.action_view'
|
|
50
|
+
event.payload.slice(:identifier, :count)
|
|
51
|
+
when 'process_action.action_controller'
|
|
52
|
+
transform_controller_event(event)
|
|
53
|
+
else
|
|
54
|
+
event.payload
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def transform_sql_event(event)
|
|
59
|
+
payload = event.payload.slice(:name, :sql, :binds, :type_casted_binds)
|
|
60
|
+
typecasted_binds = payload[:type_casted_binds]
|
|
61
|
+
# Sometimes, typecasted binds are a proc. Not sure why. In those instances, we extract the typecasted
|
|
62
|
+
# values from the proc by executing call.
|
|
63
|
+
typecasted_binds = typecasted_binds.respond_to?(:call) ? typecasted_binds.call : typecasted_binds
|
|
64
|
+
payload[:binds] = transform_binds(payload[:binds], typecasted_binds)
|
|
65
|
+
payload.delete(:type_casted_binds)
|
|
66
|
+
payload.reject { |_k, v| v.blank? }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def transform_binds(binds, type_casted_binds)
|
|
70
|
+
binds.each_with_object([]).with_index do |(binding, object), i|
|
|
71
|
+
name = binding.name
|
|
72
|
+
value = type_casted_binds[i]
|
|
73
|
+
object << { name: name, value: value }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def transform_controller_event(event)
|
|
78
|
+
payload = event.payload
|
|
79
|
+
.slice(:view_runtime, :db_runtime)
|
|
80
|
+
.transform_values { |value| value&.round(2) }
|
|
81
|
+
payload.reject { |_k, v| v.blank? }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|