prosopite 1.0.2 → 1.0.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
2
  SHA256:
3
- metadata.gz: 8c01f842ae2f77f85afad80b9333d9e08532763b0a2f4da8b947fd224bd8ad5e
4
- data.tar.gz: b7355dba60a61af1936fabc438838cd6c5e68c2bf99ad4f89250f0fbb56da6f7
3
+ metadata.gz: 77276ce50263c0d9e2e4a9e0c525924ac5810367f036d783197222819f8fb312
4
+ data.tar.gz: b43868ebc87b40d97997db1c7a77fb3ee34cb032a76a0b290adb174c8d04c6d3
5
5
  SHA512:
6
- metadata.gz: d667f984caa2c358dd1268a515d4784bad98d86c39f42535cc97c7161c5f9131dbdf8dd57786aebc6fc20b55d1fcc660f4700260db08e47df3400797e4f7e3da
7
- data.tar.gz: 1b31e428871d38f29fb3f46f1c637cc822addbc5c826366da5b98ebe149bc1af63912f69a8a50cec277ed8e2c34c185bdc11e3f58d302a43fedd97c5b20622cc
6
+ metadata.gz: 5fc318b3becb5095f93244d8e23699c27e604c43ba7a3dc489ee3939d19b23e26a47eb4957d6355f28fdaa18fb6ecaa2caf27721a03fcadadefa73a5cbcfec7e
7
+ data.tar.gz: e5954aa6aec45c26722f807dcb2fde6aae4c1090d097cc7172a306cdde9639b734d226826fa1d6dcab59a9d22857dc7901978eb4297287ac49b81a63b23ae0e1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prosopite (1.0.1)
4
+ prosopite (1.0.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -127,11 +127,12 @@ Prosopite auto-detection can be enabled on all controllers:
127
127
  ```ruby
128
128
  class ApplicationController < ActionController::Base
129
129
  unless Rails.env.production?
130
- before_action do
130
+ around_action :n_plus_one_detection
131
+
132
+ def n_plus_one_detection
131
133
  Prosopite.scan
132
- end
133
-
134
- after_action do
134
+ yield
135
+ ensure
135
136
  Prosopite.finish
136
137
  end
137
138
  end
@@ -181,7 +182,13 @@ WARNING: scan/finish should run before/after **each** test and NOT before/after
181
182
  Ignore notifications for call stacks containing one or more substrings:
182
183
 
183
184
  ```ruby
184
- Prosopite.allow_list = ['substring_in_call_stack']
185
+ Prosopite.allow_stack_paths = ['substring_in_call_stack']
186
+ ```
187
+
188
+ Ignore notifications matching a specific SQL query:
189
+
190
+ ```ruby
191
+ Prosopite.ignore_queries = [/regex_match/, "SELECT * from EXACT_STRING_MATCH"]
185
192
  ```
186
193
 
187
194
  ## Scanning code outside controllers or tests
@@ -202,6 +209,23 @@ Prosopite.scan do
202
209
  end
203
210
  ```
204
211
 
212
+ ## Pausing and resuming scans
213
+
214
+ Scans can be paused:
215
+
216
+ ```ruby
217
+ Prosopite.scan
218
+ # <code to scan>
219
+ Prosopite.pause
220
+ # <code that has n+1s>
221
+ Prosopite.resume
222
+ # <code to scan>
223
+ Prosopite.finish
224
+ ```
225
+
226
+ An example of when you might use this is if you are [testing Active Jobs inline](https://guides.rubyonrails.org/testing.html#testing-jobs),
227
+ and don't want to run Prosopite on background job code, just foreground app code. In that case you could write an [Active Job callback](https://edgeguides.rubyonrails.org/active_job_basics.html#callbacks) that pauses the scan while the job is running.
228
+
205
229
  ## Contributing
206
230
 
207
231
  Bug reports and pull requests are welcome on GitHub at https://github.com/charkost/prosopite.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prosopite
4
- VERSION = "1.0.2"
4
+ VERSION = "1.0.6"
5
5
  end
data/lib/prosopite.rb CHANGED
@@ -1,12 +1,21 @@
1
1
 
2
2
  module Prosopite
3
+ DEFAULT_ALLOW_LIST = %w(active_record/associations/preloader active_record/validations/uniqueness)
4
+
3
5
  class NPlusOneQueriesError < StandardError; end
4
6
  class << self
5
7
  attr_writer :raise,
6
8
  :stderr_logger,
7
9
  :rails_logger,
8
10
  :prosopite_logger,
9
- :allow_list
11
+ :allow_stack_paths,
12
+ :ignore_queries
13
+
14
+ def allow_list=(value)
15
+ puts "Prosopite.allow_list= is deprecated. Use Prosopite.allow_stack_paths= instead."
16
+
17
+ self.allow_stack_paths = value
18
+ end
10
19
 
11
20
  def scan
12
21
  tc[:prosopite_scan] ||= false
@@ -18,7 +27,7 @@ module Prosopite
18
27
  tc[:prosopite_query_holder] = Hash.new { |h, k| h[k] = [] }
19
28
  tc[:prosopite_query_caller] = {}
20
29
 
21
- @allow_list ||= []
30
+ @allow_stack_paths ||= []
22
31
 
23
32
  tc[:prosopite_scan] = true
24
33
 
@@ -36,6 +45,14 @@ module Prosopite
36
45
  Thread.current
37
46
  end
38
47
 
48
+ def pause
49
+ tc[:prosopite_scan] = false
50
+ end
51
+
52
+ def resume
53
+ tc[:prosopite_scan] = true
54
+ end
55
+
39
56
  def scan?
40
57
  tc[:prosopite_scan]
41
58
  end
@@ -62,14 +79,15 @@ module Prosopite
62
79
  end
63
80
  end
64
81
 
82
+ next unless fingerprints.uniq.size == 1
83
+
65
84
  kaller = tc[:prosopite_query_caller][location_key]
85
+ allow_list = (@allow_stack_paths + DEFAULT_ALLOW_LIST)
86
+ is_allowed = kaller.any? { |f| allow_list.any? { |s| f.include?(s) } }
66
87
 
67
- if fingerprints.uniq.size == 1 && !kaller.any? { |f| @allow_list.any? { |s| f.include?(s) } }
88
+ unless is_allowed
68
89
  queries = tc[:prosopite_query_holder][location_key]
69
-
70
- unless kaller.any? { |f| f.include?('active_record/validations/uniqueness') }
71
- tc[:prosopite_notifications][queries] = kaller
72
- end
90
+ tc[:prosopite_notifications][queries] = kaller
73
91
  end
74
92
  end
75
93
  end
@@ -170,6 +188,11 @@ module Prosopite
170
188
  str.split("\n").map { |line| "\e[91m#{line}\e[0m" }.join("\n")
171
189
  end
172
190
 
191
+ def ignore_query?(sql)
192
+ @ignore_queries ||= []
193
+ @ignore_queries.any? { |q| q === sql }
194
+ end
195
+
173
196
  def subscribe
174
197
  @subscribed ||= false
175
198
  return if @subscribed
@@ -177,7 +200,7 @@ module Prosopite
177
200
  ActiveSupport::Notifications.subscribe 'sql.active_record' do |_, _, _, _, data|
178
201
  sql, name = data[:sql], data[:name]
179
202
 
180
- if scan? && name != "SCHEMA" && sql.include?('SELECT') && data[:cached].nil?
203
+ if scan? && name != "SCHEMA" && sql.include?('SELECT') && data[:cached].nil? && !ignore_query?(sql)
181
204
  location_key = Digest::SHA1.hexdigest(caller.join)
182
205
 
183
206
  tc[:prosopite_query_counter][location_key] += 1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prosopite
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mpampis Kostas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-25 00:00:00.000000000 Z
11
+ date: 2021-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry