active_record_query_counter 2.2.0 → 2.3.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: 00cf8b2bba420e0b37944a53f4be128aeac846d6e387b15b03c3393f3a0030c2
4
- data.tar.gz: 10c05613e25513f1afab756f9cdd1133a19f7b54e34ca811b7f3ba5ad982ff0e
3
+ metadata.gz: 9b460515835154824cb80fec7db1e62dc4f4f983f8779fc1b80bec3c728646a4
4
+ data.tar.gz: 3d26302dd73d2ae010f4732ca4711a7dd1daa4ca0cca55e5ccd50349e89b282c
5
5
  SHA512:
6
- metadata.gz: 4294aac8c3b0b55197ba1d069cc0a57f269ad772c23480b928fcf3f0a01b7c4f806f4969bf32f2d229b8dea65bc976d18cc864f923ec468dbbb43fc2fbe20bdd
7
- data.tar.gz: ffddf3b2d87b74a2ad184d0ec55c4b371cda418c262aa2d0889cf40916579f5bff575ef0e631a39764edd58f7d321b71fa1b993dda6c3ff0c9f1ef060ca02769
6
+ metadata.gz: d1af45ed8c0659df4fcbf665621576b07380565a1289458e868b7cb33825c2d055e7b489eb1e490c31a566157a01f328eedd2771f9f3f5bffdece2b357445a01
7
+ data.tar.gz: ba21e07f668e1c3f97c61ce6f48fd10ef2d019afdd7d9d579e3487c710d58e8b44a9b1c5042572bc74be55a907c506d6385947dbe85a10b14b57e2b7b94037b7
data/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ 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.3.0
8
+
9
+ ### Added
10
+
11
+ - Added count of rollbacks from transactions
12
+
13
+ ## 2.2.1
14
+
15
+ ### Changed
16
+
17
+ - Classes not required to run the gem are now lazy loaded.
18
+
7
19
  ## 2.2.0
8
20
 
9
21
  ### Added
data/README.md CHANGED
@@ -1,37 +1,47 @@
1
1
  # ActiveRecordQueryCounter
2
2
 
3
- ![Continuous Integration](https://github.com/bdurand/active_record_query_counter/workflows/Continuous%20Integration/badge.svg)
3
+ [![Continuous Integration](https://github.com/bdurand/active_record_query_counter/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/active_record_query_counter/actions/workflows/continuous_integration.yml)
4
4
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
5
+ [![Gem Version](https://badge.fury.io/rb/active_record_query_counter.svg)](https://badge.fury.io/rb/active_record_query_counter)
5
6
 
6
- This gem injects itself into ActiveRecord to give you insight into how your code is using the database.
7
+ **ActiveRecordQueryCounter** is a ruby gem that provides detailed insights into how your code interacts with the database by hooking into ActiveRecord.
7
8
 
8
- Within a block of code, it will count:
9
+ It measures database usage within a block of code, including:
9
10
 
10
- - the number of queries
11
- - the number of rows returned
12
- - the amount of time spent on queries
13
- - the number of transactions used
14
- - the amount of time spent inside transactions
11
+ - The number of queries executed
12
+ - The number of rows returned
13
+ - The total time spent on queries
14
+ - The number of transactions used
15
+ - The total time spent inside transactions
16
+ - The number of transactions that were rolled back
15
17
 
16
- The intended use is to gather instrumentation stats for finding hot spots in your code that produce a lot of queries or slow queries or queries that return a lot of rows. It can also be used to find code that is not using transactions when making multiple updates to the database.
18
+ This gem is designed to help you:
19
+
20
+ - Identify "hot spots" in your code that generate excessive or slow queries.
21
+ - Spot queries returning unexpectedly large result sets.
22
+ - Detect areas where transactions are underutilized, especially when performing multiple database updates.
17
23
 
18
24
  ## Usage
19
25
 
20
- The behavior must be enabled on your database connection adapter from within an initializer.
26
+ ### Enabling The Gem
27
+
28
+ To use **ActiveRecordQueryCounter**, you first need to enable it on your database connection adapter. Add the following to an initializer:
21
29
 
22
- Postgres:
30
+ For **PostgreSQL**:
23
31
 
24
32
  ```ruby
25
33
  ActiveRecordQueryCounter.enable!(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
26
34
  ```
27
35
 
28
- MySQL:
36
+ For **MySQL**:
29
37
 
30
38
  ```ruby
31
39
  ActiveRecordQueryCounter.enable!(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
32
40
  ```
33
41
 
34
- Next you must specify the blocks where you want to count queries.
42
+ ### Counting Queries
43
+
44
+ To measure database activity, wrap the code you want to monitor inside a `count_queries` block:
35
45
 
36
46
  ```ruby
37
47
  ActiveRecordQueryCounter.count_queries do
@@ -41,18 +51,25 @@ ActiveRecordQueryCounter.count_queries do
41
51
  puts "Query Time: #{ActiveRecordQueryCounter.query_time}"
42
52
  puts "Transactions: #{ActiveRecordQueryCounter.transaction_count}"
43
53
  puts "Transaction Time: #{ActiveRecordQueryCounter.transaction_time}"
54
+ puts "Rollbacks: #{ActiveRecordQueryCounter.rollback_count}"
44
55
  end
45
56
  ```
46
57
 
47
- This gem includes middleware for both Rack and Sidekiq that will enable query counting on web requests and in workers. If you are using Rails with Sidekiq, you can enable both with an initializer.
58
+ ### Middleware Integration
59
+
60
+ For **Rails** and **Sidekiq**, middleware is included to enable query counting in web requests and workers.
61
+
62
+ Add the following to an initializer:
48
63
 
49
64
  ```ruby
50
65
  ActiveSupport.on_load(:active_record) do
51
66
  ActiveRecordQueryCounter.enable!(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
52
67
  end
53
68
 
69
+ # Enable Rack Middleware
54
70
  Rails.application.config.middleware.use(ActiveRecordQueryCounter::RackMiddleware)
55
71
 
72
+ # Enable Sidekiq Middleware
56
73
  Sidekiq.configure_server do |config|
57
74
  config.server_middleware do |chain|
58
75
  chain.add ActiveRecordQueryCounter::SidekiqMiddleware
@@ -60,13 +77,15 @@ Sidekiq.configure_server do |config|
60
77
  end
61
78
  ```
62
79
 
63
- If you want to disable query counting within a block of code, you can use the `disable` method.
80
+ ### Disabling Query Counting
81
+
82
+ You can temporarily disable query counting within a block using `disable`:
64
83
 
65
84
  ```ruby
66
85
  ActiveRecordQueryCounter.count_queries do
67
86
  do_something
68
87
  ActiveRecordQueryCounter.disable do
69
- # Queries will not be counted in this block.
88
+ # Queries in this block will not be counted.
70
89
  do_something_else
71
90
  end
72
91
  end
@@ -74,43 +93,46 @@ end
74
93
 
75
94
  ### Notifications
76
95
 
77
- You can also subscribe to ActiveSupport notifications to get notified when query thresholds are exceeded.
96
+ **ActiveRecordQueryCounter** supports ActiveSupport notifications when certain query thresholds are exceeded.
97
+
98
+ #### Available Notifications
99
+
100
+ ##### 1. active_record_query_counter.query_time notification
78
101
 
79
- #### active_record_query_counter.query_time notification
102
+ Triggered when a query exceeds the query_time threshold with the payload:
80
103
 
81
- This notification is triggered when a query takes longer than the `query_time` threshold. The payload contains the following keys:
82
104
 
83
105
  - `:sql` - The SQL statement that was executed.
84
106
  - `:binds` - The bind parameters that were used.
85
107
  - `:row_count` - The number of rows returned.
86
108
  - `:trace` - The stack trace of where the query was executed.
87
109
 
88
- #### active_record_query_counter.row_count notification
110
+ ##### 2. active_record_query_counter.row_count notification
89
111
 
90
- This notification is triggered when a query returns more rows than the `row_count` threshold. The payload contains the following keys:
112
+ Triggered when a query exceeds the row_count threshold with the payload:
91
113
 
92
114
  - `:sql` - The SQL statement that was executed.
93
115
  - `:binds` - The bind parameters that were used.
94
116
  - `:row_count` - The number of rows returned.
95
117
  - `:trace` - The stack trace of where the query was executed.
96
118
 
97
- #### active_record_query_counter.transaction_time notification
119
+ ##### 3. active_record_query_counter.transaction_time notification
98
120
 
99
- This notification is triggered when a transaction takes longer than the `transaction_time` threshold. The payload contains the following keys:
121
+ Triggered when a transaction exceeds the transaction_time threshold with the payload:
100
122
 
101
123
  - `:trace` - The stack trace of where the transaction was completed.
102
124
 
103
- #### active_record_query_counter.transaction_count notification
125
+ ##### 4. active_record_query_counter.transaction_count notification
104
126
 
105
- This notification is triggered when a transaction takes longer than the `transaction_count` threshold. The payload contains the following keys:
127
+ Triggered when transactions exceed the transaction_count threshold with the payload:
106
128
 
107
129
  - `:transactions` - An array of `ActiveRecordQueryCounter::TransactionInfo` objects.
108
130
 
109
131
  The duration of the notification event is the time between when the first transaction was started and the last transaction was completed.
110
132
 
111
- #### Thresholds
133
+ #### Setting Thresholds
112
134
 
113
- The thresholds for triggering notifications can be set globally in an initializer:
135
+ Thresholds can be configured **globally** in an initializer:
114
136
 
115
137
  ```ruby
116
138
  ActiveRecordQueryCounter.default_thresholds.set(
@@ -121,7 +143,7 @@ ActiveRecordQueryCounter.default_thresholds.set(
121
143
  )
122
144
  ```
123
145
 
124
- They can be set locally inside a `count_queries` block with the `thresholds` object. Local thresholds will override the global thresholds only inside the block and will not change any global state.
146
+ Or locally within a block:
125
147
 
126
148
  ```ruby
127
149
  ActiveRecordQueryCounter.count_queries do
@@ -134,7 +156,8 @@ ActiveRecordQueryCounter.count_queries do
134
156
  end
135
157
  ```
136
158
 
137
- You can pass thresholds to individual Sidekiq workers via the `sidekiq_options` on the worker.
159
+ #### Sidekiq Worker Thresholds
160
+ Thresholds for individual Sidekiq workers can be set using `sidekiq_options`:
138
161
 
139
162
  ```ruby
140
163
  class MyWorker
@@ -150,7 +173,6 @@ class MyWorker
150
173
  }
151
174
  }
152
175
  )
153
- # You can disable thresholds for the worker by setting `thresholds: false`.
154
176
 
155
177
  def perform
156
178
  do_something
@@ -158,7 +180,11 @@ class MyWorker
158
180
  end
159
181
  ```
160
182
 
161
- You can set separate thresholds on the Rack middleware when you install it.
183
+ To disable thresholds for a worker, set `thresholds: false`.
184
+
185
+ #### Rack Middleware Thresholds
186
+
187
+ You can configure separate thresholds for the Rack middleware:
162
188
 
163
189
  ```ruby
164
190
  Rails.application.config.middleware.use(ActiveRecordQueryCounter::RackMiddleware, thresholds: {
@@ -169,7 +195,7 @@ Rails.application.config.middleware.use(ActiveRecordQueryCounter::RackMiddleware
169
195
  })
170
196
  ```
171
197
 
172
- #### Example Notification Subscriptions
198
+ #### Example: Subscribing to Notifications
173
199
 
174
200
  ```ruby
175
201
  ActiveRecordQueryCounter.default_thresholds.query_time = 1.0
@@ -204,6 +230,24 @@ ActiveSupport::Notifications.subscribe('active_record_query_counter.transaction_
204
230
  end
205
231
  ```
206
232
 
233
+ ## Installation
234
+
235
+ Add this line to your application's Gemfile:
236
+
237
+ ```ruby
238
+ gem 'active_record_query_counter'
239
+ ```
240
+
241
+ And then execute:
242
+ ```bash
243
+ $ bundle
244
+ ```
245
+
246
+ Or install it yourself as:
247
+ ```bash
248
+ $ gem install active_record_query_counter
249
+ ```
250
+
207
251
  ## Contributing
208
252
 
209
253
  Open a pull request on GitHub.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.0
1
+ 2.3.0
@@ -4,10 +4,16 @@ Gem::Specification.new do |spec|
4
4
  spec.authors = ["Brian Durand"]
5
5
  spec.email = ["bbdurand@gmail.com"]
6
6
 
7
- spec.summary = "Count total number of ActiveRecord queries and row counts inside a block"
7
+ spec.summary = "Provides detailed insights into how your code interacts with the database by hooking into ActiveRecord."
8
8
  spec.homepage = "https://github.com/bdurand/active_record_query_counter"
9
9
  spec.license = "MIT"
10
10
 
11
+ spec.metadata = {
12
+ "homepage_uri" => spec.homepage,
13
+ "source_code_uri" => spec.homepage,
14
+ "changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
15
+ }
16
+
11
17
  # Specify which files should be added to the gem when it is released.
12
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
19
  ignore_files = %w[
@@ -3,7 +3,7 @@
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, :cached_query_count
6
+ attr_accessor :query_count, :row_count, :query_time, :cached_query_count, :rollback_count
7
7
  attr_reader :thresholds
8
8
 
9
9
  def initialize
@@ -13,6 +13,7 @@ module ActiveRecordQueryCounter
13
13
  @cached_query_count = 0
14
14
  @transactions_hash = {}
15
15
  @thresholds = ActiveRecordQueryCounter.default_thresholds.dup
16
+ @rollback_count = 0
16
17
  end
17
18
 
18
19
  # Return the percentage of queries that used the query cache instead of going to the database.
@@ -34,7 +34,7 @@ module ActiveRecordQueryCounter
34
34
  values.each do |key, value|
35
35
  setter = "#{key}="
36
36
  if respond_to?(setter)
37
- public_send("#{key}=", value)
37
+ public_send(:"#{key}=", value)
38
38
  else
39
39
  raise ArgumentError, "Unknown threshold: #{key}"
40
40
  end
@@ -31,6 +31,7 @@ module ActiveRecordQueryCounter
31
31
  if @active_record_query_counter_transaction_start_time && open_transactions == 1
32
32
  end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
33
33
  ActiveRecordQueryCounter.add_transaction(@active_record_query_counter_transaction_start_time, end_time)
34
+ ActiveRecordQueryCounter.increment_rollbacks
34
35
  @active_record_query_counter_transaction_start_time = nil
35
36
  end
36
37
  super
@@ -2,12 +2,9 @@
2
2
 
3
3
  require_relative "active_record_query_counter/connection_adapter_extension"
4
4
  require_relative "active_record_query_counter/counter"
5
- require_relative "active_record_query_counter/rack_middleware"
6
- require_relative "active_record_query_counter/sidekiq_middleware"
7
5
  require_relative "active_record_query_counter/thresholds"
8
6
  require_relative "active_record_query_counter/transaction_info"
9
7
  require_relative "active_record_query_counter/transaction_manager_extension"
10
- require_relative "active_record_query_counter/version"
11
8
 
12
9
  # Everything you need to count ActiveRecord queries and row counts within a block.
13
10
  #
@@ -19,6 +16,10 @@ require_relative "active_record_query_counter/version"
19
16
  # puts ActiveRecordQueryCounter.row_count
20
17
  # end
21
18
  module ActiveRecordQueryCounter
19
+ autoload :RackMiddleware, "active_record_query_counter/rack_middleware"
20
+ autoload :SidekiqMiddleware, "active_record_query_counter/sidekiq_middleware"
21
+ autoload :VERSION, "active_record_query_counter/version"
22
+
22
23
  IGNORED_STATEMENTS = %w[SCHEMA EXPLAIN].freeze
23
24
  private_constant :IGNORED_STATEMENTS
24
25
 
@@ -112,6 +113,17 @@ module ActiveRecordQueryCounter
112
113
  end
113
114
  end
114
115
 
116
+ # Return the number of rollbacks that have been counted within the current block.
117
+ # Returns nil if not inside a block where queries are being counted.
118
+ #
119
+ # @return [Integer, nil]
120
+ def increment_rollbacks
121
+ counter = current_counter
122
+ return unless counter.is_a?(Counter)
123
+
124
+ counter.rollback_count += 1
125
+ end
126
+
115
127
  # Return the number of queries that have been counted within the current block.
116
128
  # Returns nil if not inside a block where queries are being counted.
117
129
  #
@@ -194,6 +206,15 @@ module ActiveRecordQueryCounter
194
206
  counter.transactions if counter.is_a?(Counter)
195
207
  end
196
208
 
209
+ # Return the number of transactions that have rolled back within the current block.
210
+ # Returns nil if not inside a block where queries are being counted.
211
+ #
212
+ # @return [Integer, nil]
213
+ def rollback_count
214
+ counter = current_counter
215
+ counter.rollback_count if counter.is_a?(Counter)
216
+ end
217
+
197
218
  # Return the query info as a hash with keys :query_count, :row_count, :query_time
198
219
  # :transaction_count, and :transaction_type or nil if not inside a block where queries
199
220
  # are being counted.
@@ -209,7 +230,8 @@ module ActiveRecordQueryCounter
209
230
  cached_query_count: counter.cached_query_count,
210
231
  cache_hit_rate: counter.cache_hit_rate,
211
232
  transaction_count: counter.transaction_count,
212
- transaction_time: counter.transaction_time
233
+ transaction_time: counter.transaction_time,
234
+ rollback_count: counter.rollback_count
213
235
  }
214
236
  end
215
237
  end
@@ -233,8 +255,10 @@ module ActiveRecordQueryCounter
233
255
  # @param connection_class [Class] the connection adapter class to extend
234
256
  # @return [void]
235
257
  def enable!(connection_class)
236
- ConnectionAdapterExtension.inject(connection_class)
237
- TransactionManagerExtension.inject(ActiveRecord::ConnectionAdapters::TransactionManager)
258
+ ActiveSupport.on_load(:active_record) do
259
+ ConnectionAdapterExtension.inject(connection_class)
260
+ TransactionManagerExtension.inject(ActiveRecord::ConnectionAdapters::TransactionManager)
261
+ end
238
262
 
239
263
  @cache_subscription ||= ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, _start_time, _end_time, _id, payload|
240
264
  if payload[:cached]
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.2.0
4
+ version: 2.3.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-11-03 00:00:00.000000000 Z
11
+ date: 2024-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -46,7 +46,7 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - CHANGELOG.md
49
- - MIT_LICENSE
49
+ - MIT_LICENSE.txt
50
50
  - README.md
51
51
  - VERSION
52
52
  - active_record_query_counter.gemspec
@@ -62,7 +62,10 @@ files:
62
62
  homepage: https://github.com/bdurand/active_record_query_counter
63
63
  licenses:
64
64
  - MIT
65
- metadata: {}
65
+ metadata:
66
+ homepage_uri: https://github.com/bdurand/active_record_query_counter
67
+ source_code_uri: https://github.com/bdurand/active_record_query_counter
68
+ changelog_uri: https://github.com/bdurand/active_record_query_counter/blob/main/CHANGELOG.md
66
69
  post_install_message:
67
70
  rdoc_options: []
68
71
  require_paths:
@@ -78,8 +81,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
81
  - !ruby/object:Gem::Version
79
82
  version: '0'
80
83
  requirements: []
81
- rubygems_version: 3.4.20
84
+ rubygems_version: 3.4.10
82
85
  signing_key:
83
86
  specification_version: 4
84
- summary: Count total number of ActiveRecord queries and row counts inside a block
87
+ summary: Provides detailed insights into how your code interacts with the database
88
+ by hooking into ActiveRecord.
85
89
  test_files: []
File without changes