activesupport 7.0.9 → 7.1.6
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 +1007 -326
- 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 +2 -0
- data/lib/active_support/backtrace_cleaner.rb +30 -5
- 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 +36 -9
- data/lib/active_support/cache/mem_cache_store.rb +100 -76
- data/lib/active_support/cache/memory_store.rb +75 -23
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +151 -141
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +333 -253
- data/lib/active_support/callbacks.rb +44 -21
- 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 +2 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +13 -10
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- 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_time/conversions.rb +6 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +1 -10
- data/lib/active_support/core_ext/enumerable.rb +3 -75
- data/lib/active_support/core_ext/erb/util.rb +196 -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/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/delegation.rb +81 -37
- data/lib/active_support/core_ext/module/deprecation.rb +15 -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 +2 -0
- data/lib/active_support/core_ext/numeric.rb +0 -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 +22 -12
- data/lib/active_support/core_ext/object/json.rb +10 -2
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +3 -3
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -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 +24 -12
- data/lib/active_support/core_ext/string/filters.rb +20 -14
- data/lib/active_support/core_ext/string/inflections.rb +16 -5
- data/lib/active_support/core_ext/string/output_safety.rb +38 -174
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +18 -2
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- 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/current_attributes.rb +15 -6
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +3 -5
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
- data/lib/active_support/deprecation/reporting.rb +35 -21
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +104 -132
- data/lib/active_support/duration/iso8601_serializer.rb +0 -2
- data/lib/active_support/duration.rb +2 -1
- data/lib/active_support/encrypted_configuration.rb +30 -9
- data/lib/active_support/encrypted_file.rb +8 -3
- 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 +121 -35
- data/lib/active_support/execution_wrapper.rb +4 -4
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +10 -2
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +35 -17
- data/lib/active_support/html_safe_translation.rb +16 -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 +22 -10
- 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 +85 -33
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +9 -24
- 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 +292 -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 +212 -93
- 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 +2 -0
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +245 -81
- data/lib/active_support/notifications/instrumenter.rb +71 -14
- data/lib/active_support/notifications.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +14 -0
- data/lib/active_support/parameter_filter.rb +84 -69
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +33 -21
- 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 +3 -1
- data/lib/active_support/subscriber.rb +9 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -24
- data/lib/active_support/test_case.rb +153 -6
- data/lib/active_support/testing/assertions.rb +25 -9
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +25 -25
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/testing/method_call_assertions.rb +21 -8
- 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 +39 -0
- data/lib/active_support/testing/time_helpers.rb +37 -15
- data/lib/active_support/time_with_zone.rb +4 -14
- data/lib/active_support/values/time_zone.rb +18 -7
- 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 +2 -2
- data/lib/active_support.rb +14 -3
- metadata +45 -14
- 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 -36
- 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/per_thread_registry.rb +0 -65
|
@@ -17,6 +17,33 @@ module ActiveSupport
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
module FanoutIteration # :nodoc:
|
|
21
|
+
private
|
|
22
|
+
def iterate_guarding_exceptions(collection)
|
|
23
|
+
exceptions = nil
|
|
24
|
+
|
|
25
|
+
collection.each do |s|
|
|
26
|
+
yield s
|
|
27
|
+
rescue Exception => e
|
|
28
|
+
exceptions ||= []
|
|
29
|
+
exceptions << e
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if exceptions
|
|
33
|
+
exceptions = exceptions.flat_map do |exception|
|
|
34
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
|
35
|
+
end
|
|
36
|
+
if exceptions.size == 1
|
|
37
|
+
raise exceptions.first
|
|
38
|
+
else
|
|
39
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
collection
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
20
47
|
# This is a default queue implementation that ships with Notifications.
|
|
21
48
|
# It just pushes events to all registered log subscribers.
|
|
22
49
|
#
|
|
@@ -25,22 +52,29 @@ module ActiveSupport
|
|
|
25
52
|
include Mutex_m
|
|
26
53
|
|
|
27
54
|
def initialize
|
|
28
|
-
@string_subscribers =
|
|
55
|
+
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
|
29
56
|
@other_subscribers = []
|
|
30
|
-
@
|
|
57
|
+
@all_listeners_for = Concurrent::Map.new
|
|
58
|
+
@groups_for = Concurrent::Map.new
|
|
59
|
+
@silenceable_groups_for = Concurrent::Map.new
|
|
31
60
|
super
|
|
32
61
|
end
|
|
33
62
|
|
|
63
|
+
def inspect # :nodoc:
|
|
64
|
+
total_patterns = @string_subscribers.size + @other_subscribers.size
|
|
65
|
+
"#<#{self.class} (#{total_patterns} patterns)>"
|
|
66
|
+
end
|
|
67
|
+
|
|
34
68
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
|
35
69
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
|
36
70
|
synchronize do
|
|
37
71
|
case pattern
|
|
38
72
|
when String
|
|
39
73
|
@string_subscribers[pattern] << subscriber
|
|
40
|
-
|
|
74
|
+
clear_cache(pattern)
|
|
41
75
|
when NilClass, Regexp
|
|
42
76
|
@other_subscribers << subscriber
|
|
43
|
-
|
|
77
|
+
clear_cache
|
|
44
78
|
else
|
|
45
79
|
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
|
46
80
|
end
|
|
@@ -53,69 +87,232 @@ module ActiveSupport
|
|
|
53
87
|
case subscriber_or_name
|
|
54
88
|
when String
|
|
55
89
|
@string_subscribers[subscriber_or_name].clear
|
|
56
|
-
|
|
90
|
+
clear_cache(subscriber_or_name)
|
|
57
91
|
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
|
58
92
|
else
|
|
59
93
|
pattern = subscriber_or_name.try(:pattern)
|
|
60
94
|
if String === pattern
|
|
61
95
|
@string_subscribers[pattern].delete(subscriber_or_name)
|
|
62
|
-
|
|
96
|
+
clear_cache(pattern)
|
|
63
97
|
else
|
|
64
98
|
@other_subscribers.delete(subscriber_or_name)
|
|
65
|
-
|
|
99
|
+
clear_cache
|
|
66
100
|
end
|
|
67
101
|
end
|
|
68
102
|
end
|
|
69
103
|
end
|
|
70
104
|
|
|
71
|
-
def
|
|
72
|
-
|
|
105
|
+
def clear_cache(key = nil) # :nodoc:
|
|
106
|
+
if key
|
|
107
|
+
@all_listeners_for.delete(key)
|
|
108
|
+
@groups_for.delete(key)
|
|
109
|
+
@silenceable_groups_for.delete(key)
|
|
110
|
+
else
|
|
111
|
+
@all_listeners_for.clear
|
|
112
|
+
@groups_for.clear
|
|
113
|
+
@silenceable_groups_for.clear
|
|
114
|
+
end
|
|
73
115
|
end
|
|
74
116
|
|
|
75
|
-
|
|
76
|
-
|
|
117
|
+
class BaseGroup # :nodoc:
|
|
118
|
+
include FanoutIteration
|
|
119
|
+
|
|
120
|
+
def initialize(listeners, name, id, payload)
|
|
121
|
+
@listeners = listeners
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def each(&block)
|
|
125
|
+
iterate_guarding_exceptions(@listeners, &block)
|
|
126
|
+
end
|
|
77
127
|
end
|
|
78
128
|
|
|
79
|
-
|
|
80
|
-
|
|
129
|
+
class BaseTimeGroup < BaseGroup # :nodoc:
|
|
130
|
+
def start(name, id, payload)
|
|
131
|
+
@start_time = now
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def finish(name, id, payload)
|
|
135
|
+
stop_time = now
|
|
136
|
+
each do |listener|
|
|
137
|
+
listener.call(name, @start_time, stop_time, id, payload)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
81
140
|
end
|
|
82
141
|
|
|
83
|
-
|
|
84
|
-
|
|
142
|
+
class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
|
|
143
|
+
private
|
|
144
|
+
def now
|
|
145
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
146
|
+
end
|
|
85
147
|
end
|
|
86
148
|
|
|
87
|
-
|
|
88
|
-
|
|
149
|
+
class TimedGroup < BaseTimeGroup # :nodoc:
|
|
150
|
+
private
|
|
151
|
+
def now
|
|
152
|
+
Time.now
|
|
153
|
+
end
|
|
154
|
+
end
|
|
89
155
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
156
|
+
class EventedGroup < BaseGroup # :nodoc:
|
|
157
|
+
def start(name, id, payload)
|
|
158
|
+
each do |s|
|
|
159
|
+
s.start(name, id, payload)
|
|
160
|
+
end
|
|
95
161
|
end
|
|
96
162
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else
|
|
101
|
-
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
|
163
|
+
def finish(name, id, payload)
|
|
164
|
+
each do |s|
|
|
165
|
+
s.finish(name, id, payload)
|
|
102
166
|
end
|
|
103
167
|
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
class EventObjectGroup < BaseGroup # :nodoc:
|
|
171
|
+
def start(name, id, payload)
|
|
172
|
+
@event = build_event(name, id, payload)
|
|
173
|
+
@event.start!
|
|
174
|
+
end
|
|
104
175
|
|
|
105
|
-
|
|
176
|
+
def finish(name, id, payload)
|
|
177
|
+
@event.payload = payload
|
|
178
|
+
@event.finish!
|
|
179
|
+
|
|
180
|
+
each do |s|
|
|
181
|
+
s.call(@event)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
private
|
|
186
|
+
def build_event(name, id, payload)
|
|
187
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
|
188
|
+
end
|
|
106
189
|
end
|
|
107
190
|
|
|
108
|
-
def
|
|
191
|
+
def groups_for(name) # :nodoc:
|
|
192
|
+
groups = @groups_for.compute_if_absent(name) do
|
|
193
|
+
all_listeners_for(name).reject(&:silenceable).group_by(&:group_class).transform_values do |s|
|
|
194
|
+
s.map(&:delegate)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
silenceable_groups = @silenceable_groups_for.compute_if_absent(name) do
|
|
199
|
+
all_listeners_for(name).select(&:silenceable).group_by(&:group_class).transform_values do |s|
|
|
200
|
+
s.map(&:delegate)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
unless silenceable_groups.empty?
|
|
205
|
+
groups = groups.dup
|
|
206
|
+
silenceable_groups.each do |group_class, subscriptions|
|
|
207
|
+
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
|
208
|
+
unless active_subscriptions.empty?
|
|
209
|
+
groups[group_class] = (groups[group_class] || []) + active_subscriptions
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
groups
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# A +Handle+ is used to record the start and finish time of event.
|
|
218
|
+
#
|
|
219
|
+
# Both #start and #finish must each be called exactly once.
|
|
220
|
+
#
|
|
221
|
+
# Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
|
|
222
|
+
# +Handle+ is a low-level API intended for cases where the block form can't be used.
|
|
223
|
+
#
|
|
224
|
+
# handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
|
|
225
|
+
# begin
|
|
226
|
+
# handle.start
|
|
227
|
+
# # work to be instrumented
|
|
228
|
+
# ensure
|
|
229
|
+
# handle.finish
|
|
230
|
+
# end
|
|
231
|
+
class Handle
|
|
232
|
+
include FanoutIteration
|
|
233
|
+
|
|
234
|
+
def initialize(notifier, name, id, payload) # :nodoc:
|
|
235
|
+
@name = name
|
|
236
|
+
@id = id
|
|
237
|
+
@payload = payload
|
|
238
|
+
@groups = notifier.groups_for(name).map do |group_klass, grouped_listeners|
|
|
239
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
|
240
|
+
end
|
|
241
|
+
@state = :initialized
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def start
|
|
245
|
+
ensure_state! :initialized
|
|
246
|
+
@state = :started
|
|
247
|
+
|
|
248
|
+
iterate_guarding_exceptions(@groups) do |group|
|
|
249
|
+
group.start(@name, @id, @payload)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def finish
|
|
254
|
+
finish_with_values(@name, @id, @payload)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def finish_with_values(name, id, payload) # :nodoc:
|
|
258
|
+
ensure_state! :started
|
|
259
|
+
@state = :finished
|
|
260
|
+
|
|
261
|
+
iterate_guarding_exceptions(@groups) do |group|
|
|
262
|
+
group.finish(name, id, payload)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
private
|
|
267
|
+
def ensure_state!(expected)
|
|
268
|
+
if @state != expected
|
|
269
|
+
raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
include FanoutIteration
|
|
275
|
+
|
|
276
|
+
def build_handle(name, id, payload)
|
|
277
|
+
Handle.new(self, name, id, payload)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def start(name, id, payload)
|
|
281
|
+
handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
|
|
282
|
+
handle = build_handle(name, id, payload)
|
|
283
|
+
handle_stack << handle
|
|
284
|
+
handle.start
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def finish(name, id, payload, listeners = nil)
|
|
288
|
+
handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
|
|
289
|
+
handle = handle_stack.pop
|
|
290
|
+
handle.finish_with_values(name, id, payload)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def publish(name, *args)
|
|
294
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def publish_event(event)
|
|
298
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def all_listeners_for(name)
|
|
109
302
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
|
110
|
-
@
|
|
303
|
+
@all_listeners_for[name] || synchronize do
|
|
111
304
|
# use synchronisation when accessing @subscribers
|
|
112
|
-
@
|
|
305
|
+
@all_listeners_for[name] ||=
|
|
113
306
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
|
114
307
|
end
|
|
115
308
|
end
|
|
116
309
|
|
|
310
|
+
def listeners_for(name)
|
|
311
|
+
all_listeners_for(name).reject { |s| s.silenced?(name) }
|
|
312
|
+
end
|
|
313
|
+
|
|
117
314
|
def listening?(name)
|
|
118
|
-
|
|
315
|
+
all_listeners_for(name).any? { |s| !s.silenced?(name) }
|
|
119
316
|
end
|
|
120
317
|
|
|
121
318
|
# This is a sync queue, so there is no waiting.
|
|
@@ -180,15 +377,20 @@ module ActiveSupport
|
|
|
180
377
|
end
|
|
181
378
|
|
|
182
379
|
class Evented # :nodoc:
|
|
183
|
-
attr_reader :pattern
|
|
380
|
+
attr_reader :pattern, :delegate, :silenceable
|
|
184
381
|
|
|
185
382
|
def initialize(pattern, delegate)
|
|
186
383
|
@pattern = Matcher.wrap(pattern)
|
|
187
384
|
@delegate = delegate
|
|
385
|
+
@silenceable = delegate.respond_to?(:silenced?)
|
|
188
386
|
@can_publish = delegate.respond_to?(:publish)
|
|
189
387
|
@can_publish_event = delegate.respond_to?(:publish_event)
|
|
190
388
|
end
|
|
191
389
|
|
|
390
|
+
def group_class
|
|
391
|
+
EventedGroup
|
|
392
|
+
end
|
|
393
|
+
|
|
192
394
|
def publish(name, *args)
|
|
193
395
|
if @can_publish
|
|
194
396
|
@delegate.publish name, *args
|
|
@@ -203,12 +405,8 @@ module ActiveSupport
|
|
|
203
405
|
end
|
|
204
406
|
end
|
|
205
407
|
|
|
206
|
-
def
|
|
207
|
-
@delegate.
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def finish(name, id, payload)
|
|
211
|
-
@delegate.finish name, id, payload
|
|
408
|
+
def silenced?(name)
|
|
409
|
+
@silenceable && @delegate.silenced?(name)
|
|
212
410
|
end
|
|
213
411
|
|
|
214
412
|
def subscribed_to?(name)
|
|
@@ -221,63 +419,29 @@ module ActiveSupport
|
|
|
221
419
|
end
|
|
222
420
|
|
|
223
421
|
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
|
|
422
|
+
def group_class
|
|
423
|
+
TimedGroup
|
|
231
424
|
end
|
|
232
425
|
|
|
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
426
|
def publish(name, *args)
|
|
242
427
|
@delegate.call name, *args
|
|
243
428
|
end
|
|
429
|
+
end
|
|
244
430
|
|
|
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)
|
|
431
|
+
class MonotonicTimed < Timed # :nodoc:
|
|
432
|
+
def group_class
|
|
433
|
+
MonotonicTimedGroup
|
|
254
434
|
end
|
|
255
435
|
end
|
|
256
436
|
|
|
257
437
|
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
|
|
438
|
+
def group_class
|
|
439
|
+
EventObjectGroup
|
|
271
440
|
end
|
|
272
441
|
|
|
273
442
|
def publish_event(event)
|
|
274
443
|
@delegate.call event
|
|
275
444
|
end
|
|
276
|
-
|
|
277
|
-
private
|
|
278
|
-
def build_event(name, id, payload)
|
|
279
|
-
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
|
280
|
-
end
|
|
281
445
|
end
|
|
282
446
|
end
|
|
283
447
|
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, :transaction_id
|
|
107
|
+
attr_reader :name, :transaction_id
|
|
60
108
|
attr_accessor :payload
|
|
61
109
|
|
|
62
110
|
def initialize(name, start, ending, transaction_id, payload)
|
|
@@ -65,7 +113,6 @@ 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
|
|
@@ -116,7 +163,8 @@ module ActiveSupport
|
|
|
116
163
|
# Returns the idle time time (in milliseconds) passed between the call to
|
|
117
164
|
# #start! and the call to #finish!.
|
|
118
165
|
def idle_time
|
|
119
|
-
duration - cpu_time
|
|
166
|
+
diff = duration - cpu_time
|
|
167
|
+
diff > 0.0 ? diff : 0.0
|
|
120
168
|
end
|
|
121
169
|
|
|
122
170
|
# Returns the number of allocations made between the call to #start! and
|
|
@@ -125,6 +173,23 @@ module ActiveSupport
|
|
|
125
173
|
@allocation_count_finish - @allocation_count_start
|
|
126
174
|
end
|
|
127
175
|
|
|
176
|
+
def children # :nodoc:
|
|
177
|
+
ActiveSupport.deprecator.warn <<~EOM
|
|
178
|
+
ActiveSupport::Notifications::Event#children is deprecated and will
|
|
179
|
+
be removed in Rails 7.2.
|
|
180
|
+
EOM
|
|
181
|
+
[]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def parent_of?(event) # :nodoc:
|
|
185
|
+
ActiveSupport.deprecator.warn <<~EOM
|
|
186
|
+
ActiveSupport::Notifications::Event#parent_of? is deprecated and will
|
|
187
|
+
be removed in Rails 7.2.
|
|
188
|
+
EOM
|
|
189
|
+
start = (time - event.time) * 1000
|
|
190
|
+
start <= 0 && (start + duration >= event.duration)
|
|
191
|
+
end
|
|
192
|
+
|
|
128
193
|
# Returns the difference in milliseconds between when the execution of the
|
|
129
194
|
# event started and when it ended.
|
|
130
195
|
#
|
|
@@ -141,14 +206,6 @@ module ActiveSupport
|
|
|
141
206
|
@end - @time
|
|
142
207
|
end
|
|
143
208
|
|
|
144
|
-
def <<(event)
|
|
145
|
-
@children << event
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def parent_of?(event)
|
|
149
|
-
@children.include? event
|
|
150
|
-
end
|
|
151
|
-
|
|
152
209
|
private
|
|
153
210
|
def now
|
|
154
211
|
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
|
@@ -6,7 +6,7 @@ require "active_support/notifications/fanout"
|
|
|
6
6
|
module ActiveSupport
|
|
7
7
|
# = \Notifications
|
|
8
8
|
#
|
|
9
|
-
#
|
|
9
|
+
# +ActiveSupport::Notifications+ provides an instrumentation API for
|
|
10
10
|
# Ruby.
|
|
11
11
|
#
|
|
12
12
|
# == Instrumenters
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
require "bigdecimal"
|
|
4
4
|
require "bigdecimal/util"
|
|
5
5
|
require "active_support/core_ext/big_decimal/conversions"
|
|
6
|
-
require "active_support/core_ext/object/blank"
|
|
7
6
|
require "active_support/core_ext/hash/keys"
|
|
8
7
|
require "active_support/i18n"
|
|
9
8
|
require "active_support/core_ext/class/attribute"
|
|
@@ -124,7 +123,8 @@ module ActiveSupport
|
|
|
124
123
|
|
|
125
124
|
def initialize(number, options)
|
|
126
125
|
@number = number
|
|
127
|
-
@opts
|
|
126
|
+
@opts = options.symbolize_keys
|
|
127
|
+
@options = nil
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def execute
|
|
@@ -5,7 +5,7 @@ require "active_support/number_helper/number_converter"
|
|
|
5
5
|
module ActiveSupport
|
|
6
6
|
module NumberHelper
|
|
7
7
|
class NumberToHumanSizeConverter < NumberConverter # :nodoc:
|
|
8
|
-
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
|
|
8
|
+
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb, :zb]
|
|
9
9
|
|
|
10
10
|
self.namespace = :human
|
|
11
11
|
self.validate_float = true
|
|
@@ -7,7 +7,7 @@ YAML.add_builtin_type("omap") do |type, val|
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
module ActiveSupport
|
|
10
|
-
# DEPRECATED:
|
|
10
|
+
# DEPRECATED: +ActiveSupport::OrderedHash+ implements a hash that preserves
|
|
11
11
|
# insertion order.
|
|
12
12
|
#
|
|
13
13
|
# oh = ActiveSupport::OrderedHash.new
|
|
@@ -17,9 +17,9 @@ module ActiveSupport
|
|
|
17
17
|
#
|
|
18
18
|
# Also, maps the +omap+ feature for YAML files
|
|
19
19
|
# (See https://yaml.org/type/omap.html) to support ordered items
|
|
20
|
-
# when loading from
|
|
20
|
+
# when loading from YAML.
|
|
21
21
|
#
|
|
22
|
-
#
|
|
22
|
+
# +ActiveSupport::OrderedHash+ is namespaced to prevent conflicts
|
|
23
23
|
# with other implementations.
|
|
24
24
|
class OrderedHash < ::Hash # :nodoc:
|
|
25
25
|
def to_yaml_type
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require "active_support/core_ext/object/blank"
|
|
4
4
|
|
|
5
5
|
module ActiveSupport
|
|
6
|
+
# = Ordered Options
|
|
7
|
+
#
|
|
6
8
|
# +OrderedOptions+ inherits from +Hash+ and provides dynamic accessor methods.
|
|
7
9
|
#
|
|
8
10
|
# With a +Hash+, key-value pairs are typically managed like this:
|
|
@@ -40,6 +42,10 @@ module ActiveSupport
|
|
|
40
42
|
super(key.to_sym)
|
|
41
43
|
end
|
|
42
44
|
|
|
45
|
+
def dig(key, *identifiers)
|
|
46
|
+
super(key.to_sym, *identifiers)
|
|
47
|
+
end
|
|
48
|
+
|
|
43
49
|
def method_missing(name, *args)
|
|
44
50
|
name_string = +name.to_s
|
|
45
51
|
if name_string.chomp!("=")
|
|
@@ -68,6 +74,8 @@ module ActiveSupport
|
|
|
68
74
|
end
|
|
69
75
|
end
|
|
70
76
|
|
|
77
|
+
# = Inheritable Options
|
|
78
|
+
#
|
|
71
79
|
# +InheritableOptions+ provides a constructor to build an OrderedOptions
|
|
72
80
|
# hash inherited from another hash.
|
|
73
81
|
#
|
|
@@ -76,6 +84,12 @@ module ActiveSupport
|
|
|
76
84
|
# h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
|
|
77
85
|
# h.girl # => 'Mary'
|
|
78
86
|
# h.boy # => 'John'
|
|
87
|
+
#
|
|
88
|
+
# If the existing hash has string keys, call Hash#symbolize_keys on it.
|
|
89
|
+
#
|
|
90
|
+
# h = ActiveSupport::InheritableOptions.new({ 'girl' => 'Mary', 'boy' => 'John' }.symbolize_keys)
|
|
91
|
+
# h.girl # => 'Mary'
|
|
92
|
+
# h.boy # => 'John'
|
|
79
93
|
class InheritableOptions < OrderedOptions
|
|
80
94
|
def initialize(parent = nil)
|
|
81
95
|
if parent.kind_of?(OrderedOptions)
|