active_record_query_counter 2.0.0 → 2.2.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: eb19f1f7e8a7678f3cdf3079b05e9aa26353b33b809c240943e0899f584dac6a
4
- data.tar.gz: 7bcbce0b2d06c4f871074898651071f1400cd87c7ee8ee514837ee80caac6774
3
+ metadata.gz: 00cf8b2bba420e0b37944a53f4be128aeac846d6e387b15b03c3393f3a0030c2
4
+ data.tar.gz: 10c05613e25513f1afab756f9cdd1133a19f7b54e34ca811b7f3ba5ad982ff0e
5
5
  SHA512:
6
- metadata.gz: 80c468ec96c069bb4043a0e210d4fb4b1d82714d2aa0b69bd07ac9fd23bb04255ffcf4b175fcfa66b7aa0afd8434c211645e70f4fd8d05ad9c10faa4ee95c679
7
- data.tar.gz: fb972d526b98c97f98230a29eb9412726746a58c3d4a05406ab9ccc046d6eb0ec5007fa8d52d26a40c9a966ad2af4c50c045c1d9257cd15ce90dd21c5dedbcfa
6
+ metadata.gz: 4294aac8c3b0b55197ba1d069cc0a57f269ad772c23480b928fcf3f0a01b7c4f806f4969bf32f2d229b8dea65bc976d18cc864f923ec468dbbb43fc2fbe20bdd
7
+ data.tar.gz: ffddf3b2d87b74a2ad184d0ec55c4b371cda418c262aa2d0889cf40916579f5bff575ef0e631a39764edd58f7d321b71fa1b993dda6c3ff0c9f1ef060ca02769
data/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 2.2.0
8
+
9
+ ### Added
10
+
11
+ - Added `ActiveRecordQueryCounter.disable` method to allow disabling query counting behavior within a block.
12
+ - Rails 7.1 compatibility.
13
+
14
+ ## 2.1.0
15
+
16
+ ### Added
17
+
18
+ - Added count of queries that hit the query cache instead of being sent to the database.
19
+
20
+ ### Removed
21
+
22
+ - Dropped support for ActiveRecord 5.0.
23
+
7
24
  ## 2.0.0
8
25
 
9
26
  ### Added
data/README.md CHANGED
@@ -60,6 +60,18 @@ Sidekiq.configure_server do |config|
60
60
  end
61
61
  ```
62
62
 
63
+ If you want to disable query counting within a block of code, you can use the `disable` method.
64
+
65
+ ```ruby
66
+ ActiveRecordQueryCounter.count_queries do
67
+ do_something
68
+ ActiveRecordQueryCounter.disable do
69
+ # Queries will not be counted in this block.
70
+ do_something_else
71
+ end
72
+ end
73
+ ```
74
+
63
75
  ### Notifications
64
76
 
65
77
  You can also subscribe to ActiveSupport notifications to get notified when query thresholds are exceeded.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.2.0
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.require_paths = ["lib"]
30
30
 
31
- spec.add_dependency "activerecord", ">= 5.0"
31
+ spec.add_dependency "activerecord", ">= 5.1"
32
32
 
33
33
  spec.add_development_dependency "bundler"
34
34
 
@@ -3,14 +3,38 @@
3
3
  module ActiveRecordQueryCounter
4
4
  # Module to prepend to the connection adapter to inject the counting behavior.
5
5
  module ConnectionAdapterExtension
6
- def exec_query(sql, name = nil, binds = [], *args, **kwargs)
7
- start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
8
- result = super
9
- if result.is_a?(ActiveRecord::Result)
10
- end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
11
- ActiveRecordQueryCounter.add_query(sql, name, binds, result.length, start_time, end_time)
6
+ class << self
7
+ def inject(connection_class)
8
+ # Rails 7.1+ uses internal_exec_query instead of exec_query.
9
+ mod = (connection_class.instance_methods.include?(:internal_exec_query) ? InternalExecQuery : ExecQuery)
10
+ unless connection_class.include?(mod)
11
+ connection_class.prepend(mod)
12
+ end
13
+ end
14
+ end
15
+
16
+ module ExecQuery
17
+ def exec_query(sql, name = nil, binds = [], *args, **kwargs)
18
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+ result = super
20
+ if result.is_a?(ActiveRecord::Result)
21
+ end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
+ ActiveRecordQueryCounter.add_query(sql, name, binds, result.length, start_time, end_time)
23
+ end
24
+ result
25
+ end
26
+ end
27
+
28
+ module InternalExecQuery
29
+ def internal_exec_query(sql, name = nil, binds = [], *args, **kwargs)
30
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
31
+ result = super
32
+ if result.is_a?(ActiveRecord::Result)
33
+ end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
34
+ ActiveRecordQueryCounter.add_query(sql, name, binds, result.length, start_time, end_time)
35
+ end
36
+ result
12
37
  end
13
- result
14
38
  end
15
39
  end
16
40
  end
@@ -3,17 +3,30 @@
3
3
  module ActiveRecordQueryCounter
4
4
  # Data structure for storing query information encountered within a block.
5
5
  class Counter
6
- attr_accessor :query_count, :row_count, :query_time
6
+ attr_accessor :query_count, :row_count, :query_time, :cached_query_count
7
7
  attr_reader :thresholds
8
8
 
9
9
  def initialize
10
10
  @query_count = 0
11
11
  @row_count = 0
12
12
  @query_time = 0.0
13
+ @cached_query_count = 0
13
14
  @transactions_hash = {}
14
15
  @thresholds = ActiveRecordQueryCounter.default_thresholds.dup
15
16
  end
16
17
 
18
+ # Return the percentage of queries that used the query cache instead of going to the database.
19
+ #
20
+ # @return [Float]
21
+ def cache_hit_rate
22
+ total_queries = query_count + cached_query_count
23
+ if total_queries > 0
24
+ (cached_query_count.to_f / total_queries)
25
+ else
26
+ 0.0
27
+ end
28
+ end
29
+
17
30
  # Return an array of transaction information for any transactions that have been tracked
18
31
  # by the counter.
19
32
  #
@@ -6,6 +6,10 @@ module ActiveRecordQueryCounter
6
6
  class Thresholds
7
7
  attr_reader :query_time, :row_count, :transaction_time, :transaction_count
8
8
 
9
+ def initialize
10
+ clear
11
+ end
12
+
9
13
  def query_time=(value)
10
14
  @query_time = value&.to_f
11
15
  end
@@ -3,6 +3,14 @@
3
3
  module ActiveRecordQueryCounter
4
4
  # Extension to ActiveRecord::ConnectionAdapters::TransactionManager to count transactions.
5
5
  module TransactionManagerExtension
6
+ class << self
7
+ def inject(transaction_manager_class)
8
+ unless transaction_manager_class.include?(self)
9
+ transaction_manager_class.prepend(self)
10
+ end
11
+ end
12
+ end
13
+
6
14
  def begin_transaction(*args, **kwargs)
7
15
  if open_transactions == 0
8
16
  @active_record_query_counter_transaction_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -19,7 +19,7 @@ require_relative "active_record_query_counter/version"
19
19
  # puts ActiveRecordQueryCounter.row_count
20
20
  # end
21
21
  module ActiveRecordQueryCounter
22
- IGNORED_STATEMENTS = %w[CACHE SCHEMA EXPLAIN].freeze
22
+ IGNORED_STATEMENTS = %w[SCHEMA EXPLAIN].freeze
23
23
  private_constant :IGNORED_STATEMENTS
24
24
 
25
25
  class << self
@@ -48,6 +48,20 @@ module ActiveRecordQueryCounter
48
48
  end
49
49
  end
50
50
 
51
+ # Disable query counting in a block. Any queries or transactions inside the block will not
52
+ # be counted.
53
+ #
54
+ # @return [Object] the return value of the block
55
+ def disable(&block)
56
+ counter = current_counter
57
+ begin
58
+ self.current_counter = nil
59
+ yield
60
+ ensure
61
+ self.current_counter = counter
62
+ end
63
+ end
64
+
51
65
  # Increment the query counters.
52
66
  #
53
67
  # @param row_count [Integer] the number of rows returned by the query
@@ -107,6 +121,16 @@ module ActiveRecordQueryCounter
107
121
  counter.query_count if counter.is_a?(Counter)
108
122
  end
109
123
 
124
+ # Return the number of queries that hit the query cache and were not sent to the database
125
+ # that have been counted within the current block. Returns nil if not inside a block where
126
+ # queries are being counted.
127
+ #
128
+ # @return [Integer, nil]
129
+ def cached_query_count
130
+ counter = current_counter
131
+ counter.cached_query_count if counter.is_a?(Counter)
132
+ end
133
+
110
134
  # Return the number of rows that have been counted within the current block.
111
135
  # Returns nil if not inside a block where queries are being counted.
112
136
  #
@@ -182,6 +206,8 @@ module ActiveRecordQueryCounter
182
206
  query_count: counter.query_count,
183
207
  row_count: counter.row_count,
184
208
  query_time: counter.query_time,
209
+ cached_query_count: counter.cached_query_count,
210
+ cache_hit_rate: counter.cache_hit_rate,
185
211
  transaction_count: counter.transaction_count,
186
212
  transaction_time: counter.transaction_time
187
213
  }
@@ -207,11 +233,14 @@ module ActiveRecordQueryCounter
207
233
  # @param connection_class [Class] the connection adapter class to extend
208
234
  # @return [void]
209
235
  def enable!(connection_class)
210
- unless connection_class.include?(ConnectionAdapterExtension)
211
- connection_class.prepend(ConnectionAdapterExtension)
212
- end
213
- unless ActiveRecord::ConnectionAdapters::TransactionManager.include?(TransactionManagerExtension)
214
- ActiveRecord::ConnectionAdapters::TransactionManager.prepend(TransactionManagerExtension)
236
+ ConnectionAdapterExtension.inject(connection_class)
237
+ TransactionManagerExtension.inject(ActiveRecord::ConnectionAdapters::TransactionManager)
238
+
239
+ @cache_subscription ||= ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, _start_time, _end_time, _id, payload|
240
+ if payload[:cached]
241
+ counter = current_counter
242
+ counter.cached_query_count += 1 if counter
243
+ end
215
244
  end
216
245
  end
217
246
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_query_counter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-09 00:00:00.000000000 Z
11
+ date: 2023-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '5.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '5.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -78,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
78
  - !ruby/object:Gem::Version
79
79
  version: '0'
80
80
  requirements: []
81
- rubygems_version: 3.4.10
81
+ rubygems_version: 3.4.20
82
82
  signing_key:
83
83
  specification_version: 4
84
84
  summary: Count total number of ActiveRecord queries and row counts inside a block