activesupport 7.0.8.6 → 7.2.2.1
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 +143 -454
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +3 -1
- data/lib/active_support/backtrace_cleaner.rb +39 -7
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +49 -17
- data/lib/active_support/cache/mem_cache_store.rb +94 -128
- data/lib/active_support/cache/memory_store.rb +80 -25
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +165 -152
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +363 -291
- data/lib/active_support/callbacks.rb +118 -134
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +1 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +17 -34
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +1 -2
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +7 -10
- data/lib/active_support/core_ext/enumerable.rb +3 -75
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -119
- data/lib/active_support/core_ext/module/deprecation.rb +12 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
- data/lib/active_support/core_ext/object/json.rb +17 -7
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +4 -4
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +28 -7
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +1 -5
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -5
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +34 -177
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +36 -30
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -3
- data/lib/active_support/core_ext/time/zones.rb +4 -4
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +53 -46
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +9 -16
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +47 -25
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +3 -5
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
- data/lib/active_support/deprecation/reporting.rb +49 -27
- data/lib/active_support/deprecation.rb +39 -9
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +66 -172
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -4
- data/lib/active_support/duration.rb +13 -7
- data/lib/active_support/encrypted_configuration.rb +30 -9
- data/lib/active_support/encrypted_file.rb +9 -4
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +160 -36
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +4 -5
- data/lib/active_support/file_update_checker.rb +5 -3
- data/lib/active_support/fork_tracker.rb +4 -32
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +41 -25
- data/lib/active_support/html_safe_translation.rb +19 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +23 -11
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +9 -1
- data/lib/active_support/lazy_load_hooks.rb +6 -4
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +74 -34
- data/lib/active_support/logger.rb +22 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -32
- data/lib/active_support/message_encryptor.rb +197 -53
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +305 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +220 -89
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +111 -45
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +4 -2
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +248 -87
- data/lib/active_support/notifications/instrumenter.rb +93 -25
- data/lib/active_support/notifications.rb +29 -28
- data/lib/active_support/number_helper/number_converter.rb +16 -7
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -318
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +67 -15
- data/lib/active_support/parameter_filter.rb +84 -69
- data/lib/active_support/proxy_object.rb +8 -3
- data/lib/active_support/railtie.rb +25 -20
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +10 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -25
- data/lib/active_support/test_case.rb +156 -7
- data/lib/active_support/testing/assertions.rb +28 -12
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/deprecation.rb +20 -27
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +21 -9
- data/lib/active_support/testing/method_call_assertions.rb +7 -8
- data/lib/active_support/testing/parallelization/server.rb +3 -0
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +43 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +38 -16
- data/lib/active_support/time_with_zone.rb +12 -18
- data/lib/active_support/values/time_zone.rb +25 -14
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +12 -3
- data/lib/active_support.rb +15 -3
- metadata +142 -21
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/deprecation/instance_delegator.rb +0 -38
- data/lib/active_support/per_thread_registry.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "mutex_m"
|
4
3
|
require "concurrent/map"
|
5
4
|
require "set"
|
6
5
|
require "active_support/core_ext/object/try"
|
@@ -17,30 +16,62 @@ module ActiveSupport
|
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
19
|
+
module FanoutIteration # :nodoc:
|
20
|
+
private
|
21
|
+
def iterate_guarding_exceptions(collection)
|
22
|
+
exceptions = nil
|
23
|
+
|
24
|
+
collection.each do |s|
|
25
|
+
yield s
|
26
|
+
rescue Exception => e
|
27
|
+
exceptions ||= []
|
28
|
+
exceptions << e
|
29
|
+
end
|
30
|
+
|
31
|
+
if exceptions
|
32
|
+
exceptions = exceptions.flat_map do |exception|
|
33
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
34
|
+
end
|
35
|
+
if exceptions.size == 1
|
36
|
+
raise exceptions.first
|
37
|
+
else
|
38
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
collection
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
20
46
|
# This is a default queue implementation that ships with Notifications.
|
21
47
|
# It just pushes events to all registered log subscribers.
|
22
48
|
#
|
23
49
|
# This class is thread safe. All methods are reentrant.
|
24
50
|
class Fanout
|
25
|
-
include Mutex_m
|
26
|
-
|
27
51
|
def initialize
|
28
|
-
@
|
52
|
+
@mutex = Mutex.new
|
53
|
+
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
29
54
|
@other_subscribers = []
|
30
|
-
@
|
31
|
-
|
55
|
+
@all_listeners_for = Concurrent::Map.new
|
56
|
+
@groups_for = Concurrent::Map.new
|
57
|
+
@silenceable_groups_for = Concurrent::Map.new
|
58
|
+
end
|
59
|
+
|
60
|
+
def inspect # :nodoc:
|
61
|
+
total_patterns = @string_subscribers.size + @other_subscribers.size
|
62
|
+
"#<#{self.class} (#{total_patterns} patterns)>"
|
32
63
|
end
|
33
64
|
|
34
65
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
35
66
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
36
|
-
synchronize do
|
67
|
+
@mutex.synchronize do
|
37
68
|
case pattern
|
38
69
|
when String
|
39
70
|
@string_subscribers[pattern] << subscriber
|
40
|
-
|
71
|
+
clear_cache(pattern)
|
41
72
|
when NilClass, Regexp
|
42
73
|
@other_subscribers << subscriber
|
43
|
-
|
74
|
+
clear_cache
|
44
75
|
else
|
45
76
|
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
46
77
|
end
|
@@ -49,73 +80,236 @@ module ActiveSupport
|
|
49
80
|
end
|
50
81
|
|
51
82
|
def unsubscribe(subscriber_or_name)
|
52
|
-
synchronize do
|
83
|
+
@mutex.synchronize do
|
53
84
|
case subscriber_or_name
|
54
85
|
when String
|
55
86
|
@string_subscribers[subscriber_or_name].clear
|
56
|
-
|
87
|
+
clear_cache(subscriber_or_name)
|
57
88
|
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
58
89
|
else
|
59
90
|
pattern = subscriber_or_name.try(:pattern)
|
60
91
|
if String === pattern
|
61
92
|
@string_subscribers[pattern].delete(subscriber_or_name)
|
62
|
-
|
93
|
+
clear_cache(pattern)
|
63
94
|
else
|
64
95
|
@other_subscribers.delete(subscriber_or_name)
|
65
|
-
|
96
|
+
clear_cache
|
66
97
|
end
|
67
98
|
end
|
68
99
|
end
|
69
100
|
end
|
70
101
|
|
71
|
-
def
|
72
|
-
|
102
|
+
def clear_cache(key = nil) # :nodoc:
|
103
|
+
if key
|
104
|
+
@all_listeners_for.delete(key)
|
105
|
+
@groups_for.delete(key)
|
106
|
+
@silenceable_groups_for.delete(key)
|
107
|
+
else
|
108
|
+
@all_listeners_for.clear
|
109
|
+
@groups_for.clear
|
110
|
+
@silenceable_groups_for.clear
|
111
|
+
end
|
73
112
|
end
|
74
113
|
|
75
|
-
|
76
|
-
|
114
|
+
class BaseGroup # :nodoc:
|
115
|
+
include FanoutIteration
|
116
|
+
|
117
|
+
def initialize(listeners, name, id, payload)
|
118
|
+
@listeners = listeners
|
119
|
+
end
|
120
|
+
|
121
|
+
def each(&block)
|
122
|
+
iterate_guarding_exceptions(@listeners, &block)
|
123
|
+
end
|
77
124
|
end
|
78
125
|
|
79
|
-
|
80
|
-
|
126
|
+
class BaseTimeGroup < BaseGroup # :nodoc:
|
127
|
+
def start(name, id, payload)
|
128
|
+
@start_time = now
|
129
|
+
end
|
130
|
+
|
131
|
+
def finish(name, id, payload)
|
132
|
+
stop_time = now
|
133
|
+
each do |listener|
|
134
|
+
listener.call(name, @start_time, stop_time, id, payload)
|
135
|
+
end
|
136
|
+
end
|
81
137
|
end
|
82
138
|
|
83
|
-
|
84
|
-
|
139
|
+
class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
|
140
|
+
private
|
141
|
+
def now
|
142
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
143
|
+
end
|
85
144
|
end
|
86
145
|
|
87
|
-
|
88
|
-
|
146
|
+
class TimedGroup < BaseTimeGroup # :nodoc:
|
147
|
+
private
|
148
|
+
def now
|
149
|
+
Time.now
|
150
|
+
end
|
151
|
+
end
|
89
152
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
153
|
+
class EventedGroup < BaseGroup # :nodoc:
|
154
|
+
def start(name, id, payload)
|
155
|
+
each do |s|
|
156
|
+
s.start(name, id, payload)
|
157
|
+
end
|
95
158
|
end
|
96
159
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
160
|
+
def finish(name, id, payload)
|
161
|
+
each do |s|
|
162
|
+
s.finish(name, id, payload)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class EventObjectGroup < BaseGroup # :nodoc:
|
168
|
+
def start(name, id, payload)
|
169
|
+
@event = build_event(name, id, payload)
|
170
|
+
@event.start!
|
171
|
+
end
|
172
|
+
|
173
|
+
def finish(name, id, payload)
|
174
|
+
@event.payload = payload
|
175
|
+
@event.finish!
|
176
|
+
|
177
|
+
each do |s|
|
178
|
+
s.call(@event)
|
102
179
|
end
|
103
180
|
end
|
104
181
|
|
105
|
-
|
182
|
+
private
|
183
|
+
def build_event(name, id, payload)
|
184
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
185
|
+
end
|
106
186
|
end
|
107
187
|
|
108
|
-
def
|
188
|
+
def groups_for(name) # :nodoc:
|
189
|
+
groups = @groups_for.compute_if_absent(name) do
|
190
|
+
all_listeners_for(name).reject(&:silenceable).group_by(&:group_class).transform_values do |s|
|
191
|
+
s.map(&:delegate)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
silenceable_groups = @silenceable_groups_for.compute_if_absent(name) do
|
196
|
+
all_listeners_for(name).select(&:silenceable).group_by(&:group_class).transform_values do |s|
|
197
|
+
s.map(&:delegate)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
unless silenceable_groups.empty?
|
202
|
+
groups = groups.dup
|
203
|
+
silenceable_groups.each do |group_class, subscriptions|
|
204
|
+
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
205
|
+
unless active_subscriptions.empty?
|
206
|
+
groups[group_class] = (groups[group_class] || []) + active_subscriptions
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
groups
|
212
|
+
end
|
213
|
+
|
214
|
+
# A +Handle+ is used to record the start and finish time of event.
|
215
|
+
#
|
216
|
+
# Both #start and #finish must each be called exactly once.
|
217
|
+
#
|
218
|
+
# Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
|
219
|
+
# +Handle+ is a low-level API intended for cases where the block form can't be used.
|
220
|
+
#
|
221
|
+
# handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
|
222
|
+
# begin
|
223
|
+
# handle.start
|
224
|
+
# # work to be instrumented
|
225
|
+
# ensure
|
226
|
+
# handle.finish
|
227
|
+
# end
|
228
|
+
class Handle
|
229
|
+
include FanoutIteration
|
230
|
+
|
231
|
+
def initialize(notifier, name, id, payload) # :nodoc:
|
232
|
+
@name = name
|
233
|
+
@id = id
|
234
|
+
@payload = payload
|
235
|
+
@groups = notifier.groups_for(name).map do |group_klass, grouped_listeners|
|
236
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
237
|
+
end
|
238
|
+
@state = :initialized
|
239
|
+
end
|
240
|
+
|
241
|
+
def start
|
242
|
+
ensure_state! :initialized
|
243
|
+
@state = :started
|
244
|
+
|
245
|
+
iterate_guarding_exceptions(@groups) do |group|
|
246
|
+
group.start(@name, @id, @payload)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def finish
|
251
|
+
finish_with_values(@name, @id, @payload)
|
252
|
+
end
|
253
|
+
|
254
|
+
def finish_with_values(name, id, payload) # :nodoc:
|
255
|
+
ensure_state! :started
|
256
|
+
@state = :finished
|
257
|
+
|
258
|
+
iterate_guarding_exceptions(@groups) do |group|
|
259
|
+
group.finish(name, id, payload)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
private
|
264
|
+
def ensure_state!(expected)
|
265
|
+
if @state != expected
|
266
|
+
raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
include FanoutIteration
|
272
|
+
|
273
|
+
def build_handle(name, id, payload)
|
274
|
+
Handle.new(self, name, id, payload)
|
275
|
+
end
|
276
|
+
|
277
|
+
def start(name, id, payload)
|
278
|
+
handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
|
279
|
+
handle = build_handle(name, id, payload)
|
280
|
+
handle_stack << handle
|
281
|
+
handle.start
|
282
|
+
end
|
283
|
+
|
284
|
+
def finish(name, id, payload, listeners = nil)
|
285
|
+
handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
|
286
|
+
handle = handle_stack.pop
|
287
|
+
handle.finish_with_values(name, id, payload)
|
288
|
+
end
|
289
|
+
|
290
|
+
def publish(name, *args)
|
291
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
292
|
+
end
|
293
|
+
|
294
|
+
def publish_event(event)
|
295
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
296
|
+
end
|
297
|
+
|
298
|
+
def all_listeners_for(name)
|
109
299
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
110
|
-
@
|
300
|
+
@all_listeners_for[name] || @mutex.synchronize do
|
111
301
|
# use synchronisation when accessing @subscribers
|
112
|
-
@
|
302
|
+
@all_listeners_for[name] ||=
|
113
303
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
114
304
|
end
|
115
305
|
end
|
116
306
|
|
307
|
+
def listeners_for(name)
|
308
|
+
all_listeners_for(name).reject { |s| s.silenced?(name) }
|
309
|
+
end
|
310
|
+
|
117
311
|
def listening?(name)
|
118
|
-
|
312
|
+
all_listeners_for(name).any? { |s| !s.silenced?(name) }
|
119
313
|
end
|
120
314
|
|
121
315
|
# This is a sync queue, so there is no waiting.
|
@@ -180,15 +374,20 @@ module ActiveSupport
|
|
180
374
|
end
|
181
375
|
|
182
376
|
class Evented # :nodoc:
|
183
|
-
attr_reader :pattern
|
377
|
+
attr_reader :pattern, :delegate, :silenceable
|
184
378
|
|
185
379
|
def initialize(pattern, delegate)
|
186
380
|
@pattern = Matcher.wrap(pattern)
|
187
381
|
@delegate = delegate
|
382
|
+
@silenceable = delegate.respond_to?(:silenced?)
|
188
383
|
@can_publish = delegate.respond_to?(:publish)
|
189
384
|
@can_publish_event = delegate.respond_to?(:publish_event)
|
190
385
|
end
|
191
386
|
|
387
|
+
def group_class
|
388
|
+
EventedGroup
|
389
|
+
end
|
390
|
+
|
192
391
|
def publish(name, *args)
|
193
392
|
if @can_publish
|
194
393
|
@delegate.publish name, *args
|
@@ -203,12 +402,8 @@ module ActiveSupport
|
|
203
402
|
end
|
204
403
|
end
|
205
404
|
|
206
|
-
def
|
207
|
-
@delegate.
|
208
|
-
end
|
209
|
-
|
210
|
-
def finish(name, id, payload)
|
211
|
-
@delegate.finish name, id, payload
|
405
|
+
def silenced?(name)
|
406
|
+
@silenceable && @delegate.silenced?(name)
|
212
407
|
end
|
213
408
|
|
214
409
|
def subscribed_to?(name)
|
@@ -221,63 +416,29 @@ module ActiveSupport
|
|
221
416
|
end
|
222
417
|
|
223
418
|
class Timed < Evented # :nodoc:
|
224
|
-
def
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
def start(name, id, payload)
|
229
|
-
timestack = IsolatedExecutionState[:_timestack] ||= []
|
230
|
-
timestack.push Time.now
|
419
|
+
def group_class
|
420
|
+
TimedGroup
|
231
421
|
end
|
232
422
|
|
233
|
-
def finish(name, id, payload)
|
234
|
-
timestack = IsolatedExecutionState[:_timestack]
|
235
|
-
started = timestack.pop
|
236
|
-
@delegate.call(name, started, Time.now, id, payload)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
class MonotonicTimed < Evented # :nodoc:
|
241
423
|
def publish(name, *args)
|
242
424
|
@delegate.call name, *args
|
243
425
|
end
|
426
|
+
end
|
244
427
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
end
|
249
|
-
|
250
|
-
def finish(name, id, payload)
|
251
|
-
timestack = IsolatedExecutionState[:_timestack_monotonic]
|
252
|
-
started = timestack.pop
|
253
|
-
@delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
|
428
|
+
class MonotonicTimed < Timed # :nodoc:
|
429
|
+
def group_class
|
430
|
+
MonotonicTimedGroup
|
254
431
|
end
|
255
432
|
end
|
256
433
|
|
257
434
|
class EventObject < Evented
|
258
|
-
def
|
259
|
-
|
260
|
-
event = build_event name, id, payload
|
261
|
-
event.start!
|
262
|
-
stack.push event
|
263
|
-
end
|
264
|
-
|
265
|
-
def finish(name, id, payload)
|
266
|
-
stack = IsolatedExecutionState[:_event_stack]
|
267
|
-
event = stack.pop
|
268
|
-
event.payload = payload
|
269
|
-
event.finish!
|
270
|
-
@delegate.call event
|
435
|
+
def group_class
|
436
|
+
EventObjectGroup
|
271
437
|
end
|
272
438
|
|
273
439
|
def publish_event(event)
|
274
440
|
@delegate.call event
|
275
441
|
end
|
276
|
-
|
277
|
-
private
|
278
|
-
def build_event(name, id, payload)
|
279
|
-
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
280
|
-
end
|
281
442
|
end
|
282
443
|
end
|
283
444
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/module/delegation"
|
3
4
|
require "securerandom"
|
4
5
|
|
5
6
|
module ActiveSupport
|
@@ -9,17 +10,50 @@ module ActiveSupport
|
|
9
10
|
attr_reader :id
|
10
11
|
|
11
12
|
def initialize(notifier)
|
13
|
+
unless notifier.respond_to?(:build_handle)
|
14
|
+
notifier = LegacyHandle::Wrapper.new(notifier)
|
15
|
+
end
|
16
|
+
|
12
17
|
@id = unique_id
|
13
18
|
@notifier = notifier
|
14
19
|
end
|
15
20
|
|
21
|
+
class LegacyHandle # :nodoc:
|
22
|
+
class Wrapper # :nodoc:
|
23
|
+
def initialize(notifier)
|
24
|
+
@notifier = notifier
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_handle(name, id, payload)
|
28
|
+
LegacyHandle.new(@notifier, name, id, payload)
|
29
|
+
end
|
30
|
+
|
31
|
+
delegate :start, :finish, to: :@notifier
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(notifier, name, id, payload)
|
35
|
+
@notifier = notifier
|
36
|
+
@name = name
|
37
|
+
@id = id
|
38
|
+
@payload = payload
|
39
|
+
end
|
40
|
+
|
41
|
+
def start
|
42
|
+
@listener_state = @notifier.start @name, @id, @payload
|
43
|
+
end
|
44
|
+
|
45
|
+
def finish
|
46
|
+
@notifier.finish(@name, @id, @payload, @listener_state)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
16
50
|
# Given a block, instrument it by measuring the time taken to execute
|
17
51
|
# and publish it. Without a block, simply send a message via the
|
18
52
|
# notifier. Notice that events get sent even if an error occurs in the
|
19
53
|
# passed-in block.
|
20
54
|
def instrument(name, payload = {})
|
21
|
-
|
22
|
-
|
55
|
+
handle = build_handle(name, payload)
|
56
|
+
handle.start
|
23
57
|
begin
|
24
58
|
yield payload if block_given?
|
25
59
|
rescue Exception => e
|
@@ -27,10 +61,24 @@ module ActiveSupport
|
|
27
61
|
payload[:exception_object] = e
|
28
62
|
raise e
|
29
63
|
ensure
|
30
|
-
|
64
|
+
handle.finish
|
31
65
|
end
|
32
66
|
end
|
33
67
|
|
68
|
+
# Returns a "handle" for an event with the given +name+ and +payload+.
|
69
|
+
#
|
70
|
+
# #start and #finish must each be called exactly once on the returned object.
|
71
|
+
#
|
72
|
+
# Where possible, it's best to use #instrument, which will record the
|
73
|
+
# start and finish of the event and correctly handle any exceptions.
|
74
|
+
# +build_handle+ is a low-level API intended for cases where using
|
75
|
+
# +instrument+ isn't possible.
|
76
|
+
#
|
77
|
+
# See ActiveSupport::Notifications::Fanout::Handle.
|
78
|
+
def build_handle(name, payload)
|
79
|
+
@notifier.build_handle(name, @id, payload)
|
80
|
+
end
|
81
|
+
|
34
82
|
def new_event(name, payload = {}) # :nodoc:
|
35
83
|
Event.new(name, nil, nil, @id, payload)
|
36
84
|
end
|
@@ -56,7 +104,7 @@ module ActiveSupport
|
|
56
104
|
end
|
57
105
|
|
58
106
|
class Event
|
59
|
-
attr_reader :name, :
|
107
|
+
attr_reader :name, :transaction_id
|
60
108
|
attr_accessor :payload
|
61
109
|
|
62
110
|
def initialize(name, start, ending, transaction_id, payload)
|
@@ -65,14 +113,23 @@ module ActiveSupport
|
|
65
113
|
@time = start ? start.to_f * 1_000.0 : start
|
66
114
|
@transaction_id = transaction_id
|
67
115
|
@end = ending ? ending.to_f * 1_000.0 : ending
|
68
|
-
@children = []
|
69
116
|
@cpu_time_start = 0.0
|
70
117
|
@cpu_time_finish = 0.0
|
71
118
|
@allocation_count_start = 0
|
72
119
|
@allocation_count_finish = 0
|
120
|
+
@gc_time_start = 0
|
121
|
+
@gc_time_finish = 0
|
73
122
|
end
|
74
123
|
|
75
|
-
def
|
124
|
+
def time
|
125
|
+
@time / 1000.0 if @time
|
126
|
+
end
|
127
|
+
|
128
|
+
def end
|
129
|
+
@end / 1000.0 if @end
|
130
|
+
end
|
131
|
+
|
132
|
+
def record # :nodoc:
|
76
133
|
start!
|
77
134
|
begin
|
78
135
|
yield payload if block_given?
|
@@ -89,39 +146,48 @@ module ActiveSupport
|
|
89
146
|
def start!
|
90
147
|
@time = now
|
91
148
|
@cpu_time_start = now_cpu
|
149
|
+
@gc_time_start = now_gc
|
92
150
|
@allocation_count_start = now_allocations
|
93
151
|
end
|
94
152
|
|
95
153
|
# Record information at the time this event finishes
|
96
154
|
def finish!
|
97
155
|
@cpu_time_finish = now_cpu
|
156
|
+
@gc_time_finish = now_gc
|
98
157
|
@end = now
|
99
158
|
@allocation_count_finish = now_allocations
|
100
159
|
end
|
101
160
|
|
102
|
-
# Returns the CPU time (in milliseconds) passed
|
103
|
-
#
|
161
|
+
# Returns the CPU time (in milliseconds) passed between the call to
|
162
|
+
# #start! and the call to #finish!.
|
104
163
|
def cpu_time
|
105
164
|
@cpu_time_finish - @cpu_time_start
|
106
165
|
end
|
107
166
|
|
108
|
-
# Returns the idle time time (in milliseconds) passed
|
109
|
-
#
|
167
|
+
# Returns the idle time time (in milliseconds) passed between the call to
|
168
|
+
# #start! and the call to #finish!.
|
110
169
|
def idle_time
|
111
|
-
duration - cpu_time
|
170
|
+
diff = duration - cpu_time
|
171
|
+
diff > 0.0 ? diff : 0.0
|
112
172
|
end
|
113
173
|
|
114
|
-
# Returns the number of allocations made
|
115
|
-
# the call to
|
174
|
+
# Returns the number of allocations made between the call to #start! and
|
175
|
+
# the call to #finish!.
|
116
176
|
def allocations
|
117
177
|
@allocation_count_finish - @allocation_count_start
|
118
178
|
end
|
119
179
|
|
180
|
+
# Returns the time spent in GC (in milliseconds) between the call to #start!
|
181
|
+
# and the call to #finish!
|
182
|
+
def gc_time
|
183
|
+
(@gc_time_finish - @gc_time_start) / 1_000_000.0
|
184
|
+
end
|
185
|
+
|
120
186
|
# Returns the difference in milliseconds between when the execution of the
|
121
187
|
# event started and when it ended.
|
122
188
|
#
|
123
|
-
# ActiveSupport::Notifications.subscribe('wait') do
|
124
|
-
# @event =
|
189
|
+
# ActiveSupport::Notifications.subscribe('wait') do |event|
|
190
|
+
# @event = event
|
125
191
|
# end
|
126
192
|
#
|
127
193
|
# ActiveSupport::Notifications.instrument('wait') do
|
@@ -130,15 +196,7 @@ module ActiveSupport
|
|
130
196
|
#
|
131
197
|
# @event.duration # => 1000.138
|
132
198
|
def duration
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
def <<(event)
|
137
|
-
@children << event
|
138
|
-
end
|
139
|
-
|
140
|
-
def parent_of?(event)
|
141
|
-
@children.include? event
|
199
|
+
@end - @time
|
142
200
|
end
|
143
201
|
|
144
202
|
private
|
@@ -153,11 +211,21 @@ module ActiveSupport
|
|
153
211
|
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
154
212
|
end
|
155
213
|
rescue
|
156
|
-
def now_cpu
|
214
|
+
def now_cpu
|
157
215
|
0.0
|
158
216
|
end
|
159
217
|
end
|
160
218
|
|
219
|
+
if GC.respond_to?(:total_time)
|
220
|
+
def now_gc
|
221
|
+
GC.total_time
|
222
|
+
end
|
223
|
+
else
|
224
|
+
def now_gc
|
225
|
+
0
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
161
229
|
if GC.stat.key?(:total_allocated_objects)
|
162
230
|
def now_allocations
|
163
231
|
GC.stat(:total_allocated_objects)
|