query-trace-summary 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59f45bb76097ce37b3b06322754ea53671944995a65a20fbd6b48701b5ab2973
4
+ data.tar.gz: 88bb0e298bc0c15ebfac7da535e24b021b48eae73b7988991dd1f79be48f0262
5
+ SHA512:
6
+ metadata.gz: 182fc7195b82176c6e6c35750e2fa61ff7921a3dc04b3d54ee59327e7be4850e14ff371f995702f3bee000234aa49276f6b335117b5e24c9f7212787b83dd78e
7
+ data.tar.gz: ccffeb7eded79d613fc05154ae0161e2d07572cfbc651ecd912a84f772bba90e22427ef3f265e619d6d9b54cfe4ea3cf02cb35413a5580130224b481f0c2a58b
data/lib/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'query-trace-summary'
2
+
3
+ path = File.expand_path(__dir__)
4
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| import f }
@@ -0,0 +1,66 @@
1
+ require 'bigdecimal'
2
+
3
+ module QueryTraceSummary
4
+ class EventSummary
5
+ attr_accessor :model, :action, :location, :total_time, :calls
6
+
7
+ ASCII_COLOR_RX = /\e\[\d+m/
8
+ EVENT_RX = /([A-Z][A-Za-z0-9_:]+) (Create|Load|Update|Destroy) \((\d+(?:\.\d+)?)ms\)/
9
+
10
+ # Assumes conservative file naming
11
+ LOCATION_RX = /([a-zA-Z0-9_.\-\/]+:\d+:in `.+')$/
12
+
13
+ def initialize(model, action, location)
14
+ @model = model
15
+ @action = action
16
+ @location = location
17
+ @total_time = @calls = 0
18
+ end
19
+
20
+ # Gathers all of the events in provided files
21
+ # and returns array of event summaries
22
+ # sorted in descending order by their total time
23
+ def self.parse_files(*file_names)
24
+ events = {}
25
+
26
+ event_match = nil
27
+
28
+ each_line(*file_names) do |line|
29
+ # Previous line was an event
30
+ if event_match
31
+ location_match = LOCATION_RX.match(line)
32
+ if location_match
33
+ model, action, time = event_match.captures
34
+ location = location_match.captures.first
35
+
36
+ key = "#{model}/#{action}/#{location}"
37
+
38
+ event = events[key] ||= new(model, action, location)
39
+ event.calls += 1
40
+ event.total_time += time.to_d
41
+
42
+ event_match = nil
43
+
44
+ next
45
+ end
46
+ end
47
+
48
+ event_match = EVENT_RX.match(line)
49
+ end
50
+
51
+ events.values.sort_by { |summary| -summary.total_time }
52
+ end
53
+
54
+ private
55
+
56
+ def self.each_line(*file_names)
57
+ file_names.each do |file_name|
58
+ File.foreach(file_name) do |line|
59
+ # Strip ASCII color codes
60
+ line = line.gsub(ASCII_COLOR_RX, '')
61
+ yield line
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ module QueryTraceSummary
2
+ require 'railtie' if defined?(Rails)
3
+ end
4
+
5
+ require 'event_summary'
data/lib/railtie.rb ADDED
@@ -0,0 +1,8 @@
1
+ module QueryTraceSummary
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ path = File.expand_path(__dir__)
5
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require 'csv'
2
+
3
+ namespace :query_trace_summary do
4
+ desc "Prints CSV-formatted summary for queries in log file(s)"
5
+ task :csv do |t|
6
+ file_names = ARGV[1..-1]
7
+ if file_names.length == 0
8
+ puts "Usage: rake #{t.name} <log-file>..."
9
+ exit
10
+ end
11
+
12
+ summaries = QueryTraceSummary::EventSummary.parse_files(*file_names)
13
+ csv = CSV.generate do |csv|
14
+ csv << ['Total time', 'Calls', 'Action', 'Model', 'Location']
15
+ summaries.each do |s|
16
+ csv << [s.total_time, s.calls, s.action, s.model, s.location]
17
+ end
18
+ end
19
+
20
+ puts csv
21
+ exit
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ namespace :query_trace_summary do
2
+ desc "Prints top 10 time-consuming queries in log file(s)"
3
+ task :top10 do |t|
4
+ file_names = ARGV[1..-1]
5
+ if file_names.length == 0
6
+ puts "Usage: rake #{t.name} <log-file>..."
7
+ exit
8
+ end
9
+
10
+ summaries = QueryTraceSummary::EventSummary.parse_files(*file_names)
11
+ summaries = summaries[0..9]
12
+
13
+ lines = summaries.map do |s|
14
+ [
15
+ "#{s.total_time}ms",
16
+ "#{s.calls} calls",
17
+ s.action,
18
+ s.model,
19
+ s.location
20
+ ]
21
+ end
22
+
23
+ # Align output columns
24
+ lengths = lines.map { |l| l.map(&:length) }
25
+ col_widths = lengths.transpose.map(&:max)
26
+
27
+ lines.each do |l|
28
+ l[0] = l[0].rjust(col_widths[0])
29
+ l[1] = l[1].rjust(col_widths[1])
30
+ l[2] = l[2].ljust(col_widths[2])
31
+ l[3] = l[3].ljust(col_widths[3])
32
+
33
+ puts l.join(' ')
34
+ end
35
+
36
+ exit
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: query-trace-summary
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mārtiņš Veiskats
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-09-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Generates summary of time consumed by database queries. Helpful to pinpoint
14
+ where to focus optimization efforts.
15
+ email: martins.veiskats@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/Rakefile
21
+ - lib/event_summary.rb
22
+ - lib/query-trace-summary.rb
23
+ - lib/railtie.rb
24
+ - lib/tasks/csv.rake
25
+ - lib/tasks/top10.rake
26
+ homepage: https://github.com/mveiskats/query-trace-summary
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubygems_version: 3.0.3
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Generates summary of time consumed by database queries. Helpful to pinpoint
49
+ where to focus optimization efforts.
50
+ test_files: []