time_bandits 0.14.0 → 0.15.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/.github/workflows/run-tests.yml +4 -4
- data/Appraisals +6 -5
- data/CHANGELOG.md +4 -0
- data/Gemfile +14 -0
- data/lib/time_bandits/monkey_patches/active_record/log_subscriber.rb +77 -0
- data/lib/time_bandits/monkey_patches/active_record/railties/controller_runtime.rb +29 -0
- data/lib/time_bandits/monkey_patches/active_record/runtime_registry.rb +70 -0
- data/lib/time_bandits/monkey_patches/active_record.rb +5 -157
- data/lib/time_bandits/time_consumers/database.rb +14 -2
- data/lib/time_bandits/version.rb +1 -1
- data/test/unit/database_test.rb +54 -6
- data/test/unit/memcached_test.rb +1 -0
- data/time_bandits.gemspec +2 -14
- metadata +10 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56bb0eb9adc75541319ab152fee15ca29bb60d92135a85e2dee0dc192334c03e
|
4
|
+
data.tar.gz: 51c3edf811d144bd2221d57994b1a53ccbbe92228a42252628037d1cae8b3113
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a020882e44e5b0244b2a426b31cfa855b4aa4c4cb2fb3b7e0c2e9b7a9bf37eb4a4ccb86484b8e851e7902fe5afc4e3a6a7f2803a47de0d5b286055ba5db3edc
|
7
|
+
data.tar.gz: e74877201e8880fd4eb0d5e52728badcb0dfd89b8b9429cde69dacae7ba5afcef4b3d82ea016f2c342139f3f6447e07f96b8c35b68e03195ff65bdabb8a90367
|
@@ -13,13 +13,13 @@ jobs:
|
|
13
13
|
|
14
14
|
strategy:
|
15
15
|
matrix:
|
16
|
-
ruby-version: [3.
|
16
|
+
ruby-version: [3.3.1, 3.2.4, 3.1.5, 3.0.7]
|
17
17
|
|
18
18
|
steps:
|
19
|
-
- uses: actions/checkout@
|
19
|
+
- uses: actions/checkout@v4
|
20
20
|
|
21
21
|
- name: Start containers
|
22
|
-
run: docker
|
22
|
+
run: docker compose -f docker-compose.yml up -d
|
23
23
|
|
24
24
|
- name: Set up Ruby ${{ matrix.ruby-version }}
|
25
25
|
uses: ruby/setup-ruby@v1
|
@@ -43,4 +43,4 @@ jobs:
|
|
43
43
|
|
44
44
|
- name: Stop containers
|
45
45
|
if: always()
|
46
|
-
run: docker
|
46
|
+
run: docker compose -f "docker-compose.yml" down
|
data/Appraisals
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
appraisals = [
|
2
|
-
"6.
|
3
|
-
"
|
4
|
-
"7.
|
5
|
-
"7.1.0"
|
2
|
+
"6.1.7.8",
|
3
|
+
"7.0.8.4",
|
4
|
+
"7.1.3.4",
|
6
5
|
]
|
7
6
|
|
8
|
-
|
7
|
+
if RUBY_VERSION >= "3.1"
|
8
|
+
appraisals << "7.2.0.rc1"
|
9
|
+
end
|
9
10
|
|
10
11
|
appraisals.each do |rails_version|
|
11
12
|
%w(4.0 5.0).each do |redis_version|
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -3,4 +3,18 @@ source "https://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in time_bandits.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem "ansi"
|
7
|
+
gem "appraisal"
|
8
|
+
gem "byebug"
|
9
|
+
gem "dalli"
|
10
|
+
gem "memcached", "~> 1.8.0" if RUBY_VERSION < "3.3.0"
|
11
|
+
gem "minitest"
|
12
|
+
gem "mocha"
|
13
|
+
gem "mysql2"
|
14
|
+
gem "rake"
|
15
|
+
gem "redis"
|
16
|
+
gem "sequel"
|
17
|
+
gem "activerecord"
|
18
|
+
gem "beetle", ">= 3.4.1"
|
19
|
+
|
6
20
|
gem "hiredis-client"
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# This file monkey patches class ActiveRecord::LogSubscriber to count
|
2
|
+
# the number of sql statements being executed and the number of query
|
3
|
+
# cache hits, but is only used for Rails versions before 7.1.0.
|
4
|
+
|
5
|
+
require "active_record/log_subscriber"
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
class LogSubscriber
|
9
|
+
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"] unless defined?(IGNORE_PAYLOAD_NAMES)
|
10
|
+
|
11
|
+
def self.call_count=(value)
|
12
|
+
Thread.current.thread_variable_set(:active_record_sql_call_count, value)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.call_count
|
16
|
+
Thread.current.thread_variable_get(:active_record_sql_call_count) ||
|
17
|
+
Thread.current.thread_variable_set(:active_record_sql_call_count, 0)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.query_cache_hits=(value)
|
21
|
+
Thread.current.thread_variable_set(:active_record_sql_query_cache_hits, value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.query_cache_hits
|
25
|
+
Thread.current.thread_variable_get(:active_record_sql_query_cache_hits) ||
|
26
|
+
Thread.current.thread_variable_set(:active_record_sql_query_cache_hits, 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.reset_call_count
|
30
|
+
calls = call_count
|
31
|
+
self.call_count = 0
|
32
|
+
calls
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.reset_query_cache_hits
|
36
|
+
hits = query_cache_hits
|
37
|
+
self.query_cache_hits = 0
|
38
|
+
hits
|
39
|
+
end
|
40
|
+
|
41
|
+
remove_method :sql
|
42
|
+
def sql(event)
|
43
|
+
payload = event.payload
|
44
|
+
|
45
|
+
self.class.runtime += event.duration
|
46
|
+
self.class.call_count += 1
|
47
|
+
self.class.query_cache_hits += 1 if payload[:cached] || payload[:name] == "CACHE"
|
48
|
+
|
49
|
+
return unless logger.debug?
|
50
|
+
|
51
|
+
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
52
|
+
|
53
|
+
log_sql_statement(payload, event)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def log_sql_statement(payload, event)
|
58
|
+
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
59
|
+
name = "CACHE #{name}" if payload[:cached]
|
60
|
+
sql = payload[:sql]
|
61
|
+
binds = nil
|
62
|
+
|
63
|
+
unless (payload[:binds] || []).empty?
|
64
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
65
|
+
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
66
|
+
render_bind(attr, value)
|
67
|
+
}.inspect
|
68
|
+
end
|
69
|
+
|
70
|
+
name = colorize_payload_name(name, payload[:name])
|
71
|
+
sql = color(sql, sql_color(sql), true)
|
72
|
+
|
73
|
+
debug " #{name} #{sql}#{binds}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "active_record/railties/controller_runtime"
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Railties
|
5
|
+
module ControllerRuntime
|
6
|
+
remove_method :cleanup_view_runtime
|
7
|
+
def cleanup_view_runtime
|
8
|
+
# this method has been redefined to do nothing for activerecord on purpose
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
remove_method :append_info_to_payload
|
13
|
+
def append_info_to_payload(payload)
|
14
|
+
super
|
15
|
+
if ActiveRecord::Base.connected?
|
16
|
+
payload[:db_runtime] = TimeBandits::TimeConsumers::Database.instance.consumed
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
# this method has been redefined to do nothing for activerecord on purpose
|
22
|
+
remove_method :log_process_action
|
23
|
+
def log_process_action(payload)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# This file monkey patches class ActiveRecord::RuntimeRegistry to
|
2
|
+
# additionally store call counts and cache hits and subscribes an
|
3
|
+
# event listener to manage those counters. It is used if the active
|
4
|
+
# record version is 7.1.0 or higher.
|
5
|
+
|
6
|
+
require "active_record/runtime_registry"
|
7
|
+
|
8
|
+
module ActiveRecord
|
9
|
+
module RuntimeRegistry
|
10
|
+
|
11
|
+
if respond_to?(:queries_count)
|
12
|
+
alias_method :call_count, :queries_count
|
13
|
+
alias_method :call_count=, :queries_count=
|
14
|
+
else
|
15
|
+
def self.call_count
|
16
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_call_count] ||= 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.call_count=(value)
|
20
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_call_count] = value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if respond_to?(:cached_queries_count)
|
25
|
+
alias_method :query_cache_hits, :cached_queries_count
|
26
|
+
alias_method :query_cache_hits=, :cached_queries_count=
|
27
|
+
else
|
28
|
+
def self.query_cache_hits
|
29
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_query_cache_hits] ||= 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.query_cache_hits=(value)
|
33
|
+
ActiveSupport::IsolatedExecutionState[:active_record_sql_query_cache_hits] = value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if respond_to?(:reset_runtimes)
|
38
|
+
alias_method :reset_runtime, :reset_runtimes
|
39
|
+
else
|
40
|
+
alias_method :reset_runtime, :reset
|
41
|
+
end
|
42
|
+
alias_method :runtime, :sql_runtime
|
43
|
+
alias_method :runtime=, :sql_runtime=
|
44
|
+
|
45
|
+
def self.reset_call_count
|
46
|
+
calls = call_count
|
47
|
+
self.call_count = 0
|
48
|
+
calls
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.reset_query_cache_hits
|
52
|
+
hits = query_cache_hits
|
53
|
+
self.query_cache_hits = 0
|
54
|
+
hits
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Rails 7.2 already collects query counts and cache hits, so we no
|
62
|
+
# longer need our own event handler.
|
63
|
+
unless ActiveRecord::RuntimeRegistry.respond_to?(:queries_count)
|
64
|
+
require "active_support/notifications"
|
65
|
+
|
66
|
+
ActiveSupport::Notifications.monotonic_subscribe("sql.active_record") do |event|
|
67
|
+
ActiveRecord::RuntimeRegistry.call_count += 1
|
68
|
+
ActiveRecord::RuntimeRegistry.query_cache_hits += 1 if event.payload[:cached]
|
69
|
+
end
|
70
|
+
end
|
@@ -1,158 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require "active_record/log_subscriber"
|
7
|
-
|
8
|
-
module ActiveRecord
|
9
|
-
class LogSubscriber
|
10
|
-
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"] unless defined?(IGNORE_PAYLOAD_NAMES)
|
11
|
-
|
12
|
-
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.1.0")
|
13
|
-
def self.reset_runtime
|
14
|
-
ActiveRecord::RuntimeRegistry.reset
|
15
|
-
end
|
16
|
-
def self.runtime
|
17
|
-
ActiveRecord::RuntimeRegistry.sql_runtime
|
18
|
-
end
|
19
|
-
def self.runtime=(value)
|
20
|
-
ActiveRecord::RuntimeRegistry.sql_runtime = value
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.call_count=(value)
|
25
|
-
Thread.current.thread_variable_set(:active_record_sql_call_count, value)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.call_count
|
29
|
-
Thread.current.thread_variable_get(:active_record_sql_call_count) ||
|
30
|
-
Thread.current.thread_variable_set(:active_record_sql_call_count, 0)
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.query_cache_hits=(value)
|
34
|
-
Thread.current.thread_variable_set(:active_record_sql_query_cache_hits, value)
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.query_cache_hits
|
38
|
-
Thread.current.thread_variable_get(:active_record_sql_query_cache_hits) ||
|
39
|
-
Thread.current.thread_variable_set(:active_record_sql_query_cache_hits, 0)
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.reset_call_count
|
43
|
-
calls = call_count
|
44
|
-
self.call_count = 0
|
45
|
-
calls
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.reset_query_cache_hits
|
49
|
-
hits = query_cache_hits
|
50
|
-
self.query_cache_hits = 0
|
51
|
-
hits
|
52
|
-
end
|
53
|
-
|
54
|
-
remove_method :sql
|
55
|
-
def sql(event)
|
56
|
-
payload = event.payload
|
57
|
-
|
58
|
-
self.class.runtime += event.duration
|
59
|
-
self.class.call_count += 1
|
60
|
-
self.class.query_cache_hits += 1 if payload[:cached] || payload[:name] == "CACHE"
|
61
|
-
|
62
|
-
return unless logger.debug?
|
63
|
-
|
64
|
-
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
65
|
-
|
66
|
-
log_sql_statement(payload, event)
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
def log_sql_statement(payload, event)
|
71
|
-
name = if payload[:async]
|
72
|
-
"ASYNC #{payload[:name]} (#{payload[:lock_wait].round(1)}ms) (db time #{event.duration.round(1)}ms)"
|
73
|
-
else
|
74
|
-
"#{payload[:name]} (#{event.duration.round(1)}ms)"
|
75
|
-
end
|
76
|
-
name = "CACHE #{name}" if payload[:cached]
|
77
|
-
sql = payload[:sql]
|
78
|
-
binds = render_binds(payload)
|
79
|
-
|
80
|
-
name = colorize_payload_name(name, payload[:name])
|
81
|
-
sql = colorize_sql(sql) if colorize_logging
|
82
|
-
|
83
|
-
debug " #{name} #{sql}#{binds}"
|
84
|
-
end
|
85
|
-
|
86
|
-
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.1.0")
|
87
|
-
def render_binds(payload)
|
88
|
-
binds = nil
|
89
|
-
if payload[:binds]&.any?
|
90
|
-
casted_params = type_casted_binds(payload[:type_casted_binds])
|
91
|
-
|
92
|
-
binds = []
|
93
|
-
payload[:binds].each_with_index do |attr, i|
|
94
|
-
attribute_name = if attr.respond_to?(:name)
|
95
|
-
attr.name
|
96
|
-
elsif attr.respond_to?(:[]) && attr[i].respond_to?(:name)
|
97
|
-
attr[i].name
|
98
|
-
else
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
|
102
|
-
filtered_params = filter(attribute_name, casted_params[i])
|
103
|
-
|
104
|
-
binds << render_bind(attr, filtered_params)
|
105
|
-
end
|
106
|
-
binds = binds.inspect
|
107
|
-
binds.prepend(" ")
|
108
|
-
end
|
109
|
-
return binds
|
110
|
-
end
|
111
|
-
def colorize_sql(sql)
|
112
|
-
color(sql, sql_color(sql), bold: true)
|
113
|
-
end
|
114
|
-
else
|
115
|
-
def render_binds(payload)
|
116
|
-
binds = nil
|
117
|
-
unless (payload[:binds] || []).empty?
|
118
|
-
casted_params = type_casted_binds(payload[:type_casted_binds])
|
119
|
-
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
120
|
-
render_bind(attr, value)
|
121
|
-
}.inspect
|
122
|
-
end
|
123
|
-
return binds
|
124
|
-
end
|
125
|
-
def colorize_sql(sql)
|
126
|
-
color(sql, sql_color(sql), true)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
require "active_record/railties/controller_runtime"
|
132
|
-
|
133
|
-
module Railties
|
134
|
-
module ControllerRuntime
|
135
|
-
remove_method :cleanup_view_runtime
|
136
|
-
def cleanup_view_runtime
|
137
|
-
# this method has been redefined to do nothing for activerecord on purpose
|
138
|
-
super
|
139
|
-
end
|
140
|
-
|
141
|
-
remove_method :append_info_to_payload
|
142
|
-
def append_info_to_payload(payload)
|
143
|
-
super
|
144
|
-
if ActiveRecord::Base.connected?
|
145
|
-
payload[:db_runtime] = TimeBandits::TimeConsumers::Database.instance.consumed
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
module ClassMethods
|
150
|
-
# this method has been redefined to do nothing for activerecord on purpose
|
151
|
-
remove_method :log_process_action
|
152
|
-
def log_process_action(payload)
|
153
|
-
super
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
1
|
+
if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("7.1.0")
|
2
|
+
require_relative "active_record/log_subscriber"
|
3
|
+
else
|
4
|
+
require_relative "active_record/runtime_registry"
|
158
5
|
end
|
6
|
+
require_relative "active_record/railties/controller_runtime"
|
@@ -13,6 +13,18 @@ module TimeBandits
|
|
13
13
|
fields :time, :calls, :sql_query_cache_hits
|
14
14
|
format "ActiveRecord: %.3fms(%dq,%dh)", :time, :calls, :sql_query_cache_hits
|
15
15
|
|
16
|
+
class << self
|
17
|
+
if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("7.1.0")
|
18
|
+
def metrics_store
|
19
|
+
ActiveRecord::RuntimeRegistry
|
20
|
+
end
|
21
|
+
else
|
22
|
+
def metrics_store
|
23
|
+
ActiveRecord::LogSubscriber
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
def reset
|
17
29
|
reset_stats
|
18
30
|
super
|
@@ -27,13 +39,13 @@ module TimeBandits
|
|
27
39
|
end
|
28
40
|
|
29
41
|
def current_runtime
|
30
|
-
Database.instance.time +
|
42
|
+
Database.instance.time + self.class.metrics_store.runtime
|
31
43
|
end
|
32
44
|
|
33
45
|
private
|
34
46
|
|
35
47
|
def reset_stats
|
36
|
-
s =
|
48
|
+
s = self.class.metrics_store
|
37
49
|
hits = s.reset_query_cache_hits
|
38
50
|
calls = s.reset_call_count
|
39
51
|
time = s.reset_runtime
|
data/lib/time_bandits/version.rb
CHANGED
data/test/unit/database_test.rb
CHANGED
@@ -10,6 +10,15 @@ class DatabaseTest < Test::Unit::TestCase
|
|
10
10
|
TimeBandits.reset
|
11
11
|
@old_logger = ActiveRecord::Base.logger
|
12
12
|
ActiveRecord::Base.logger = Logger.new($stdout)
|
13
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection(
|
16
|
+
adapter: "mysql2",
|
17
|
+
username: "root",
|
18
|
+
encoding: "utf8",
|
19
|
+
host: ENV['MYSQL_HOST'] || "127.0.0.1",
|
20
|
+
port: (ENV['MYSQL_PORT'] || 3601).to_i
|
21
|
+
)
|
13
22
|
end
|
14
23
|
|
15
24
|
def teardown
|
@@ -28,18 +37,20 @@ class DatabaseTest < Test::Unit::TestCase
|
|
28
37
|
end
|
29
38
|
|
30
39
|
test "formatting" do
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
metrics_store.runtime += 1.234
|
41
|
+
metrics_store.call_count += 3
|
42
|
+
metrics_store.query_cache_hits += 1
|
34
43
|
TimeBandits.consumed
|
35
44
|
assert_equal "ActiveRecord: 1.234ms(3q,1h)", TimeBandits.runtime
|
36
45
|
end
|
37
46
|
|
38
47
|
test "accessing current runtime" do
|
39
|
-
|
48
|
+
metrics_store.runtime += 1.234
|
49
|
+
assert_equal 1.234, metrics_store.runtime
|
50
|
+
assert_equal 1.234, bandit.current_runtime
|
40
51
|
assert_equal 1.234, TimeBandits.consumed
|
41
|
-
assert_equal 0,
|
42
|
-
|
52
|
+
assert_equal 0, metrics_store.runtime
|
53
|
+
metrics_store.runtime += 4.0
|
43
54
|
assert_equal 5.234, bandit.current_runtime
|
44
55
|
assert_equal "ActiveRecord: 1.234ms(0q,0h)", TimeBandits.runtime
|
45
56
|
end
|
@@ -52,12 +63,49 @@ class DatabaseTest < Test::Unit::TestCase
|
|
52
63
|
assert_nil log_subscriber.new.sql(event)
|
53
64
|
end
|
54
65
|
|
66
|
+
test "instrumentation records runtimes at log level debug" do
|
67
|
+
ActiveRecord::Base.logger.stubs(:debug)
|
68
|
+
ActiveRecord::Base.connection.execute "SELECT 1"
|
69
|
+
bandit.consumed
|
70
|
+
assert(bandit.current_runtime > 0)
|
71
|
+
if ActiveRecord::VERSION::STRING =~ /\A7.2\..*\Z/
|
72
|
+
# registry ingores schema calls now
|
73
|
+
assert_equal 1, bandit.calls
|
74
|
+
else
|
75
|
+
# 2 calls, because one configures the connection
|
76
|
+
assert_equal 2, bandit.calls
|
77
|
+
end
|
78
|
+
assert_equal 0, bandit.sql_query_cache_hits
|
79
|
+
end
|
80
|
+
|
81
|
+
test "instrumentation records runtimes at log level error" do
|
82
|
+
skip if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("7.1.0")
|
83
|
+
ActiveRecord::Base.logger.level = Logger::ERROR
|
84
|
+
ActiveRecord::LogSubscriber.expects(:sql).never
|
85
|
+
assert_equal 0, bandit.calls
|
86
|
+
ActiveRecord::Base.connection.execute "SELECT 1"
|
87
|
+
bandit.consumed
|
88
|
+
assert(bandit.current_runtime > 0)
|
89
|
+
if ActiveRecord::VERSION::STRING =~ /\A7.2\..*\Z/
|
90
|
+
# registry ingores schema calls now
|
91
|
+
assert_equal 1, bandit.calls
|
92
|
+
else
|
93
|
+
# 2 calls, because one configures the connection
|
94
|
+
assert_equal 2, bandit.calls
|
95
|
+
end
|
96
|
+
assert_equal 0, bandit.sql_query_cache_hits
|
97
|
+
end
|
98
|
+
|
55
99
|
private
|
56
100
|
|
57
101
|
def bandit
|
58
102
|
TimeBandits::TimeConsumers::Database.instance
|
59
103
|
end
|
60
104
|
|
105
|
+
def metrics_store
|
106
|
+
TimeBandits::TimeConsumers::Database.metrics_store
|
107
|
+
end
|
108
|
+
|
61
109
|
def log_subscriber
|
62
110
|
ActiveRecord::LogSubscriber
|
63
111
|
end
|
data/test/unit/memcached_test.rb
CHANGED
@@ -2,6 +2,7 @@ require_relative '../test_helper'
|
|
2
2
|
|
3
3
|
class MemcachedTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
+
skip "memcached is currently not supported on Ruby #{RUBY_VERSION} as the gem does not compile" unless RUBY_VERSION < "3.3.0"
|
5
6
|
TimeBandits.time_bandits = []
|
6
7
|
TimeBandits.add TimeBandits::TimeConsumers::Memcached
|
7
8
|
TimeBandits.reset
|
data/time_bandits.gemspec
CHANGED
@@ -23,19 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
s.add_runtime_dependency("thread_variables")
|
25
25
|
s.add_runtime_dependency("activesupport", [">= 5.2.0"])
|
26
|
-
|
27
|
-
s.
|
28
|
-
s.add_development_dependency("appraisal")
|
29
|
-
s.add_development_dependency("byebug")
|
30
|
-
s.add_development_dependency("dalli")
|
31
|
-
s.add_development_dependency("memcached", "~> 1.8.0")
|
32
|
-
s.add_development_dependency("minitest")
|
33
|
-
s.add_development_dependency("mocha")
|
34
|
-
s.add_development_dependency("mysql2")
|
35
|
-
s.add_development_dependency("rake")
|
36
|
-
s.add_development_dependency("redis")
|
37
|
-
s.add_development_dependency("sequel")
|
38
|
-
s.add_development_dependency("activerecord")
|
39
|
-
s.add_development_dependency("beetle", ">= 3.4.1")
|
26
|
+
s.add_runtime_dependency("base64")
|
27
|
+
s.add_runtime_dependency("mutex_m")
|
40
28
|
end
|
41
29
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_bandits
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Kaes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thread_variables
|
@@ -39,153 +39,13 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 5.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: base64
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
-
type: :
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: appraisal
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: byebug
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: dalli
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: memcached
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 1.8.0
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 1.8.0
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: minitest
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: mocha
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: mysql2
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: rake
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - ">="
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - ">="
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: redis
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - ">="
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - ">="
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: sequel
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - ">="
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
188
|
-
type: :development
|
48
|
+
type: :runtime
|
189
49
|
prerelease: false
|
190
50
|
version_requirements: !ruby/object:Gem::Requirement
|
191
51
|
requirements:
|
@@ -193,33 +53,19 @@ dependencies:
|
|
193
53
|
- !ruby/object:Gem::Version
|
194
54
|
version: '0'
|
195
55
|
- !ruby/object:Gem::Dependency
|
196
|
-
name:
|
56
|
+
name: mutex_m
|
197
57
|
requirement: !ruby/object:Gem::Requirement
|
198
58
|
requirements:
|
199
59
|
- - ">="
|
200
60
|
- !ruby/object:Gem::Version
|
201
61
|
version: '0'
|
202
|
-
type: :
|
62
|
+
type: :runtime
|
203
63
|
prerelease: false
|
204
64
|
version_requirements: !ruby/object:Gem::Requirement
|
205
65
|
requirements:
|
206
66
|
- - ">="
|
207
67
|
- !ruby/object:Gem::Version
|
208
68
|
version: '0'
|
209
|
-
- !ruby/object:Gem::Dependency
|
210
|
-
name: beetle
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
212
|
-
requirements:
|
213
|
-
- - ">="
|
214
|
-
- !ruby/object:Gem::Version
|
215
|
-
version: 3.4.1
|
216
|
-
type: :development
|
217
|
-
prerelease: false
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - ">="
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: 3.4.1
|
223
69
|
description: Rails Completed Line on Steroids
|
224
70
|
email:
|
225
71
|
- skaes@railsexpress.de
|
@@ -240,6 +86,9 @@ files:
|
|
240
86
|
- lib/time_bandits.rb
|
241
87
|
- lib/time_bandits/monkey_patches/action_controller.rb
|
242
88
|
- lib/time_bandits/monkey_patches/active_record.rb
|
89
|
+
- lib/time_bandits/monkey_patches/active_record/log_subscriber.rb
|
90
|
+
- lib/time_bandits/monkey_patches/active_record/railties/controller_runtime.rb
|
91
|
+
- lib/time_bandits/monkey_patches/active_record/runtime_registry.rb
|
243
92
|
- lib/time_bandits/monkey_patches/memcache-client.rb
|
244
93
|
- lib/time_bandits/monkey_patches/memcached.rb
|
245
94
|
- lib/time_bandits/monkey_patches/redis.rb
|
@@ -289,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
289
138
|
- !ruby/object:Gem::Version
|
290
139
|
version: '0'
|
291
140
|
requirements: []
|
292
|
-
rubygems_version: 3.
|
141
|
+
rubygems_version: 3.5.9
|
293
142
|
signing_key:
|
294
143
|
specification_version: 4
|
295
144
|
summary: Custom performance logging for Rails
|