active_record_query_counter 3.1.1 → 3.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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +7 -3
- data/VERSION +1 -1
- data/active_record_query_counter.gemspec +1 -3
- data/lib/active_record_query_counter/connection_adapter_extension.rb +40 -14
- data/lib/active_record_query_counter.rb +92 -30
- metadata +3 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: daaa5b12132d82613fb803966073b0b55131f0e47b83c1d05e0e6dca63c3ba98
|
|
4
|
+
data.tar.gz: ede14e3f86b236a2d39009dfe84d930a0541eea70c1273d7346ff4ac40218154
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03c8d4e734928d45f7a95188e4a9dc805ef45dabef52d0144d4323f5100163c2603955d1ffa3e78f22178fec458932ea8f56ee67f346bb7a51eae83264de4cee
|
|
7
|
+
data.tar.gz: 38e3d4959598bc8a9d8cd80c06b07fa34485e9a812095be7783f7a8161e3bcf0e4f3aaa619a114fe8beac9b4251bfdc78b3e445b67e5e0fe21a505b865bb33b2
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ 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
|
+
## 3.2.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Connection setup time (time spent in the adapter's `connect!`, `reconnect!`, and `verify!` methods while running a query) is now measured and subtracted from the reported query time, so a query that triggers a reconnect after an idle period or a database failover is no longer reported as an inexplicably slow query. The time is reported separately as `:connection_time` in the `query_time` and `row_count` notification payloads.
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
|
|
15
|
+
- Support for ActiveRecord versions prior to 7.1.
|
|
16
|
+
|
|
7
17
|
## 3.1.1
|
|
8
18
|
|
|
9
19
|
### Fixed
|
data/README.md
CHANGED
|
@@ -57,9 +57,11 @@ end
|
|
|
57
57
|
|
|
58
58
|
### Query Time
|
|
59
59
|
|
|
60
|
-
The query time (`ActiveRecordQueryCounter.query_time` and the duration reported by the notifications) is **not** the raw wall clock time a query took. The wall clock time includes time the thread was not actually waiting on the database, such as GC pauses (which can be triggered by other threads and stop the world)
|
|
60
|
+
The query time (`ActiveRecordQueryCounter.query_time` and the duration reported by the notifications) is **not** the raw wall clock time a query took. The wall clock time includes time the thread was not actually waiting on the database, such as GC pauses (which can be triggered by other threads and stop the world), the Ruby CPU work of building the result objects, and the time spent establishing or re-establishing the database connection. On a busy, multi-threaded server these can add up to seconds, making a trivial query look pathologically slow.
|
|
61
61
|
|
|
62
|
-
To report the time actually spent waiting on the database as closely as possible, the GC time and thread CPU time that elapsed while the query ran are subtracted from the wall clock time. The raw wall clock time is still available as `:elapsed_time` in the notification payloads.
|
|
62
|
+
To report the time actually spent waiting on the database as closely as possible, the connection setup time, GC time, and thread CPU time that elapsed while the query ran are subtracted from the wall clock time. The raw wall clock time is still available as `:elapsed_time` in the notification payloads.
|
|
63
|
+
|
|
64
|
+
Connection setup time is the wall clock time spent inside the adapter's `connect!`, `reconnect!`, and `verify!` methods while running the query. ActiveRecord (re)establishes and verifies connections lazily, from within the query execution path, so when a connection has gone stale — after an idle period, or a database failover (common with clustered databases such as Amazon Aurora) — the reconnect (DNS resolution, TCP connect, TLS handshake, and authentication) happens on the next query and is otherwise charged to it. This is reported separately as `:connection_time` in the notification payloads so these events are diagnosable rather than appearing as inexplicably slow queries.
|
|
63
65
|
|
|
64
66
|
> [!NOTE]
|
|
65
67
|
> Measuring GC time requires Ruby's GC total time measurement, which is enabled by default (`GC.measure_total_time`). Thread CPU time is measured via `Process::CLOCK_THREAD_CPUTIME_ID`; on platforms that do not provide it, CPU time is treated as zero.
|
|
@@ -118,8 +120,9 @@ Triggered when a query exceeds the query_time threshold with the payload:
|
|
|
118
120
|
- `:elapsed_time` - The raw wall clock time the query took (in milliseconds).
|
|
119
121
|
- `:gc_time` - The GC time that elapsed while the query ran (in milliseconds).
|
|
120
122
|
- `:cpu_time` - The thread CPU time spent while the query ran (in milliseconds).
|
|
123
|
+
- `:connection_time` - The time spent establishing, verifying, or reconnecting the database connection while the query ran (in milliseconds).
|
|
121
124
|
|
|
122
|
-
The duration of the notification event is the query time: the wall clock time with the GC time and CPU time subtracted out (see [Query Time](#query-time)). The raw wall clock time is still available as `:elapsed_time`.
|
|
125
|
+
The duration of the notification event is the query time: the wall clock time with the connection setup time, GC time, and CPU time subtracted out (see [Query Time](#query-time)). The raw wall clock time is still available as `:elapsed_time`.
|
|
123
126
|
|
|
124
127
|
##### 2. active_record_query_counter.row_count notification
|
|
125
128
|
|
|
@@ -132,6 +135,7 @@ Triggered when a query exceeds the row_count threshold with the payload:
|
|
|
132
135
|
- `:elapsed_time` - The raw wall clock time the query took (in milliseconds).
|
|
133
136
|
- `:gc_time` - The GC time that elapsed while the query ran (in milliseconds).
|
|
134
137
|
- `:cpu_time` - The thread CPU time spent while the query ran (in milliseconds).
|
|
138
|
+
- `:connection_time` - The time spent establishing, verifying, or reconnecting the database connection while the query ran (in milliseconds).
|
|
135
139
|
|
|
136
140
|
##### 3. active_record_query_counter.transaction_time notification
|
|
137
141
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.2.0
|
|
@@ -34,9 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
|
|
35
35
|
spec.require_paths = ["lib"]
|
|
36
36
|
|
|
37
|
-
spec.add_dependency "activerecord", ">=
|
|
38
|
-
|
|
39
|
-
spec.add_development_dependency "bundler"
|
|
37
|
+
spec.add_dependency "activerecord", ">= 7.1"
|
|
40
38
|
|
|
41
39
|
spec.required_ruby_version = ">= 3.1"
|
|
42
40
|
end
|
|
@@ -8,19 +8,28 @@ module ActiveRecordQueryCounter
|
|
|
8
8
|
# measured and is treated as zero.
|
|
9
9
|
CPU_CLOCK_ID = (Process::CLOCK_THREAD_CPUTIME_ID if defined?(Process::CLOCK_THREAD_CPUTIME_ID))
|
|
10
10
|
|
|
11
|
+
# Connection adapter methods that establish, verify, or reconnect the underlying database
|
|
12
|
+
# connection. When these run inside a query (for example when a stale connection is
|
|
13
|
+
# re-established after an idle period or a database failover), the wall clock time they
|
|
14
|
+
# consume is spent setting up the connection rather than executing the query. It is measured
|
|
15
|
+
# separately so it can be subtracted from the reported query time.
|
|
16
|
+
CONNECTION_SETUP_METHODS = %i[connect! reconnect! verify!].freeze
|
|
17
|
+
|
|
11
18
|
class << self
|
|
12
19
|
def inject(connection_class)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
unless connection_class.include?(InternalExecQuery)
|
|
21
|
+
connection_class.prepend(InternalExecQuery)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
unless connection_class.include?(ConnectionSetupExtension)
|
|
25
|
+
connection_class.prepend(ConnectionSetupExtension)
|
|
17
26
|
end
|
|
18
27
|
end
|
|
19
28
|
|
|
20
29
|
# Measure a query by wrapping its execution. In addition to the wall clock time, the GC
|
|
21
|
-
# time
|
|
22
|
-
# actually spent waiting on the database can be isolated from time lost to
|
|
23
|
-
# collection
|
|
30
|
+
# time, thread CPU time, and connection setup time spent while the query runs are captured
|
|
31
|
+
# so that the time actually spent waiting on the database can be isolated from time lost to
|
|
32
|
+
# garbage collection, Ruby VM work, and (re)establishing the database connection.
|
|
24
33
|
#
|
|
25
34
|
# @param sql [String] the SQL statement being executed
|
|
26
35
|
# @param name [String, nil] the name of the query
|
|
@@ -30,13 +39,18 @@ module ActiveRecordQueryCounter
|
|
|
30
39
|
def measure_query(sql, name, binds)
|
|
31
40
|
gc_start = GC.total_time
|
|
32
41
|
cpu_start = current_cpu_time
|
|
42
|
+
previous_timer = ActiveRecordQueryCounter.start_connection_timer
|
|
33
43
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
34
|
-
|
|
44
|
+
begin
|
|
45
|
+
result = yield
|
|
46
|
+
ensure
|
|
47
|
+
connection_time = ActiveRecordQueryCounter.stop_connection_timer(previous_timer)
|
|
48
|
+
end
|
|
35
49
|
if result.is_a?(ActiveRecord::Result)
|
|
36
50
|
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
37
51
|
cpu_time = current_cpu_time - cpu_start
|
|
38
52
|
gc_time = (GC.total_time - gc_start) / 1_000_000_000.0
|
|
39
|
-
ActiveRecordQueryCounter.add_query(sql, name, binds, result.length, start_time, end_time, gc_time, cpu_time)
|
|
53
|
+
ActiveRecordQueryCounter.add_query(sql, name, binds, result.length, start_time, end_time, gc_time, cpu_time, connection_time)
|
|
40
54
|
end
|
|
41
55
|
result
|
|
42
56
|
end
|
|
@@ -51,15 +65,27 @@ module ActiveRecordQueryCounter
|
|
|
51
65
|
end
|
|
52
66
|
end
|
|
53
67
|
|
|
54
|
-
module
|
|
55
|
-
def
|
|
68
|
+
module InternalExecQuery
|
|
69
|
+
def internal_exec_query(sql, name = nil, binds = [], **kwargs)
|
|
56
70
|
ConnectionAdapterExtension.measure_query(sql, name, binds) { super }
|
|
57
71
|
end
|
|
58
72
|
end
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
# Module prepended to the connection adapter to measure the wall clock time spent
|
|
75
|
+
# establishing, verifying, or reconnecting the database connection while a query is running
|
|
76
|
+
# (see {CONNECTION_SETUP_METHODS}). The measured time is accumulated on the current query's
|
|
77
|
+
# connection timer so it can be subtracted from the reported query time.
|
|
78
|
+
module ConnectionSetupExtension
|
|
79
|
+
def connect!(...)
|
|
80
|
+
ActiveRecordQueryCounter.measure_connection_setup { super }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def reconnect!(...)
|
|
84
|
+
ActiveRecordQueryCounter.measure_connection_setup { super }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def verify!(...)
|
|
88
|
+
ActiveRecordQueryCounter.measure_connection_setup { super }
|
|
63
89
|
end
|
|
64
90
|
end
|
|
65
91
|
end
|
|
@@ -72,10 +72,11 @@ module ActiveRecordQueryCounter
|
|
|
72
72
|
# Increment the query counters.
|
|
73
73
|
#
|
|
74
74
|
# The reported query time is the wall clock time spent executing the query with the GC
|
|
75
|
-
# time
|
|
76
|
-
# spent waiting on the database as closely as possible (see
|
|
77
|
-
# query time, rather than the raw wall clock time, is what is
|
|
78
|
-
# the threshold, and used as the duration of the emitted
|
|
75
|
+
# time, Ruby thread CPU time, and connection setup time subtracted out so that it reflects
|
|
76
|
+
# the time actually spent waiting on the database as closely as possible (see
|
|
77
|
+
# {.database_query_time}). This query time, rather than the raw wall clock time, is what is
|
|
78
|
+
# accumulated, compared against the threshold, and used as the duration of the emitted
|
|
79
|
+
# notification.
|
|
79
80
|
#
|
|
80
81
|
# @param sql [String] the SQL statement that was executed
|
|
81
82
|
# @param name [String, nil] the name of the query
|
|
@@ -85,16 +86,18 @@ module ActiveRecordQueryCounter
|
|
|
85
86
|
# @param end_time [Float] the monotonic time when the query ended
|
|
86
87
|
# @param gc_time [Float] the GC time in seconds that elapsed while the query ran
|
|
87
88
|
# @param cpu_time [Float] the thread CPU time in seconds spent while the query ran
|
|
89
|
+
# @param connection_time [Float] the time in seconds spent establishing, verifying, or
|
|
90
|
+
# reconnecting the database connection while the query ran
|
|
88
91
|
# @return [void]
|
|
89
92
|
# @api private
|
|
90
|
-
def add_query(sql, name, binds, row_count, start_time, end_time, gc_time, cpu_time)
|
|
93
|
+
def add_query(sql, name, binds, row_count, start_time, end_time, gc_time, cpu_time, connection_time = 0.0)
|
|
91
94
|
return if IGNORED_STATEMENTS.include?(name)
|
|
92
95
|
|
|
93
96
|
counter = current_counter
|
|
94
97
|
return unless counter.is_a?(Counter)
|
|
95
98
|
|
|
96
99
|
elapsed_time = end_time - start_time
|
|
97
|
-
query_time = database_query_time(elapsed_time, gc_time, cpu_time)
|
|
100
|
+
query_time = database_query_time(elapsed_time, gc_time, cpu_time, connection_time)
|
|
98
101
|
counter.query_count += 1
|
|
99
102
|
counter.row_count += row_count
|
|
100
103
|
counter.query_time += query_time
|
|
@@ -107,14 +110,14 @@ module ActiveRecordQueryCounter
|
|
|
107
110
|
query_time_threshold = counter.thresholds.query_time || -1
|
|
108
111
|
if query_time_threshold.between?(0, query_time)
|
|
109
112
|
trace = backtrace
|
|
110
|
-
payload = notification_payload(sql: sql, binds: binds, row_count: row_count, trace: trace, elapsed_time: elapsed_time, gc_time: gc_time, cpu_time: cpu_time)
|
|
113
|
+
payload = notification_payload(sql: sql, binds: binds, row_count: row_count, trace: trace, elapsed_time: elapsed_time, gc_time: gc_time, cpu_time: cpu_time, connection_time: connection_time)
|
|
111
114
|
send_notification("query_time", start_time, notification_end_time, **payload)
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
row_count_threshold = counter.thresholds.row_count || -1
|
|
115
118
|
if row_count_threshold.between?(0, row_count)
|
|
116
119
|
trace ||= backtrace
|
|
117
|
-
payload = notification_payload(sql: sql, binds: binds, row_count: row_count, trace: trace, elapsed_time: elapsed_time, gc_time: gc_time, cpu_time: cpu_time)
|
|
120
|
+
payload = notification_payload(sql: sql, binds: binds, row_count: row_count, trace: trace, elapsed_time: elapsed_time, gc_time: gc_time, cpu_time: cpu_time, connection_time: connection_time)
|
|
118
121
|
send_notification("row_count", start_time, notification_end_time, **payload)
|
|
119
122
|
end
|
|
120
123
|
end
|
|
@@ -149,6 +152,54 @@ module ActiveRecordQueryCounter
|
|
|
149
152
|
counter.rollback_count += 1
|
|
150
153
|
end
|
|
151
154
|
|
|
155
|
+
# Begin measuring the time spent establishing, verifying, or reconnecting the database
|
|
156
|
+
# connection for a single query. Returns the timer that was previously in effect so it can
|
|
157
|
+
# be restored by {.stop_connection_timer}; this keeps nested queries (should they ever
|
|
158
|
+
# occur) from leaking connection time into one another.
|
|
159
|
+
#
|
|
160
|
+
# @return [Object, nil] the previous connection timer
|
|
161
|
+
# @api private
|
|
162
|
+
def start_connection_timer
|
|
163
|
+
previous_timer = connection_timer
|
|
164
|
+
self.connection_timer = {elapsed: 0.0, measuring: false}
|
|
165
|
+
previous_timer
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Finish measuring connection setup time for the current query and restore the previously
|
|
169
|
+
# active timer.
|
|
170
|
+
#
|
|
171
|
+
# @param previous_timer [Object, nil] the timer returned by {.start_connection_timer}
|
|
172
|
+
# @return [Float] the connection setup time in seconds accumulated for the query
|
|
173
|
+
# @api private
|
|
174
|
+
def stop_connection_timer(previous_timer)
|
|
175
|
+
timer = connection_timer
|
|
176
|
+
self.connection_timer = previous_timer
|
|
177
|
+
timer ? timer[:elapsed] : 0.0
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Measure the wall clock time a connection setup operation (connect, reconnect, or verify)
|
|
181
|
+
# takes and accumulate it onto the current query's connection timer. When no query is being
|
|
182
|
+
# measured, or when a connection setup operation is already being measured (for example when
|
|
183
|
+
# `verify!` delegates to `reconnect!`), the block is yielded without recording so the
|
|
184
|
+
# interval is only counted once.
|
|
185
|
+
#
|
|
186
|
+
# @yield the connection setup operation
|
|
187
|
+
# @return [Object] the result of the block
|
|
188
|
+
# @api private
|
|
189
|
+
def measure_connection_setup
|
|
190
|
+
timer = connection_timer
|
|
191
|
+
return yield if timer.nil? || timer[:measuring]
|
|
192
|
+
|
|
193
|
+
timer[:measuring] = true
|
|
194
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
195
|
+
begin
|
|
196
|
+
yield
|
|
197
|
+
ensure
|
|
198
|
+
timer[:elapsed] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
199
|
+
timer[:measuring] = false
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
152
203
|
# Return the number of queries that have been counted within the current block.
|
|
153
204
|
# Returns nil if not inside a block where queries are being counted.
|
|
154
205
|
#
|
|
@@ -295,24 +346,24 @@ module ActiveRecordQueryCounter
|
|
|
295
346
|
|
|
296
347
|
private
|
|
297
348
|
|
|
298
|
-
# The counter is stored in ActiveSupport::IsolatedExecutionState
|
|
299
|
-
#
|
|
300
|
-
# for ActiveSupport 6.x uses Thread.current, which is fiber-local, so on those versions
|
|
301
|
-
# queries executed in a fiber spawned inside the block are not counted.
|
|
349
|
+
# The counter is stored in ActiveSupport::IsolatedExecutionState so that it follows the
|
|
350
|
+
# application's configured isolation level (thread or fiber).
|
|
302
351
|
def current_counter
|
|
303
|
-
|
|
304
|
-
ActiveSupport::IsolatedExecutionState[:active_record_query_counter]
|
|
305
|
-
else
|
|
306
|
-
Thread.current[:active_record_query_counter]
|
|
307
|
-
end
|
|
352
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_counter]
|
|
308
353
|
end
|
|
309
354
|
|
|
310
355
|
def current_counter=(counter)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
356
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_counter] = counter
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# The connection timer accumulates the connection setup time for the query currently being
|
|
360
|
+
# measured. It is stored with the same isolation as the counter (see {#current_counter}).
|
|
361
|
+
def connection_timer
|
|
362
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_counter_connection_timer]
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def connection_timer=(timer)
|
|
366
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_counter_connection_timer] = timer
|
|
316
367
|
end
|
|
317
368
|
|
|
318
369
|
def send_notification(name, start_time, end_time, payload = {})
|
|
@@ -320,7 +371,7 @@ module ActiveRecordQueryCounter
|
|
|
320
371
|
ActiveSupport::Notifications.publish("active_record_query_counter.#{name}", start_time, end_time, id, payload)
|
|
321
372
|
end
|
|
322
373
|
|
|
323
|
-
def notification_payload(sql:, binds:, row_count:, trace:, elapsed_time:, gc_time:, cpu_time:)
|
|
374
|
+
def notification_payload(sql:, binds:, row_count:, trace:, elapsed_time:, gc_time:, cpu_time:, connection_time:)
|
|
324
375
|
{
|
|
325
376
|
sql: sql,
|
|
326
377
|
binds: binds,
|
|
@@ -328,12 +379,18 @@ module ActiveRecordQueryCounter
|
|
|
328
379
|
trace: trace,
|
|
329
380
|
elapsed_time: (elapsed_time * 1000.0).round(6),
|
|
330
381
|
gc_time: (gc_time * 1000.0).round(6),
|
|
331
|
-
cpu_time: (cpu_time * 1000.0).round(6)
|
|
382
|
+
cpu_time: (cpu_time * 1000.0).round(6),
|
|
383
|
+
connection_time: (connection_time * 1000.0).round(6)
|
|
332
384
|
}
|
|
333
385
|
end
|
|
334
386
|
|
|
335
|
-
# Estimate the time spent waiting on the database by subtracting the
|
|
336
|
-
# time from the wall clock time the query took.
|
|
387
|
+
# Estimate the time spent waiting on the database by subtracting the connection setup time,
|
|
388
|
+
# GC time, and thread CPU time from the wall clock time the query took.
|
|
389
|
+
#
|
|
390
|
+
# The connection setup time is a measured sub-interval of the wall clock time that was spent
|
|
391
|
+
# establishing, verifying, or reconnecting the database connection rather than executing the
|
|
392
|
+
# query, so it is removed first. This is the time that inflates a trivial query into a
|
|
393
|
+
# multi-second one after an idle period or a database failover.
|
|
337
394
|
#
|
|
338
395
|
# The GC time and CPU time normally measure distinct, non-overlapping intervals: a GC pause
|
|
339
396
|
# triggered by another thread happens while this thread is parked waiting on the database
|
|
@@ -347,13 +404,18 @@ module ActiveRecordQueryCounter
|
|
|
347
404
|
# @param elapsed_time [Float] the wall clock time the query took in seconds
|
|
348
405
|
# @param gc_time [Float] the GC time in seconds that elapsed while the query ran
|
|
349
406
|
# @param cpu_time [Float] the thread CPU time in seconds spent while the query ran
|
|
407
|
+
# @param connection_time [Float] the time in seconds spent establishing, verifying, or
|
|
408
|
+
# reconnecting the database connection while the query ran
|
|
350
409
|
# @return [Float] the estimated database time in seconds
|
|
351
|
-
def database_query_time(elapsed_time, gc_time, cpu_time)
|
|
410
|
+
def database_query_time(elapsed_time, gc_time, cpu_time, connection_time = 0.0)
|
|
352
411
|
return 0.0 if elapsed_time <= 0.0
|
|
353
412
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
413
|
+
wait_time = (elapsed_time - connection_time).clamp(0.0, elapsed_time)
|
|
414
|
+
return 0.0 if wait_time <= 0.0
|
|
415
|
+
|
|
416
|
+
query_time = wait_time - (gc_time + cpu_time)
|
|
417
|
+
query_time = wait_time - [gc_time, cpu_time].max if query_time.negative?
|
|
418
|
+
query_time.clamp(0.0, wait_time)
|
|
357
419
|
end
|
|
358
420
|
|
|
359
421
|
def backtrace
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_record_query_counter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Durand
|
|
@@ -15,28 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '7.1'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: bundler
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0'
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0'
|
|
25
|
+
version: '7.1'
|
|
40
26
|
email:
|
|
41
27
|
- bbdurand@gmail.com
|
|
42
28
|
executables: []
|