active-record-query-count 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/assets/style.css +8 -8
- data/assets/template_base_query_counter.html.erb +9 -6
- data/lib/active-record-query-count.rb +22 -13
- data/lib/active_record_query_count/configuration.rb +0 -1
- data/lib/active_record_query_count/printer/base.rb +7 -0
- data/lib/active_record_query_count/printer/console.rb +2 -2
- data/lib/active_record_query_count/printer/html.rb +11 -7
- data/lib/active_record_query_count/printer/html_compare.rb +2 -6
- data/lib/active_record_query_count/recording/tracker.rb +34 -28
- data/lib/active_record_query_count/version.rb +1 -1
- data/scripts_for_testing/script_compare_html.rb +1 -1
- data/scripts_for_testing/script_printer_html.rb +1 -1
- data/scripts_for_testing/scripts_console.rb.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d095bdca093b9cc7bf7f2e765855daa33c256a6eb6a23f7e7efb70001675f881
|
4
|
+
data.tar.gz: 50cf40d3cd40b1ee75096a5518e83289739fcbe381afa484d9db6c4395370a83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c13044996330b7784b78afef3a0243d9199c9f694ce5998d9349db9e2fc930d33f22e5425dc235c653c3d1c2283bf811dd484c7ffa7363c606ac0a191d7cfddb
|
7
|
+
data.tar.gz: c8f60440c96860f2dff53cd739718a1c28815de9113a7a323def118dbcb63b72442368ef1f90a24ed026c9c5d74c223a14e083ed57c0ae2a3f3988abebe20a8c
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# ActiveRecordQueryCount
|
2
2
|
|
3
|
-
`ActiveRecordQueryCount` is a Ruby gem designed to help you visualize and track SQL queries executed by your ActiveRecord models
|
3
|
+
`ActiveRecordQueryCount` is a Ruby gem designed to help you visualize and track the SQL queries executed by your ActiveRecord models within a block of code.
|
4
4
|
|
5
|
-
By subscribing to ActiveSupport notifications, it provides detailed insights into the
|
5
|
+
By subscribing to ActiveSupport notifications, it provides detailed insights into the number of queries being run, the time taken by the code at specific locations (by adding the time each query took in that place), the tables involved, and the locations in your code where the queries were generated.
|
6
6
|
|
7
|
-
|
7
|
+
This gem offers three key features:
|
8
8
|
|
9
|
-
1.
|
10
|
-
2. Benchmark two blocks of code to
|
11
|
-
3.
|
9
|
+
1. View an overview of all queries executed by a block of code, including the time taken and their origin locations, presented in a graph, an HTML table, or directly in the console.
|
10
|
+
2. Benchmark two blocks of code to compare SQL query counts at different locations, with results displayed in a graph or table.
|
11
|
+
3. Get an overview of SQL queries for the current request in a controller action, accessible via a button in the top-left corner of the screen.
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
data/assets/style.css
CHANGED
@@ -4,10 +4,9 @@
|
|
4
4
|
width: 100%;
|
5
5
|
border-collapse: collapse;
|
6
6
|
margin-top: 20px;
|
7
|
-
|
8
7
|
height: 100%;
|
9
|
-
overflow:auto;
|
10
|
-
display: block;
|
8
|
+
overflow: auto;
|
9
|
+
display: block;
|
11
10
|
box-sizing: border-box;
|
12
11
|
}
|
13
12
|
th, td {
|
@@ -17,11 +16,12 @@
|
|
17
16
|
th {
|
18
17
|
background-color: #f2f2f2;
|
19
18
|
}
|
20
|
-
tr
|
21
|
-
background-color: #
|
19
|
+
tr.main-row.even, tr.sub-row.even {
|
20
|
+
background-color: #f2f2f2;
|
22
21
|
}
|
23
|
-
|
24
|
-
|
22
|
+
|
23
|
+
tr.main-row.odd, tr.sub-row.odd {
|
24
|
+
background-color: #ffffff;
|
25
25
|
}
|
26
26
|
|
27
27
|
.center-container {
|
@@ -39,4 +39,4 @@
|
|
39
39
|
#queryTable {
|
40
40
|
display: table;
|
41
41
|
}
|
42
|
-
}
|
42
|
+
}
|
@@ -3,9 +3,10 @@
|
|
3
3
|
</style>
|
4
4
|
<div id='query_counter_report_gem'>
|
5
5
|
<h2>Query Count Report</h2>
|
6
|
-
<p>Total
|
7
|
-
<p>
|
8
|
-
<p>Only
|
6
|
+
<p>Total number of queries in this process: <%= total_query_count %></p>
|
7
|
+
<p>Total time spent on queries in this process (ms): <%= total_duration_time %></p>
|
8
|
+
<p>Only tables with <%= ::ActiveRecordQueryCount::Configuration.ignore_table_count %> or more queries will be displayed.</p>
|
9
|
+
<p>The top <%= ::ActiveRecordQueryCount::Configuration.max_locations_per_table %> locations with the highest occurrences will be shown for each table.</p>
|
9
10
|
<button id="toggleButton" onclick="toggleView()">Show Chart View</button>
|
10
11
|
<button id="toggleColumnButton" onclick="toggleColumnContent()">Show SQL</button>
|
11
12
|
|
@@ -19,14 +20,15 @@
|
|
19
20
|
<th id="columnHeader">File Path</th>
|
20
21
|
<th>Method</th>
|
21
22
|
<th>Location Count</th>
|
23
|
+
<th>Total Duration(ms)</th>
|
22
24
|
</tr>
|
23
|
-
<% filter_data(data).
|
24
|
-
<tr>
|
25
|
+
<% filter_data(data).each_with_index do |(table, info), index| %>
|
26
|
+
<tr class="main-row <%= index.even? ? 'even' : 'odd' %>">
|
25
27
|
<td rowspan="<%= info[:location].size + 1 %>"><%= table %></td>
|
26
28
|
<td rowspan="<%= info[:location].size + 1 %>"><%= info[:count] %></td>
|
27
29
|
</tr>
|
28
30
|
<% info[:location].each do |loc, detail| %>
|
29
|
-
<tr class="sub-row">
|
31
|
+
<tr class="sub-row <%= index.even? ? 'even' : 'odd' %>">
|
30
32
|
<% match = loc&.match(/^(?<file_path>.*):in.*`(?<method>.*)'$/) %>
|
31
33
|
<% file_path = match ? match[:file_path] : loc %>
|
32
34
|
<% method = match ? match[:method] : nil %>
|
@@ -36,6 +38,7 @@
|
|
36
38
|
</td>
|
37
39
|
<td class="method-column"><%= method %></td>
|
38
40
|
<td><%= detail[:count] %></td>
|
41
|
+
<td><%= detail[:duration] %></td>
|
39
42
|
</tr>
|
40
43
|
<% end %>
|
41
44
|
<% end %>
|
@@ -1,17 +1,26 @@
|
|
1
|
-
require 'active_support/notifications'
|
2
|
-
require_relative 'active_record_query_count/version'
|
3
|
-
require_relative 'active_record_query_count/configuration'
|
4
|
-
require_relative 'active_record_query_count/printer/base'
|
5
|
-
require_relative 'active_record_query_count/printer/console'
|
6
|
-
require_relative 'active_record_query_count/printer/html'
|
7
|
-
require_relative 'active_record_query_count/recording/base'
|
8
|
-
require_relative 'active_record_query_count/recording/tracker'
|
9
|
-
require_relative 'active_record_query_count/compare/comparator'
|
10
|
-
require_relative 'active_record_query_count/middleware'
|
11
|
-
require_relative 'active_record_query_count/printer/html_compare'
|
12
|
-
|
13
1
|
module ActiveRecordQueryCount
|
2
|
+
autoload :VERSION, 'active_record_query_count/version'
|
3
|
+
autoload :Configuration, 'active_record_query_count/configuration'
|
4
|
+
autoload :Middleware, 'active_record_query_count/middleware'
|
5
|
+
|
6
|
+
module Printer
|
7
|
+
autoload :Base, 'active_record_query_count/printer/base'
|
8
|
+
autoload :Console, 'active_record_query_count/printer/console'
|
9
|
+
autoload :Html, 'active_record_query_count/printer/html'
|
10
|
+
autoload :HtmlCompare, 'active_record_query_count/printer/html_compare'
|
11
|
+
end
|
12
|
+
|
13
|
+
module Recording
|
14
|
+
autoload :Base, 'active_record_query_count/recording/base'
|
15
|
+
autoload :Tracker, 'active_record_query_count/recording/tracker'
|
16
|
+
end
|
17
|
+
|
18
|
+
module Compare
|
19
|
+
autoload :Comparator, 'active_record_query_count/compare/comparator'
|
20
|
+
end
|
21
|
+
|
14
22
|
extend Recording::Base
|
23
|
+
|
15
24
|
if defined?(Rails::Railtie)
|
16
25
|
class QueryCountRailtie < Rails::Railtie
|
17
26
|
initializer 'active_record_query_count.configure_rails_initialization' do |app|
|
@@ -26,7 +35,7 @@ module ActiveRecordQueryCount
|
|
26
35
|
end
|
27
36
|
|
28
37
|
def tracker
|
29
|
-
Thread.current[:query_counter_data] ||= Tracker.new
|
38
|
+
Thread.current[:query_counter_data] ||= Recording::Tracker.new
|
30
39
|
end
|
31
40
|
|
32
41
|
def compare
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'json'
|
1
2
|
module ActiveRecordQueryCount
|
2
3
|
module Printer
|
3
4
|
class Base
|
@@ -11,6 +12,11 @@ module ActiveRecordQueryCount
|
|
11
12
|
INJECT_TEMPLATE_PATH = File.join(parent_dir, 'assets', 'template_for_inject.html.erb')
|
12
13
|
|
13
14
|
def filter_data data
|
15
|
+
data.each_value do |info|
|
16
|
+
info[:location].each_value do |detail|
|
17
|
+
detail[:duration] = detail[:duration].truncate(2)
|
18
|
+
end
|
19
|
+
end
|
14
20
|
data = data.select { |_, v| v[:count] >= Configuration.ignore_table_count }
|
15
21
|
data = data.sort_by { |_, v| -v[:count] }.each do |_category, info|
|
16
22
|
info[:location] = info[:location].sort_by do |_, detail|
|
@@ -30,6 +36,7 @@ module ActiveRecordQueryCount
|
|
30
36
|
end
|
31
37
|
|
32
38
|
def open_file html_dest
|
39
|
+
require 'launchy'
|
33
40
|
if ENV['WSL_DISTRIBUTION']
|
34
41
|
Launchy.open("file://wsl%24/#{ENV['WSL_DISTRIBUTION']}#{html_dest}")
|
35
42
|
else
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'colorize'
|
2
|
-
|
3
1
|
module ActiveRecordQueryCount
|
4
2
|
module Printer
|
5
3
|
class Console < Base
|
@@ -9,6 +7,7 @@ module ActiveRecordQueryCount
|
|
9
7
|
end
|
10
8
|
|
11
9
|
def print
|
10
|
+
require 'colorize'
|
12
11
|
data = filter_data(@data)
|
13
12
|
puts '[ActiveRecordQueryCount] Query count per table:'.colorize(:blue)
|
14
13
|
puts "Total query count: #{data.values.sum { |v| v[:count] }}\n\n"
|
@@ -21,6 +20,7 @@ module ActiveRecordQueryCount
|
|
21
20
|
info[:location].each do |loc, details|
|
22
21
|
puts " - File location: #{loc}"
|
23
22
|
puts " Query count: #{details[:count].to_s.colorize(:blue)}"
|
23
|
+
puts " Total Duration(ms): #{details[:duration]}"
|
24
24
|
end
|
25
25
|
puts
|
26
26
|
end
|
@@ -1,8 +1,4 @@
|
|
1
1
|
require 'erb'
|
2
|
-
require 'tempfile'
|
3
|
-
require 'launchy'
|
4
|
-
require 'pry-byebug'
|
5
|
-
require 'json'
|
6
2
|
|
7
3
|
module ActiveRecordQueryCount
|
8
4
|
module Printer
|
@@ -14,13 +10,21 @@ module ActiveRecordQueryCount
|
|
14
10
|
end
|
15
11
|
|
16
12
|
def chart_data
|
17
|
-
@chart_data ||=
|
13
|
+
@chart_data ||= generate_chart_js_data(data)
|
18
14
|
end
|
19
15
|
|
20
16
|
def total_query_count
|
21
17
|
@total_query_count ||= data.values.sum { |v| v[:count] }
|
22
18
|
end
|
23
19
|
|
20
|
+
def total_duration_time
|
21
|
+
@total_duration_time ||= data.sum do |_, info|
|
22
|
+
info[:location].sum do |_, detail|
|
23
|
+
detail[:duration]
|
24
|
+
end
|
25
|
+
end.truncate(2)
|
26
|
+
end
|
27
|
+
|
24
28
|
def inject_in_html
|
25
29
|
ERB.new(inject_template_content).result(binding)
|
26
30
|
end
|
@@ -36,13 +40,13 @@ module ActiveRecordQueryCount
|
|
36
40
|
|
37
41
|
private
|
38
42
|
|
39
|
-
def
|
43
|
+
def generate_chart_js_data(data)
|
40
44
|
chart_data = { labels: [], data: [], locations: {} }
|
41
45
|
data.each do |table, info|
|
42
46
|
chart_data[:labels] << table
|
43
47
|
chart_data[:data] << info[:count]
|
44
48
|
chart_data[:locations][table] = info[:location].map do |loc, detail|
|
45
|
-
{ location: loc, count: detail[:count] }
|
49
|
+
{ location: loc, count: detail[:count], duration: detail[:duration] }
|
46
50
|
end
|
47
51
|
end
|
48
52
|
chart_data
|
@@ -1,8 +1,4 @@
|
|
1
1
|
require 'erb'
|
2
|
-
require 'tempfile'
|
3
|
-
require 'launchy'
|
4
|
-
require 'pry-byebug'
|
5
|
-
require 'json'
|
6
2
|
|
7
3
|
module ActiveRecordQueryCount
|
8
4
|
module Printer
|
@@ -25,7 +21,7 @@ module ActiveRecordQueryCount
|
|
25
21
|
tables = data_1.keys | data_2.keys
|
26
22
|
total_query_count_1 = data_1.values.sum { |v| v[:count] }
|
27
23
|
total_query_count_2 = data_2.values.sum { |v| v[:count] }
|
28
|
-
chart_data =
|
24
|
+
chart_data = generate_chart_js_data_compare(data_1, data_2)
|
29
25
|
# end
|
30
26
|
html_dest = generate_html(binding)
|
31
27
|
open_file(html_dest)
|
@@ -33,7 +29,7 @@ module ActiveRecordQueryCount
|
|
33
29
|
|
34
30
|
private
|
35
31
|
|
36
|
-
def
|
32
|
+
def generate_chart_js_data_compare(data_1, data_2)
|
37
33
|
labels = (data_1.keys | data_2.keys).sort
|
38
34
|
chart_data = { labels: [], data_1: {}, data_2: {}, locations: {} }
|
39
35
|
chart_data[:data_1][:name] = @script_1_name
|
@@ -1,40 +1,46 @@
|
|
1
|
+
require 'active_support/notifications'
|
2
|
+
|
1
3
|
module ActiveRecordQueryCount
|
2
|
-
|
3
|
-
|
4
|
-
|
4
|
+
module Recording
|
5
|
+
class Tracker
|
6
|
+
REGEX_TABLE_SQL = /FROM\s+"(?<table>[^"]+)"/
|
7
|
+
attr_accessor :active_record_query_tracker, :subscription
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
def initialize
|
10
|
+
reset_query_count
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
# This assums that in the same location of the code it will always be the same sql query
|
14
|
+
def reset_query_count
|
15
|
+
@active_record_query_tracker = Hash.new do |hash, key|
|
16
|
+
hash[key] = { count: 0, location: Hash.new do |loc_hash, loc_key|
|
17
|
+
loc_hash[loc_key] = { count: 0, sql: nil }
|
18
|
+
end }
|
19
|
+
end
|
16
20
|
end
|
17
|
-
end
|
18
21
|
|
19
|
-
|
20
|
-
|
22
|
+
def subscribe
|
23
|
+
return unless subscription.nil?
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
@subscription = ActiveSupport::Notifications.subscribe('sql.active_record') do |_a, start, finish, _d, payload|
|
26
|
+
caller_from_sql = caller
|
27
|
+
sql = payload[:sql]
|
28
|
+
match = sql.match(REGEX_TABLE_SQL)
|
29
|
+
if match.present? && match[:table]
|
30
|
+
actual_location = Rails.backtrace_cleaner.clean(caller_from_sql).first
|
31
|
+
active_record_query_tracker[match[:table]][:count] += 1
|
32
|
+
active_record_query_tracker[match[:table]][:location][actual_location][:duration] ||= 0
|
33
|
+
active_record_query_tracker[match[:table]][:location][actual_location][:duration] += (finish - start) * 1000
|
34
|
+
active_record_query_tracker[match[:table]][:location][actual_location][:count] += 1
|
35
|
+
active_record_query_tracker[match[:table]][:location][actual_location][:sql] = sql
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
|
-
end
|
34
39
|
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
def unsubscribe
|
41
|
+
ActiveSupport::Notifications.unsubscribe(@subscription)
|
42
|
+
@subscription = nil
|
43
|
+
end
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active-record-query-count
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jose Lara
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -265,7 +265,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
265
265
|
requirements:
|
266
266
|
- - ">="
|
267
267
|
- !ruby/object:Gem::Version
|
268
|
-
version: '
|
268
|
+
version: '3.0'
|
269
269
|
- - "<"
|
270
270
|
- !ruby/object:Gem::Version
|
271
271
|
version: '4.0'
|
@@ -275,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
275
275
|
- !ruby/object:Gem::Version
|
276
276
|
version: '0'
|
277
277
|
requirements: []
|
278
|
-
rubygems_version: 3.
|
278
|
+
rubygems_version: 3.5.15
|
279
279
|
signing_key:
|
280
280
|
specification_version: 4
|
281
281
|
summary: Display an overview of the quantity of queries being made and their origins
|