-
Notifications
You must be signed in to change notification settings - Fork 399
/
railtie.rb
233 lines (193 loc) · 8.22 KB
/
railtie.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# frozen_string_literal: true
require 'fileutils'
require_relative './railtie_methods'
module Rack::MiniProfilerRails
extend Rack::MiniProfilerRailsMethods
# call direct if needed to do a defer init
def self.initialize!(app)
raise "MiniProfilerRails initialized twice. Set `require: false' for rack-mini-profiler in your Gemfile" if defined?(@already_initialized) && @already_initialized
c = Rack::MiniProfiler.config
# By default, only show the MiniProfiler in development mode.
# To use the MiniProfiler in production, call Rack::MiniProfiler.authorize_request
# from a hook in your ApplicationController
#
# Example:
# before_action { Rack::MiniProfiler.authorize_request if current_user.is_admin? }
#
# NOTE: this must be set here with = and not ||=
# The out of the box default is "true"
c.pre_authorize_cb = lambda { |env|
!Rails.env.test?
}
c.skip_paths ||= []
if serves_static_assets?(app)
c.skip_paths << app.config.assets.prefix
wp_assets_path = get_webpacker_assets_path()
c.skip_paths << wp_assets_path if wp_assets_path
end
unless Rails.env.development? || Rails.env.test?
c.authorization_mode = :allow_authorized
end
if Rails.logger
c.logger = Rails.logger
end
# The file store is just so much less flaky
# If the user has not changed from the default memory store then switch to the file store, otherwise keep what the user set
if c.storage == Rack::MiniProfiler::MemoryStore && c.storage_options.nil?
base_path = Rails.application.config.paths['tmp'].first rescue "#{Rails.root}/tmp"
tmp = base_path + '/miniprofiler'
c.storage_options = { path: tmp }
c.storage = Rack::MiniProfiler::FileStore
end
# Quiet the SQL stack traces
c.backtrace_remove = Rails.root.to_s + "/"
c.backtrace_includes = [/^\/?(app|config|lib|test)/]
c.skip_schema_queries = (Rails.env.development? || Rails.env.test?)
# Install the Middleware
app.middleware.insert(0, Rack::MiniProfiler)
c.enable_advanced_debugging_tools = Rails.env.development?
if ::Rack::MiniProfiler.patch_rails?
# Attach to various Rails methods
ActiveSupport.on_load(:action_controller) do
::Rack::MiniProfiler.profile_method(ActionController::Base, :process) { |action| "Executing action: #{action}" }
end
ActiveSupport.on_load(:action_view) do
::Rack::MiniProfiler.profile_method(ActionView::Template, :render) { |x, y| "Rendering: #{@virtual_path}" }
end
else
subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
next if !should_measure?
current = Rack::MiniProfiler.current
controller_name = payload[:controller].sub(/Controller\z/, '').downcase
description = "Executing: #{controller_name}##{payload[:action]}"
Thread.current[get_key(payload)] = current.current_timer
Rack::MiniProfiler.current.current_timer = current.current_timer.add_child(description)
end
subscribe("process_action.action_controller") do |name, start, finish, id, payload|
next if !should_measure?
key = get_key(payload)
parent_timer = Thread.current[key]
next if !parent_timer
Thread.current[key] = nil
Rack::MiniProfiler.current.current_timer.record_time
Rack::MiniProfiler.current.current_timer = parent_timer
end
subscribe("render_partial.action_view") do |name, start, finish, id, payload|
render_notification_handler(shorten_identifier(payload[:identifier]), finish, start)
end
subscribe("render_template.action_view") do |name, start, finish, id, payload|
render_notification_handler(shorten_identifier(payload[:identifier]), finish, start)
end
if Rack::MiniProfiler.subscribe_sql_active_record
# we don't want to subscribe if we've already patched a DB driver
# otherwise we would end up with 2 records for every query
subscribe("sql.active_record") do |name, start, finish, id, payload|
next if !should_measure?
next if payload[:name] =~ /SCHEMA/ && Rack::MiniProfiler.config.skip_schema_queries
Rack::MiniProfiler.record_sql(
payload[:sql],
(finish - start) * 1000,
Rack::MiniProfiler.binds_to_params(payload[:binds])
)
end
subscribe("instantiation.active_record") do |name, start, finish, id, payload|
next if !should_measure?
Rack::MiniProfiler.report_reader_duration(
(finish - start) * 1000,
payload[:record_count],
payload[:class_name]
)
end
end
end
@already_initialized = true
end
def self.create_engine
return if defined?(Rack::MiniProfilerRails::Engine)
klass = Class.new(::Rails::Engine) do
engine_name 'rack-mini-profiler'
config.assets.paths << File.expand_path('../../html', __FILE__)
config.assets.precompile << 'rack-mini-profiler.js'
config.assets.precompile << 'rack-mini-profiler.css'
end
Rack::MiniProfilerRails.const_set("Engine", klass)
end
def self.subscribe(event, &blk)
if ActiveSupport::Notifications.respond_to?(:monotonic_subscribe)
ActiveSupport::Notifications.monotonic_subscribe(event) { |*args| blk.call(*args) }
else
ActiveSupport::Notifications.subscribe(event) do |name, start, finish, id, payload|
blk.call(name, start.to_f, finish.to_f, id, payload)
end
end
end
def self.get_key(payload)
"mini_profiler_parent_timer_#{payload[:controller]}_#{payload[:action]}".to_sym
end
def self.shorten_identifier(identifier)
identifier.split('/').last(2).join('/')
end
def self.serves_static_assets?(app)
config = app.config
if !config.respond_to?(:assets) || !config.assets.respond_to?(:prefix)
return false
end
if ::Rails.version >= "5.0.0"
::Rails.configuration.public_file_server.enabled
elsif ::Rails.version >= "4.2.0"
::Rails.configuration.serve_static_files
else
::Rails.configuration.serve_static_assets
end
end
class Railtie < ::Rails::Railtie
initializer "rack_mini_profiler.configure_rails_initialization" do |app|
Rack::MiniProfilerRails.initialize!(app)
end
# Suppress compression when Rack::Deflater is lower in the middleware
# stack than Rack::MiniProfiler
config.after_initialize do |app|
middlewares = app.middleware.middlewares
if Rack::MiniProfiler.config.suppress_encoding.nil? &&
middlewares.include?(Rack::Deflater) &&
middlewares.include?(Rack::MiniProfiler) &&
middlewares.index(Rack::Deflater) > middlewares.index(Rack::MiniProfiler)
Rack::MiniProfiler.config.suppress_encoding = true
end
end
# TODO: Implement something better here
# config.after_initialize do
#
# class ::ActionView::Helpers::AssetTagHelper::JavascriptIncludeTag
# alias_method :asset_tag_orig, :asset_tag
# def asset_tag(source,options)
# current = Rack::MiniProfiler.current
# return asset_tag_orig(source,options) unless current
# wrapped = ""
# unless current.mpt_init
# current.mpt_init = true
# wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
# end
# name = source.split('/')[-1]
# wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
# wrapped
# end
# end
# class ::ActionView::Helpers::AssetTagHelper::StylesheetIncludeTag
# alias_method :asset_tag_orig, :asset_tag
# def asset_tag(source,options)
# current = Rack::MiniProfiler.current
# return asset_tag_orig(source,options) unless current
# wrapped = ""
# unless current.mpt_init
# current.mpt_init = true
# wrapped << Rack::MiniProfiler::ClientTimerStruct.init_instrumentation
# end
# name = source.split('/')[-1]
# wrapped << Rack::MiniProfiler::ClientTimerStruct.instrument(name, asset_tag_orig(source,options)).html_safe
# wrapped
# end
# end
# end
end
end