active_record_query_trace 1.5.4 → 1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 45e5fb5ece85b56cde741aab63f6d4ef1cdd4674
4
- data.tar.gz: 75090841d4650bd2ebde1517fc040fec661a25a1
2
+ SHA256:
3
+ metadata.gz: dafae1b675da678759ad1ba18101f418fb97193f178a57dcb98442e0760f2e1a
4
+ data.tar.gz: 9748c99d235fef46ef85f432c0419191e05baccd9c28be61f7e090c9cac356ad
5
5
  SHA512:
6
- metadata.gz: 0a1ff57686ca621ef4cd4ed12dadcb0bd6b4f9b2f425492bf3d814e74ff4e4e362ad24985b17f0ccc4ea6f83c8e5f631834ba3cedb9401204cd6dfbb9b3eb377
7
- data.tar.gz: 676166a2fa21b3975290260fba1d8bc83db77a25a765a33bd800a5eb9f8266f823b1da0d3c6e8d181ad37ee92e98ccbfe0bb05e73fc8a54175c2a381133b13b2
6
+ metadata.gz: 6b40a57407d833bdd54c45a0db89592dbcd5ead14e4b17cc78d3e9f6c33614163f67a57c75969c2c59396fb544eb96e390943265fe7bd0fd9fc57494cce0d985
7
+ data.tar.gz: e6a1d216f71480d97d0d254c03de448838ece938af770cf80602ee1cae92f1c5988379d0826551f5dda1eed9a80f3a8b33455e97f63022179665cd61c21e9c6b
@@ -1,7 +1,29 @@
1
- # encoding: UTF-8
2
- require 'active_support/log_subscriber'
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/log_subscriber'
3
4
 
4
5
  module ActiveRecordQueryTrace
6
+ INDENTATION = ' ' * 6
7
+ BACKTRACE_PREFIX = "Query Trace:\n#{INDENTATION}"
8
+ COLORS = {
9
+ true => '38',
10
+ blue: '34',
11
+ light_red: '1;31',
12
+ black: '30',
13
+ purple: '35',
14
+ light_green: '1;32',
15
+ red: '31',
16
+ cyan: '36',
17
+ yellow: '1;33',
18
+ green: '32',
19
+ gray: '37',
20
+ light_blue: '1;34',
21
+ brown: '33',
22
+ dark_gray: '1;30',
23
+ light_purple: '1;35',
24
+ white: '1;37',
25
+ light_cyan: '1;36'
26
+ }.freeze
5
27
 
6
28
  class << self
7
29
  attr_accessor :enabled
@@ -9,89 +31,174 @@ module ActiveRecordQueryTrace
9
31
  attr_accessor :lines
10
32
  attr_accessor :ignore_cached_queries
11
33
  attr_accessor :colorize
34
+ attr_accessor :query_type
35
+ attr_accessor :suppress_logging_of_db_reads
12
36
  end
13
37
 
14
- module ActiveRecord
15
- class LogSubscriber < ActiveSupport::LogSubscriber
38
+ class CustomLogSubscriber < ActiveRecord::LogSubscriber
39
+ def initialize
40
+ super
41
+ ActiveRecordQueryTrace.enabled = false
42
+ ActiveRecordQueryTrace.level = :app
43
+ ActiveRecordQueryTrace.lines = 5
44
+ ActiveRecordQueryTrace.ignore_cached_queries = false
45
+ ActiveRecordQueryTrace.colorize = false
46
+ ActiveRecordQueryTrace.query_type = :all
47
+ ActiveRecordQueryTrace.suppress_logging_of_db_reads = false
48
+ end
16
49
 
17
- def initialize
18
- super
19
- ActiveRecordQueryTrace.enabled = false
20
- ActiveRecordQueryTrace.level = :app
21
- ActiveRecordQueryTrace.lines = 5
22
- ActiveRecordQueryTrace.ignore_cached_queries = false
23
- ActiveRecordQueryTrace.colorize = false
50
+ def sql(event)
51
+ payload = event.payload
52
+ return unless display_backtrace?(payload)
24
53
 
25
- if ActiveRecordQueryTrace.level != :app
26
- # Rails by default silences all backtraces that match Rails::BacktraceCleaner::APP_DIRS_PATTERN
27
- Rails.backtrace_cleaner.remove_silencers!
28
- end
29
- end
54
+ setup_backtrace_cleaner
30
55
 
31
- def sql(event)
32
- if ActiveRecordQueryTrace.enabled
33
- index = begin
34
- if ActiveRecordQueryTrace.lines == 0
35
- 0..-1
36
- else
37
- 0..(ActiveRecordQueryTrace.lines - 1)
38
- end
39
- end
40
-
41
- payload = event.payload
42
- return if payload[:name] == 'SCHEMA'
43
- return if ActiveRecordQueryTrace.ignore_cached_queries && payload[:name] == 'CACHE'
44
-
45
- cleaned_trace = clean_trace(caller)[index].join("\n from ")
46
- debug(" Query Trace > " + colorize_text(cleaned_trace)) unless cleaned_trace.blank?
47
- end
56
+ trace = fully_formatted_trace # Memoize
57
+ debug(trace) unless trace.blank?
58
+ end
59
+
60
+ attach_to :active_record
61
+
62
+ private
63
+
64
+ # rubocop:disable Metrics/CyclomaticComplexity
65
+ # rubocop:disable Metrics/PerceivedComplexity
66
+ # TODO: refactor and remove rubocop:disable comments.
67
+ def display_backtrace?(payload)
68
+ ActiveRecordQueryTrace.enabled \
69
+ && !transaction_begin_or_commit_query?(payload) \
70
+ && !schema_query?(payload) \
71
+ && !(ActiveRecordQueryTrace.ignore_cached_queries && payload[:cached]) \
72
+ && !(ActiveRecordQueryTrace.suppress_logging_of_db_reads && db_read_query?(payload)) \
73
+ && display_backtrace_for_query_type?(payload)
74
+ end
75
+ # rubocop:enable Metrics/CyclomaticComplexity
76
+ # rubocop:enable Metrics/PerceivedComplexity
77
+
78
+ def display_backtrace_for_query_type?(payload)
79
+ invalid_type_msg = 'Invalid ActiveRecordQueryTrace.query_type value ' \
80
+ "#{ActiveRecordQueryTrace.level}. Should be :all, :read, or :write."
81
+
82
+ case ActiveRecordQueryTrace.query_type
83
+ when :all then true
84
+ when :read then db_read_query?(payload)
85
+ when :write then !db_read_query?(payload)
86
+ else raise(invalid_type_msg)
48
87
  end
88
+ end
49
89
 
50
- # Allow query to be colorized in the terminal
51
- def colorize_text(text)
52
- return text unless ActiveRecordQueryTrace.colorize
53
- # Try to convert the choosen color from string to integer or try
54
- # to use the colorize as the color code
55
- colors = {
56
- true => "38", "blue" => "34", "light red" => "1;31",
57
- "black" => "30", "purple" => "35", "light green" => "1;32",
58
- "red" => "31", "cyan" => "36", "yellow" => "1;33",
59
- "green" => "32", "gray" => "37", "light blue" => "1;34",
60
- "brown" => "33", "dark gray" => "1;30", "light purple" => "1;35",
61
- "white" => "1;37", "light cyan" => "1;36"
62
- }
63
- color_code = colors[ActiveRecordQueryTrace.colorize] ||
64
- ActiveRecordQueryTrace.colorize.to_s
65
- unless /\d+(;\d+){0,1}/.match(color_code)
66
- raise "Invalid color. Use one of #{ colors.keys } or a valid color code"
67
- end
68
- "\e[#{ color_code }m#{ text }\e[0m"
90
+ def db_read_query?(payload)
91
+ !payload[:sql].match(/(INSERT|UPDATE|DELETE)/)
92
+ end
93
+
94
+ def fully_formatted_trace
95
+ cleaned_trace = clean_trace(original_trace)
96
+ return if cleaned_trace.blank?
97
+ stringified_trace = BACKTRACE_PREFIX + lines_to_display(cleaned_trace).join("\n" + INDENTATION)
98
+ colorize_text(stringified_trace)
99
+ end
100
+
101
+ # Must be called after the backtrace cleaner.
102
+ def lines_to_display(full_trace)
103
+ ActiveRecordQueryTrace.lines.zero? ? full_trace : full_trace.first(ActiveRecordQueryTrace.lines)
104
+ end
105
+
106
+ def transaction_begin_or_commit_query?(payload)
107
+ payload[:sql].match(/\A(begin transaction|commit transaction|BEGIN|COMMIT)\Z/)
108
+ end
109
+
110
+ def schema_query?(payload)
111
+ payload[:name] == 'SCHEMA'
112
+ end
113
+
114
+ def clean_trace(full_trace)
115
+ invalid_level_msg = 'Invalid ActiveRecordQueryTrace.level value ' \
116
+ "#{ActiveRecordQueryTrace.level}. Should be :full, :rails, or :app."
117
+ raise(invalid_level_msg) unless %i[full app rails].include?(ActiveRecordQueryTrace.level)
118
+
119
+ trace = ActiveRecordQueryTrace.level == :full ? full_trace : Rails.backtrace_cleaner.clean(full_trace)
120
+ # We cant use a Rails::BacktraceCleaner filter to display only the relative
121
+ # path of application trace lines because it breaks the silencer that selects
122
+ # the lines to display or hide based on whether they include `Rails.root`.
123
+ trace.map { |line| line.gsub("#{Rails.root}/", '') }
124
+ end
125
+
126
+ # Rails by default silences all backtraces that *do not* match
127
+ # Rails::BacktraceCleaner::APP_DIRS_PATTERN. In other words, the default
128
+ # silencer filters out all framework backtrace lines, leaving only the
129
+ # application lines.
130
+ def setup_backtrace_cleaner
131
+ setup_backtrace_cleaner_path
132
+ return unless ActiveRecordQueryTrace.level == :rails
133
+ Rails.backtrace_cleaner.remove_filters!
134
+ Rails.backtrace_cleaner.remove_silencers!
135
+ Rails.backtrace_cleaner.add_silencer do |line|
136
+ line.match(%r{#{Regexp.escape(Rails.root.to_s)}(?!/vendor)})
69
137
  end
138
+ end
70
139
 
71
- def clean_trace(trace)
72
- # Rails relies on backtrace cleaner to set the application root directory filter
73
- # the problem is that the backtrace cleaner is initialized before the application
74
- # this ensures that the value of `root` used by the filter is set to the application root
75
- if Rails.backtrace_cleaner.instance_variable_get(:@root) == '/'
76
- Rails.backtrace_cleaner.instance_variable_set :@root, Rails.root.to_s
77
- end
140
+ # Rails relies on backtrace cleaner to set the application root directory
141
+ # filter. The problem is that the backtrace cleaner is initialized before
142
+ # this gem. This ensures that the value of `root` used by the filter
143
+ # is correct.
144
+ def setup_backtrace_cleaner_path
145
+ return unless Rails.backtrace_cleaner.instance_variable_get(:@root) == '/'
146
+ Rails.backtrace_cleaner.instance_variable_set :@root, Rails.root.to_s
147
+ end
148
+
149
+ # Allow query to be colorized in the terminal
150
+ def colorize_text(text)
151
+ return text unless ActiveRecordQueryTrace.colorize
152
+ "\e[#{color_code}m#{text}\e[0m"
153
+ end
154
+
155
+ # Wrapper used for testing purposes.
156
+ def original_trace
157
+ caller
158
+ end
78
159
 
79
- case ActiveRecordQueryTrace.level
80
- when :full
81
- trace
82
- when :rails
83
- Rails.respond_to?(:backtrace_cleaner) ? Rails.backtrace_cleaner.clean(trace) : trace
84
- when :app
85
- Rails.backtrace_cleaner.remove_silencers!
86
- Rails.backtrace_cleaner.add_silencer { |line| not line =~ /^(app|lib|engines)\// }
87
- Rails.backtrace_cleaner.clean(trace)
88
- else
89
- raise "Invalid ActiveRecordQueryTrace.level value '#{ActiveRecordQueryTrace.level}' - should be :full, :rails, or :app"
160
+ def color_code
161
+ # Backward compatibility for string color names with space as word separator.
162
+ color_code =
163
+ case ActiveRecordQueryTrace.colorize
164
+ when Symbol then COLORS[ActiveRecordQueryTrace.colorize]
165
+ when String then COLORS[ActiveRecordQueryTrace.colorize.tr("\s", '_').to_sym]
90
166
  end
91
- end
92
167
 
93
- attach_to :active_record
168
+ error_msg = 'ActiveRecordQueryTrace.colorize was set to an invalid ' \
169
+ "color. Use one of #{COLORS.keys} or a valid color code."
170
+
171
+ raise error_msg unless valid_color_code?(color_code)
172
+ color_code
173
+ end
94
174
 
175
+ def valid_color_code?(color_code)
176
+ /\A\d+(;\d+)?\Z/.match(color_code)
95
177
  end
96
178
  end
97
179
  end
180
+
181
+ # The following code is used to suppress specific entries from the log. The
182
+ # "around alias" technique is used to allow `ActiveSupport::LogSubscriber#debug`
183
+ # to be overwritten while preserving the original version, which can still be
184
+ # called.
185
+ #
186
+ # I would prefer using Module#prepend here, but alias_method does not work if
187
+ # called from within a prepended module.
188
+ #
189
+ # Note that:
190
+ # - #debug is used to log queries but also other things, do not mess it up.
191
+ # - Some queries include both SELECT and a write operation such as INSERT,
192
+ # UPDATE or DELETE. That means that checking for the presence of SELECT is not
193
+ # enough to ensure it is not a write query.
194
+ #
195
+ # TODO: move to a separate file.
196
+ ActiveSupport::LogSubscriber.class_eval do
197
+ alias_method :original_debug, :debug
198
+
199
+ def debug(*args, &block)
200
+ return if ActiveRecordQueryTrace.suppress_logging_of_db_reads \
201
+ && args.first !~ /(INSERT|UPDATE|DELETE|#{ActiveRecordQueryTrace::BACKTRACE_PREFIX})/
202
+ original_debug(*args, &block)
203
+ end
204
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordQueryTrace
4
+ VERSION = '1.6'
5
+ end
metadata CHANGED
@@ -1,25 +1,138 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_query_trace
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.4
4
+ version: '1.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Caughlan
8
+ - Bruno Facca
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-10-12 00:00:00.000000000 Z
12
- dependencies: []
13
- description: Print stack trace of all queries to the Rails log. Helpful to find where
14
- queries are being executed in your application.
15
- email: toolbag@gmail.com
12
+ date: 2019-03-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: pry
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry-byebug
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rubocop
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rubocop-rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: simplecov
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: sqlite3
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: 1.3.6
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: 1.3.6
126
+ description: Print stack trace of all DB queries to the Rails log. Helpful to find
127
+ where queries are being executed in your application.
128
+ email: bruno@facca.info
16
129
  executables: []
17
130
  extensions: []
18
131
  extra_rdoc_files: []
19
132
  files:
20
133
  - lib/active_record_query_trace.rb
21
- - lib/version.rb
22
- homepage: https://github.com/ruckus/active-record-query-trace
134
+ - lib/active_record_query_trace/version.rb
135
+ homepage: https://github.com/brunofacca/active-record-query-trace
23
136
  licenses:
24
137
  - MIT
25
138
  metadata: {}
@@ -29,19 +142,19 @@ require_paths:
29
142
  - lib
30
143
  required_ruby_version: !ruby/object:Gem::Requirement
31
144
  requirements:
32
- - - '>='
145
+ - - ">="
33
146
  - !ruby/object:Gem::Version
34
147
  version: '0'
35
148
  required_rubygems_version: !ruby/object:Gem::Requirement
36
149
  requirements:
37
- - - '>='
150
+ - - ">="
38
151
  - !ruby/object:Gem::Version
39
152
  version: '0'
40
153
  requirements: []
41
154
  rubyforge_project:
42
- rubygems_version: 2.0.6
155
+ rubygems_version: 2.7.8
43
156
  signing_key:
44
157
  specification_version: 4
45
- summary: Print stack trace of all queries to the Rails log. Helpful to find where
158
+ summary: Print stack trace of all DB queries to the Rails log. Helpful to find where
46
159
  queries are being executed in your application.
47
160
  test_files: []
data/lib/version.rb DELETED
@@ -1,3 +0,0 @@
1
- module ActiveRecordQueryTrace
2
- VERSION = '1.5.4'
3
- end