rails_mini_profiler 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +13 -10
- data/app/javascript/images/check.svg +3 -0
- data/app/javascript/images/chevron.svg +3 -0
- data/app/javascript/images/filter.svg +1 -0
- data/app/javascript/images/logo_variant.svg +2 -2
- data/app/javascript/images/search.svg +4 -5
- data/app/javascript/js/checklist_controller.js +48 -0
- data/app/javascript/js/enable_controller.js +24 -0
- data/app/javascript/js/filter_controller.js +44 -0
- data/app/javascript/js/search_controller.js +18 -0
- data/app/javascript/js/select_controller.js +47 -0
- data/app/javascript/packs/rails-mini-profiler.js +23 -15
- data/app/javascript/stylesheets/components/page_header/page_header.scss +3 -0
- data/app/javascript/stylesheets/components/pagination.scss +14 -13
- data/app/javascript/stylesheets/components/profiled_request_table/placeholder.scss +33 -0
- data/app/javascript/stylesheets/components/profiled_request_table/profiled_request_table.scss +179 -0
- data/app/javascript/stylesheets/flamegraph.scss +3 -2
- data/app/javascript/stylesheets/flashes.scss +3 -5
- data/app/javascript/stylesheets/navbar.scss +7 -13
- data/app/javascript/stylesheets/profiled_requests.scss +35 -120
- data/app/javascript/stylesheets/rails-mini-profiler.scss +90 -61
- data/app/javascript/stylesheets/traces.scss +17 -17
- data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +8 -15
- data/app/search/rails_mini_profiler/base_search.rb +67 -0
- data/app/search/rails_mini_profiler/profiled_request_search.rb +34 -0
- data/app/views/rails_mini_profiler/badge.html.erb +2 -2
- data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +8 -58
- data/app/views/rails_mini_profiler/profiled_requests/shared/header/_header.erb +20 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_placeholder.erb +12 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table.erb +14 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_head.erb +125 -0
- data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_row.erb +21 -0
- data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +1 -1
- data/lib/rails_mini_profiler/configuration.rb +3 -0
- data/lib/rails_mini_profiler/engine.rb +12 -8
- data/lib/rails_mini_profiler/middleware.rb +3 -3
- data/lib/rails_mini_profiler/tracing/controller_tracer.rb +15 -0
- data/lib/rails_mini_profiler/tracing/null_trace.rb +7 -0
- data/lib/rails_mini_profiler/tracing/sequel_tracer.rb +37 -0
- data/lib/rails_mini_profiler/tracing/sequel_tracker.rb +37 -0
- data/lib/rails_mini_profiler/tracing/subscriptions.rb +34 -0
- data/lib/rails_mini_profiler/{models → tracing}/trace.rb +10 -2
- data/lib/rails_mini_profiler/tracing/trace_factory.rb +37 -0
- data/lib/rails_mini_profiler/tracing/tracer.rb +31 -0
- data/lib/rails_mini_profiler/tracing/view_tracer.rb +12 -0
- data/lib/rails_mini_profiler/tracing.rb +11 -0
- data/lib/rails_mini_profiler/version.rb +1 -1
- data/lib/rails_mini_profiler.rb +4 -8
- data/vendor/assets/images/check.svg +3 -0
- data/vendor/assets/images/chevron.svg +3 -0
- data/vendor/assets/images/filter.svg +1 -0
- data/vendor/assets/images/logo_variant.svg +2 -2
- data/vendor/assets/images/search.svg +4 -5
- data/vendor/assets/javascripts/rails-mini-profiler.css +1 -1
- data/vendor/assets/javascripts/rails-mini-profiler.js +1 -1
- metadata +33 -4
- data/lib/rails_mini_profiler/tracers.rb +0 -85
@@ -25,13 +25,13 @@
|
|
25
25
|
transition: opacity 0.3s;
|
26
26
|
}
|
27
27
|
|
28
|
-
#
|
28
|
+
#logo-variant {
|
29
29
|
height: 18px;
|
30
30
|
width: 18px;
|
31
31
|
padding-bottom: 2px;
|
32
32
|
}
|
33
33
|
</style>
|
34
34
|
<a id="rails-mini-profiler-badge" href="<%= profiled_request_path(@profiled_request.id) %>" data-turbolinks="false" title="View performance data">
|
35
|
-
<%= inline_svg('logo_variant.svg'
|
35
|
+
<%= inline_svg('logo_variant.svg') %>
|
36
36
|
<%= (@profiled_request.duration.to_f / 100).round %>ms
|
37
37
|
</a>
|
@@ -1,59 +1,9 @@
|
|
1
|
-
<% if @profiled_requests.empty? %>
|
2
|
-
<section class="placeholder">
|
3
|
-
<%= inline_svg('logo_variant.svg', class: 'placeholder-image') %>
|
4
|
-
<div class="placeholder-text">
|
5
|
-
<h2> There is nothing here yet! </h2>
|
6
|
-
<p>Send some requests to your app for them to show up here</p>
|
7
|
-
</div>
|
8
|
-
</section>
|
9
|
-
<% else %>
|
10
|
-
<h1>Profiled Requests</h1>
|
11
|
-
<div class="profiled-requests-actions">
|
12
|
-
<%= form_with id: 'profiled-request-search-form', url: profiled_requests_url, method: :get do |form| %>
|
13
|
-
<%= form.search_field :path, id: 'profiled-request-search', placeholder: 'Search Path...', class: 'search-field' %>
|
14
|
-
<% end %>
|
15
|
-
<%= link_to(destroy_all_profiled_requests_url,
|
16
|
-
method: :delete,
|
17
|
-
class: 'clear-action',
|
18
|
-
data: { confirm: "This will delete all requests. Are you sure?" }) do %>
|
19
|
-
<button>Clear Requests</button>
|
20
|
-
<% end %>
|
21
|
-
</div>
|
22
|
-
<table id="profiled-requests-table" class="table">
|
23
|
-
<thead>
|
24
|
-
<tr>
|
25
|
-
<th class="text-left">Path</th>
|
26
|
-
<th class="text-left">Method</th>
|
27
|
-
<th class="text-left">Status</th>
|
28
|
-
<th class="text-left">Media Type</th>
|
29
|
-
<th class="text-right">Duration</th>
|
30
|
-
<th class="text-left"></th>
|
31
|
-
<th class="text-left"></th>
|
32
|
-
</tr>
|
33
|
-
</thead>
|
34
1
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
<td class=""><%= profiled_request.created_at %></td>
|
44
|
-
<td class="request-buttons">
|
45
|
-
<%= link_to(profiled_request_path(profiled_request.id), title: 'Show Details') do %>
|
46
|
-
<%= inline_svg('show.svg', options = {}) %>
|
47
|
-
<% end %>
|
48
|
-
<%= profiled_request.flamegraph_icon %>
|
49
|
-
<%= link_to(profiled_request_path(profiled_request.id), title: 'Delete Request', method: :delete) do %>
|
50
|
-
<%= inline_svg('delete.svg') %>
|
51
|
-
<% end %>
|
52
|
-
</td>
|
53
|
-
</tr>
|
54
|
-
<% end %>
|
55
|
-
</tbody>
|
56
|
-
</table>
|
57
|
-
<%== pagy_nav(@pagy) %>
|
58
|
-
<br>
|
59
|
-
<% end %>
|
2
|
+
<div
|
3
|
+
data-controller="filters selectable"
|
4
|
+
data-action="search-controller:submit@window->filters#apply">
|
5
|
+
<%= render "rails_mini_profiler/profiled_requests/shared/header/header" %>
|
6
|
+
<%= render "rails_mini_profiler/profiled_requests/shared/table/table" %>
|
7
|
+
</div>
|
8
|
+
<%== pagy_nav(@pagy) if @pagy.pages > 1 %>
|
9
|
+
<br>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="page-header profiled-requests-header">
|
2
|
+
<div class="">
|
3
|
+
<h1>Profiled Requests</h1>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<%= button_tag('Delete Selected',
|
7
|
+
disabled: params[:id].blank?,
|
8
|
+
data: {
|
9
|
+
controller: 'enable',
|
10
|
+
'enable-target': 'enable',
|
11
|
+
action: 'rmp:select:change@window->enable#change click->filters#post'
|
12
|
+
}) -%>
|
13
|
+
<%= link_to(destroy_all_profiled_requests_url,
|
14
|
+
method: :delete,
|
15
|
+
class: 'clear-action',
|
16
|
+
data: { confirm: "This will delete all requests. Are you sure?" }) do %>
|
17
|
+
<%= button_tag('Delete All') %>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<tr class="no-row">
|
2
|
+
<td colspan="100%">
|
3
|
+
<div class="placeholder">
|
4
|
+
<%= inline_svg('logo_variant.svg', class: 'placeholder-image') %>
|
5
|
+
<div class="placeholder-text">
|
6
|
+
<h2>No Requests found!</h2>
|
7
|
+
<p>Send some requests to your app or modify your filters</p>
|
8
|
+
</div>
|
9
|
+
<%= link_to('Clear Filters', profiled_requests_path, class: 'placeholder-link') %>
|
10
|
+
</div>
|
11
|
+
</td>
|
12
|
+
</tr>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<table
|
2
|
+
id="profiled-requests-table"
|
3
|
+
class="table">
|
4
|
+
<%= render "rails_mini_profiler/profiled_requests/shared/table/table_head" %>
|
5
|
+
<tbody>
|
6
|
+
<% if @profiled_requests.empty? %>
|
7
|
+
<%= render "rails_mini_profiler/profiled_requests/shared/table/placeholder" %>
|
8
|
+
<% else %>
|
9
|
+
<% @profiled_requests.each do |profiled_request| %>
|
10
|
+
<%= render "rails_mini_profiler/profiled_requests/shared/table/table_row", profiled_request: profiled_request %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
</tbody>
|
14
|
+
</table>
|
@@ -0,0 +1,125 @@
|
|
1
|
+
<thead>
|
2
|
+
<tr>
|
3
|
+
<th style="width: 20px;" class="text-left">
|
4
|
+
<%= label_tag nil do %>
|
5
|
+
<%= check_box_tag 'selected[]', nil,
|
6
|
+
params.fetch(:selected, []).size == @pagy.items,
|
7
|
+
class: "request-checkbox",
|
8
|
+
data: {
|
9
|
+
action: 'click->selectable#selectAll',
|
10
|
+
'selectable-target': 'all'
|
11
|
+
}
|
12
|
+
%>
|
13
|
+
<% end %>
|
14
|
+
</th>
|
15
|
+
<th style="width: 25%;" class="text-left" data-controller="dropdown">
|
16
|
+
<button data-action="click->dropdown#toggle click@window->dropdown#hide" data-dropdown-target="button" class="dropdown-toggle none">
|
17
|
+
Path <%= inline_svg('search.svg', class: 'table-filter-icon') %> </button>
|
18
|
+
<div data-controller="search" data-dropdown-target="menu" class="dropdown-container hidden">
|
19
|
+
<div class="dropdown-body">
|
20
|
+
<%= form_with url: profiled_requests_url, method: :get do |form| %>
|
21
|
+
<%= form.search_field :path,
|
22
|
+
value: params[:path],
|
23
|
+
placeholder: 'Search Path',
|
24
|
+
class: 'dropdown-search-field',
|
25
|
+
data: { 'filters-target': 'filter' } %>
|
26
|
+
<%= form.submit 'Search', class: 'dropdown-search-button', data: { action: 'click->search#submit' } -%>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</th>
|
31
|
+
<th style="width: 10%;" class="" data-controller="dropdown">
|
32
|
+
<button data-action="click->dropdown#toggle click@window->dropdown#hide" data-dropdown-target="button" class="dropdown-toggle none">
|
33
|
+
Method <%= inline_svg('filter.svg', class: 'table-filter-icon') %> </button>
|
34
|
+
<div data-controller="checklist" data-dropdown-target="menu" class="dropdown-container hidden">
|
35
|
+
<div class="dropdown-header">
|
36
|
+
Select Method...
|
37
|
+
<button class="clear-filters" data-action="checklist#checkNone">
|
38
|
+
Clear filter
|
39
|
+
</button>
|
40
|
+
</div>
|
41
|
+
<% %w[get put post delete].map(&:upcase).each do |method| %>
|
42
|
+
<%= label_tag nil, class: "dropdown-entry" do %>
|
43
|
+
<%= check_box_tag 'method[]', method, params.fetch(:method, []).include?(method),
|
44
|
+
class: "",
|
45
|
+
data: { 'filters-target': "filter" } %>
|
46
|
+
<%= method %>
|
47
|
+
<% end %>
|
48
|
+
<% end %>
|
49
|
+
<button class="dropdown-footer" data-action="filters#apply">
|
50
|
+
Apply
|
51
|
+
</button>
|
52
|
+
</div>
|
53
|
+
</th>
|
54
|
+
<th style="width: 10%;" class="" data-controller="dropdown">
|
55
|
+
<button data-action="click->dropdown#toggle click@window->dropdown#hide" data-dropdown-target="button" class="dropdown-toggle none">
|
56
|
+
Status <%= inline_svg('filter.svg', class: 'table-filter-icon') %> </button>
|
57
|
+
<div data-controller="checklist" data-dropdown-target="menu" class="dropdown-container hidden">
|
58
|
+
<div class="dropdown-header">
|
59
|
+
Select Status...
|
60
|
+
<button class="clear-filters" data-action="checklist#checkNone filters#apply">
|
61
|
+
Clear filter
|
62
|
+
</button>
|
63
|
+
</div>
|
64
|
+
<% %w[200 300 400 500].each do |status| %>
|
65
|
+
<%= label_tag nil, class: "dropdown-entry" do %>
|
66
|
+
<%= check_box_tag 'status[]', status, params.fetch(:status, []).include?(status),
|
67
|
+
class: "",
|
68
|
+
data: { 'filters-target': "filter" } %>
|
69
|
+
<%= status %>
|
70
|
+
<% end %>
|
71
|
+
<% end %>
|
72
|
+
<button class="dropdown-footer" data-action="filters#apply">
|
73
|
+
Apply
|
74
|
+
</button>
|
75
|
+
</div>
|
76
|
+
</th>
|
77
|
+
<th style="width: 15%" class="" data-controller="dropdown">
|
78
|
+
<button data-action="click->dropdown#toggle click@window->dropdown#hide" data-dropdown-target="button" class="dropdown-toggle none">
|
79
|
+
Media Type <%= inline_svg('filter.svg', class: 'table-filter-icon') %> </button>
|
80
|
+
<div data-controller="checklist" data-dropdown-target="menu" class="dropdown-container hidden">
|
81
|
+
<div class="dropdown-header">
|
82
|
+
Select Media Type...
|
83
|
+
<button class="clear-filters" data-action="checklist#checkNone filters#apply">
|
84
|
+
Clear filter
|
85
|
+
</button>
|
86
|
+
</div>
|
87
|
+
<% %w[text/html application/json application/xml].each do |media_type| %>
|
88
|
+
<%= label_tag nil, class: "dropdown-entry" do %>
|
89
|
+
<%= check_box_tag 'media_type[]', media_type, params.fetch(:media_type, []).include?(media_type),
|
90
|
+
class: "",
|
91
|
+
data: { target: "filters.filter" } %>
|
92
|
+
<%= media_type %>
|
93
|
+
<% end %>
|
94
|
+
<% end %>
|
95
|
+
<button class="dropdown-footer" data-action="filters#apply">
|
96
|
+
Apply
|
97
|
+
</button>
|
98
|
+
</div>
|
99
|
+
</th>
|
100
|
+
<th style="width: 10%" class="text-left" data-controller="dropdown">
|
101
|
+
<button data-action="click->dropdown#toggle click@window->dropdown#hide" data-dropdown-target="button" class="dropdown-toggle none">
|
102
|
+
Duration <%= inline_svg('filter.svg', class: 'table-filter-icon') %> </button>
|
103
|
+
<div data-controller="checklist" data-dropdown-target="menu" class="dropdown-container hidden">
|
104
|
+
<div class="dropdown-header">
|
105
|
+
Select Duration...
|
106
|
+
<button class="clear-filters" data-action="checklist#checkNone filters#apply">
|
107
|
+
Clear filter
|
108
|
+
</button>
|
109
|
+
</div>
|
110
|
+
<% %w[>100ms >250ms].each do |duration| %>
|
111
|
+
<%= label_tag nil, class: "dropdown-entry" do %>
|
112
|
+
<%= radio_button_tag 'duration', duration, params.fetch(:duration, []).include?(duration),
|
113
|
+
class: "",
|
114
|
+
data: { target: "filters.filter" } %>
|
115
|
+
<%= duration %>
|
116
|
+
<% end %>
|
117
|
+
<% end %>
|
118
|
+
<button class="dropdown-footer" data-action="filters#apply">
|
119
|
+
Apply
|
120
|
+
</button>
|
121
|
+
</div>
|
122
|
+
</th>
|
123
|
+
<th style="width: 15%" class="text-left">Date</th>
|
124
|
+
</tr>
|
125
|
+
</thead>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<tr data-link="<%= profiled_request_path(profiled_request.id) %>">
|
2
|
+
<td class="">
|
3
|
+
<%= label_tag nil do %>
|
4
|
+
<%= check_box_tag 'id[]', profiled_request.id,
|
5
|
+
params.fetch(:selected, []).include?(profiled_request.id),
|
6
|
+
class: "request-checkbox",
|
7
|
+
data: {
|
8
|
+
'selectable-target': 'selectable',
|
9
|
+
'filters-target': 'filter',
|
10
|
+
action: 'click->selectable#onSelected'
|
11
|
+
},
|
12
|
+
onclick: "event.stopPropagation();" %>
|
13
|
+
<% end %>
|
14
|
+
</td>
|
15
|
+
<td class="request-path"><%= profiled_request.request_name %></td>
|
16
|
+
<td class="text-left"> <%= profiled_request.request_method %> </td>
|
17
|
+
<td class="text-left"> <%= profiled_request.response_status %> </td>
|
18
|
+
<td class="text-left"> <%= profiled_request.response_media_type %> </td>
|
19
|
+
<td class="text-left"><%= profiled_request.duration %> ms</td>
|
20
|
+
<td class="text-left"><%= profiled_request.created_at %></td>
|
21
|
+
</tr>
|
@@ -11,14 +11,6 @@ module RailsMiniProfiler
|
|
11
11
|
app.middleware.use(RailsMiniProfiler::Middleware)
|
12
12
|
end
|
13
13
|
|
14
|
-
initializer 'rails_mini_profiler.assets.precompile', group: :all do |app|
|
15
|
-
app.config.assets.precompile += %w[
|
16
|
-
rails_mini_profiler.js
|
17
|
-
rails_mini_profiler/application.css
|
18
|
-
vendor/assets/images
|
19
|
-
]
|
20
|
-
end
|
21
|
-
|
22
14
|
config.generators do |g|
|
23
15
|
g.test_framework :rspec
|
24
16
|
end
|
@@ -26,5 +18,17 @@ module RailsMiniProfiler
|
|
26
18
|
initializer 'rails_mini_profiler_add_static assets' do |app|
|
27
19
|
app.middleware.insert_before(ActionDispatch::Static, ActionDispatch::Static, "#{root}/public")
|
28
20
|
end
|
21
|
+
|
22
|
+
# If sprockets is not being used then there is no need to hook into asset compilation. Calling config.assets
|
23
|
+
# without Sprockets installed breaks compilation.
|
24
|
+
if defined?(Sprockets::Rails)
|
25
|
+
initializer 'rails_mini_profiler.assets.precompile', group: :all do |app|
|
26
|
+
app.config.assets.precompile += %w[
|
27
|
+
rails_mini_profiler.js
|
28
|
+
rails_mini_profiler/application.css
|
29
|
+
vendor/assets/images
|
30
|
+
]
|
31
|
+
end
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
@@ -5,7 +5,7 @@ module RailsMiniProfiler
|
|
5
5
|
def initialize(app)
|
6
6
|
@app = app
|
7
7
|
@config = RailsMiniProfiler.configuration
|
8
|
-
|
8
|
+
Tracing::Subscriptions.setup! { |trace| track_trace(trace) }
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(env)
|
@@ -33,8 +33,8 @@ module RailsMiniProfiler
|
|
33
33
|
def track_trace(event)
|
34
34
|
return if traces.nil?
|
35
35
|
|
36
|
-
trace =
|
37
|
-
traces.append(trace)
|
36
|
+
trace = RailsMiniProfiler::Tracing::TraceFactory.create(event)
|
37
|
+
traces.append(trace) unless trace.is_a?(RailsMiniProfiler::Tracing::NullTrace)
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsMiniProfiler
|
4
|
+
module Tracing
|
5
|
+
class ControllerTracer < Tracer
|
6
|
+
def trace
|
7
|
+
@event[:payload] = @event[:payload]
|
8
|
+
.slice(:view_runtime, :db_runtime)
|
9
|
+
.reject { |_k, v| v.blank? }
|
10
|
+
.transform_values { |value| value&.round(2) }
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsMiniProfiler
|
4
|
+
module Tracing
|
5
|
+
class SequelTracer < Tracer
|
6
|
+
def trace
|
7
|
+
return NullTrace.new if ignore?
|
8
|
+
|
9
|
+
payload = @event[:payload].slice(:name, :sql, :binds, :type_casted_binds)
|
10
|
+
typecasted_binds = payload[:type_casted_binds]
|
11
|
+
# Sometimes, typecasted binds are a proc. Not sure why. In those instances, we extract the typecasted
|
12
|
+
# values from the proc by executing call.
|
13
|
+
typecasted_binds = typecasted_binds.call if typecasted_binds.respond_to?(:call)
|
14
|
+
payload[:binds] = transform_binds(payload[:binds], typecasted_binds)
|
15
|
+
payload.delete(:type_casted_binds)
|
16
|
+
payload.reject { |_k, v| v.blank? }
|
17
|
+
@event[:payload] = payload
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def transform_binds(binds, type_casted_binds)
|
24
|
+
binds.each_with_object([]).with_index do |(binding, object), i|
|
25
|
+
name = binding.name
|
26
|
+
value = type_casted_binds[i]
|
27
|
+
object << { name: name, value: value }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ignore?
|
32
|
+
payload = @event[:payload]
|
33
|
+
!SqlTracker.new(name: payload[:name], query: payload[:sql]).track?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsMiniProfiler
|
4
|
+
module Tracing
|
5
|
+
class SqlTracker
|
6
|
+
TRACKED_SQL_COMMANDS = %w[SELECT INSERT UPDATE DELETE].freeze
|
7
|
+
UNTRACKED_NAMES = %w[SCHEMA].freeze
|
8
|
+
UNTRACKED_TABLES = %w[
|
9
|
+
SCHEMA_MIGRATIONS
|
10
|
+
SQLITE_MASTER
|
11
|
+
ACTIVE_MONITORING_METRICS
|
12
|
+
SQLITE_TEMP_MASTER
|
13
|
+
SQLITE_VERSION
|
14
|
+
AR_INTERNAL_METADATA
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
def initialize(query:, name:)
|
18
|
+
@query = query.to_s.upcase
|
19
|
+
@name = name.to_s.upcase
|
20
|
+
end
|
21
|
+
|
22
|
+
def track?
|
23
|
+
query.start_with?(*TRACKED_SQL_COMMANDS) &&
|
24
|
+
!name.start_with?(*UNTRACKED_NAMES) &&
|
25
|
+
!untracked_tables?
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :query, :name
|
31
|
+
|
32
|
+
def untracked_tables?
|
33
|
+
UNTRACKED_TABLES.any? { |table| query.include?(table) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|