prosopite 0.1.5 → 1.0.0

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: e45d47e93e239165f045462c1247f33b4dae5796e1c852fd7a2a6ade0977ef2a
4
- data.tar.gz: 25c2afb9c1340d3e16c3fcd2ba880becdfc674c54aaecba4d83566c6585998de
3
+ metadata.gz: 3df6a0299972911e48ea44330995864e2cd2191ec66c199296ba324a5fa8e639
4
+ data.tar.gz: 4f9ee347a8cf52fd742ee66586c7e4b601c8436a4bcabe1b1afdef5e09293f44
5
5
  SHA512:
6
- metadata.gz: 3eb734873fc1c396b5312dc70fe91a4c10a8adb4658bce2302559e8d61db22cc6e54429806e99e3014308b1e236b69a34f75e59bd3b789f36145843390776998
7
- data.tar.gz: 626d2a7ebaf7553647672f137696adfe2aa70fe67589b7380c2366862c85022ee560dfbe2665f7580c4cd930a95d7c94e1a59557d4674c563379fef94e197846
6
+ metadata.gz: 668bc7e58bcabd77231adc831054d56ca572e1e9857f87736d1fd06048c1eeaac9c0c0ab970c6ed6f8ce70670ae51277c3c4f56012d0ec61240c0e728c1f3795
7
+ data.tar.gz: '0341920f4f1beddc2b9c46553f9284724ecddfe50f30579a7cc9627c93fdf2d3c714bb57fd453dd7a4783a86951b9dd2cb0a79e721189bce3b89eda0c119c8bf'
data/Gemfile CHANGED
@@ -5,3 +5,4 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "rake", "~> 13.0"
8
+ gem 'pg_query'
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prosopite (0.1.5)
5
- pg_query (~> 1.3)
4
+ prosopite (0.2.1)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
@@ -44,6 +43,7 @@ DEPENDENCIES
44
43
  activerecord
45
44
  factory_bot
46
45
  minitest
46
+ pg_query
47
47
  prosopite!
48
48
  pry
49
49
  rake (~> 13.0)
data/LICENSE.txt CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright [yyyy] [name of copyright owner]
190
+ Copyright 2021 Mpampis Kostas
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -97,6 +97,12 @@ Add this line to your application's Gemfile:
97
97
  gem 'prosopite'
98
98
  ```
99
99
 
100
+ If you're **not** using MySQL/MariaDB, you should also add:
101
+
102
+ ```ruby
103
+ gem 'pg_query'
104
+ ```
105
+
100
106
  And then execute:
101
107
 
102
108
  $ bundle install
@@ -120,12 +126,14 @@ Prosopite auto-detection can be enabled on all controllers:
120
126
 
121
127
  ```ruby
122
128
  class ApplicationController < ActionController::Base
123
- before_action do
124
- Prosopite.scan
125
- end
126
-
127
- after_action do
128
- Prosopite.finish
129
+ unless Rails.env.production?
130
+ before_action do
131
+ Prosopite.scan
132
+ end
133
+
134
+ after_action do
135
+ Prosopite.finish
136
+ end
129
137
  end
130
138
  end
131
139
  ```
@@ -168,12 +176,12 @@ end
168
176
 
169
177
  WARNING: scan/finish should run before/after **each** test and NOT before/after the whole suite.
170
178
 
171
- ## Whitelisting
179
+ ## Allow list
172
180
 
173
181
  Ignore notifications for call stacks containing one or more substrings:
174
182
 
175
183
  ```ruby
176
- Prosopite.whitelist = ['substring_in_call_stack']
184
+ Prosopite.allow_list = ['substring_in_call_stack']
177
185
  ```
178
186
 
179
187
  ## Scanning code outside controllers or tests
data/lib/prosopite.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'pg_query'
2
1
 
3
2
  module Prosopite
4
3
  class NPlusOneQueriesError < StandardError; end
@@ -7,42 +6,46 @@ module Prosopite
7
6
  :stderr_logger,
8
7
  :rails_logger,
9
8
  :prosopite_logger,
10
- :whitelist
9
+ :allow_list
11
10
 
12
11
  def scan
13
- @scan ||= false
12
+ tc[:prosopite_scan] ||= false
14
13
  return if scan?
15
14
 
16
15
  subscribe
17
16
 
18
- @query_counter = Hash.new(0)
19
- @query_holder = Hash.new { |h, k| h[k] = [] }
20
- @query_caller = {}
17
+ tc[:prosopite_query_counter] = Hash.new(0)
18
+ tc[:prosopite_query_holder] = Hash.new { |h, k| h[k] = [] }
19
+ tc[:prosopite_query_caller] = {}
21
20
 
22
- @whitelist ||= []
21
+ @allow_list ||= []
23
22
 
24
- @scan = true
23
+ tc[:prosopite_scan] = true
24
+ end
25
+
26
+ def tc
27
+ Thread.current
25
28
  end
26
29
 
27
30
  def scan?
28
- @scan
31
+ tc[:prosopite_scan]
29
32
  end
30
33
 
31
34
  def finish
32
35
  return unless scan?
33
36
 
34
- @scan = false
37
+ tc[:prosopite_scan] = false
35
38
 
36
39
  create_notifications
37
- send_notifications if @notifications.present?
40
+ send_notifications if tc[:prosopite_notifications].present?
38
41
  end
39
42
 
40
43
  def create_notifications
41
- @notifications = {}
44
+ tc[:prosopite_notifications] = {}
42
45
 
43
- @query_counter.each do |location_key, count|
46
+ tc[:prosopite_query_counter].each do |location_key, count|
44
47
  if count > 1
45
- fingerprints = @query_holder[location_key].map do |q|
48
+ fingerprints = tc[:prosopite_query_holder][location_key].map do |q|
46
49
  begin
47
50
  fingerprint(q)
48
51
  rescue
@@ -50,13 +53,13 @@ module Prosopite
50
53
  end
51
54
  end
52
55
 
53
- kaller = @query_caller[location_key]
56
+ kaller = tc[:prosopite_query_caller][location_key]
54
57
 
55
- if fingerprints.uniq.size == 1 && !kaller.any? { |f| @whitelist.any? { |s| f.include?(s) } }
56
- queries = @query_holder[location_key]
58
+ if fingerprints.uniq.size == 1 && !kaller.any? { |f| @allow_list.any? { |s| f.include?(s) } }
59
+ queries = tc[:prosopite_query_holder][location_key]
57
60
 
58
61
  unless kaller.any? { |f| f.include?('active_record/validations/uniqueness') }
59
- @notifications[queries] = kaller
62
+ tc[:prosopite_notifications][queries] = kaller
60
63
  end
61
64
  end
62
65
  end
@@ -67,6 +70,12 @@ module Prosopite
67
70
  if ActiveRecord::Base.connection.adapter_name.downcase.include?('mysql')
68
71
  mysql_fingerprint(query)
69
72
  else
73
+ begin
74
+ require 'pg_query'
75
+ rescue LoadError => e
76
+ msg = "Could not load the 'pg_query' gem. Add `gem 'pg_query'` to your Gemfile"
77
+ raise LoadError, msg, e.backtrace
78
+ end
70
79
  PgQuery.fingerprint(query)
71
80
  end
72
81
  end
@@ -126,7 +135,7 @@ module Prosopite
126
135
 
127
136
  notifications_str = ''
128
137
 
129
- @notifications.each do |queries, kaller|
138
+ tc[:prosopite_notifications].each do |queries, kaller|
130
139
  notifications_str << "N+1 queries detected:\n"
131
140
  queries.each { |q| notifications_str << " #{q}\n" }
132
141
  notifications_str << "Call stack:\n"
@@ -136,8 +145,8 @@ module Prosopite
136
145
  notifications_str << "\n"
137
146
  end
138
147
 
139
- Rails.logger.warn(notifications_str) if @rails_logger
140
- $stderr.puts(notifications_str) if @stderr_logger
148
+ Rails.logger.warn(red(notifications_str)) if @rails_logger
149
+ $stderr.puts(red(notifications_str)) if @stderr_logger
141
150
 
142
151
  if @prosopite_logger
143
152
  File.open(File.join(Rails.root, 'log', 'prosopite.log'), 'a') do |f|
@@ -148,6 +157,10 @@ module Prosopite
148
157
  raise NPlusOneQueriesError.new(notifications_str) if @raise
149
158
  end
150
159
 
160
+ def red(str)
161
+ str.split("\n").map { |line| "\e[91m#{line}\e[0m" }.join("\n")
162
+ end
163
+
151
164
  def subscribe
152
165
  @subscribed ||= false
153
166
  return if @subscribed
@@ -158,11 +171,11 @@ module Prosopite
158
171
  if scan? && sql.include?('SELECT') && data[:cached].nil?
159
172
  location_key = Digest::SHA1.hexdigest(caller.join)
160
173
 
161
- @query_counter[location_key] += 1
162
- @query_holder[location_key] << sql
174
+ tc[:prosopite_query_counter][location_key] += 1
175
+ tc[:prosopite_query_holder][location_key] << sql
163
176
 
164
- if @query_counter[location_key] > 1
165
- @query_caller[location_key] = caller.dup
177
+ if tc[:prosopite_query_counter][location_key] > 1
178
+ tc[:prosopite_query_caller][location_key] = caller.dup
166
179
  end
167
180
  end
168
181
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prosopite
4
- VERSION = "0.1.5"
4
+ VERSION = "1.0.0"
5
5
  end
data/prosopite.gemspec CHANGED
@@ -24,8 +24,6 @@ Gem::Specification.new do |spec|
24
24
  end
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.add_runtime_dependency 'pg_query', '~> 1.3'
28
-
29
27
  spec.add_development_dependency "pry"
30
28
  spec.add_development_dependency "minitest"
31
29
  spec.add_development_dependency "factory_bot"
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prosopite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 1.0.0
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-02-27 00:00:00.000000000 Z
11
+ date: 2021-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: pg_query
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.3'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.3'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: pry
29
15
  requirement: !ruby/object:Gem::Requirement