active_record_query_trace 1.5.4 → 1.6

Sign up to get free protection for your applications and to get access to all the features.
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