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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +76 -32
- data/VERSION +1 -1
- data/active_record_query_counter.gemspec +7 -1
- data/lib/active_record_query_counter/counter.rb +2 -1
- data/lib/active_record_query_counter/thresholds.rb +1 -1
- data/lib/active_record_query_counter/transaction_manager_extension.rb +1 -0
- data/lib/active_record_query_counter.rb +30 -6
- metadata +10 -6
- /data/{MIT_LICENSE → MIT_LICENSE.txt} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b460515835154824cb80fec7db1e62dc4f4f983f8779fc1b80bec3c728646a4
|
4
|
+
data.tar.gz: 3d26302dd73d2ae010f4732ca4711a7dd1daa4ca0cca55e5ccd50349e89b282c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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
|
-
|
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
|
-
|
9
|
+
It measures database usage within a block of code, including:
|
9
10
|
|
10
|
-
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
110
|
+
##### 2. active_record_query_counter.row_count notification
|
89
111
|
|
90
|
-
|
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
|
-
|
119
|
+
##### 3. active_record_query_counter.transaction_time notification
|
98
120
|
|
99
|
-
|
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
|
-
|
125
|
+
##### 4. active_record_query_counter.transaction_count notification
|
104
126
|
|
105
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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.
|
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 = "
|
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.
|
@@ -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
|
-
|
237
|
-
|
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.
|
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:
|
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.
|
84
|
+
rubygems_version: 3.4.10
|
82
85
|
signing_key:
|
83
86
|
specification_version: 4
|
84
|
-
summary:
|
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
|