active_record_query_counter 2.0.0 → 2.2.0

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
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