activesupport 7.0.10 → 7.1.0.beta1
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 +703 -361
- 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 +25 -5
- data/lib/active_support/benchmarkable.rb +1 -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 +128 -0
- data/lib/active_support/cache/file_store.rb +37 -10
- data/lib/active_support/cache/mem_cache_store.rb +84 -68
- data/lib/active_support/cache/memory_store.rb +76 -26
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +126 -131
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +20 -8
- data/lib/active_support/cache.rb +304 -246
- data/lib/active_support/callbacks.rb +38 -18
- 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/attribute.rb +1 -0
- data/lib/active_support/core_ext/class/subclasses.rb +13 -10
- data/lib/active_support/core_ext/date/conversions.rb +1 -0
- 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/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 +40 -11
- 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/duplicable.rb +15 -24
- 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 +14 -8
- data/lib/active_support/core_ext/object/with.rb +44 -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 +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 +12 -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/indent.rb +1 -1
- 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/dependencies/autoload.rb +17 -12
- data/lib/active_support/deprecation/behaviors.rb +55 -34
- 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 +40 -29
- 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 +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +35 -17
- 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 +78 -33
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_thread_safe_level.rb +9 -22
- data/lib/active_support/message_encryptor.rb +197 -53
- data/lib/active_support/message_encryptors.rb +140 -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 +134 -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 +239 -81
- data/lib/active_support/notifications/instrumenter.rb +79 -30
- data/lib/active_support/notifications.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +5 -14
- 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 +318 -379
- 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 +49 -0
- data/lib/active_support/tagged_logging.rb +60 -24
- data/lib/active_support/test_case.rb +153 -6
- data/lib/active_support/testing/assertions.rb +26 -10
- 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 +108 -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/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +38 -0
- data/lib/active_support/testing/time_helpers.rb +32 -14
- data/lib/active_support/time_with_zone.rb +4 -14
- data/lib/active_support/values/time_zone.rb +9 -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 +13 -3
- metadata +48 -58
- 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,29 @@ module ActiveSupport
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
module FanoutIteration # :nodoc:
|
|
21
|
+
def iterate_guarding_exceptions(listeners)
|
|
22
|
+
exceptions = nil
|
|
23
|
+
|
|
24
|
+
listeners.each do |s|
|
|
25
|
+
yield s
|
|
26
|
+
rescue Exception => e
|
|
27
|
+
exceptions ||= []
|
|
28
|
+
exceptions << e
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if exceptions
|
|
32
|
+
if exceptions.size == 1
|
|
33
|
+
raise exceptions.first
|
|
34
|
+
else
|
|
35
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
listeners
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
20
43
|
# This is a default queue implementation that ships with Notifications.
|
|
21
44
|
# It just pushes events to all registered log subscribers.
|
|
22
45
|
#
|
|
@@ -25,22 +48,29 @@ module ActiveSupport
|
|
|
25
48
|
include Mutex_m
|
|
26
49
|
|
|
27
50
|
def initialize
|
|
28
|
-
@string_subscribers =
|
|
51
|
+
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
|
29
52
|
@other_subscribers = []
|
|
30
|
-
@
|
|
53
|
+
@all_listeners_for = Concurrent::Map.new
|
|
54
|
+
@groups_for = Concurrent::Map.new
|
|
55
|
+
@silenceable_groups_for = Concurrent::Map.new
|
|
31
56
|
super
|
|
32
57
|
end
|
|
33
58
|
|
|
59
|
+
def inspect # :nodoc:
|
|
60
|
+
total_patterns = @string_subscribers.size + @other_subscribers.size
|
|
61
|
+
"#<#{self.class} (#{total_patterns} patterns)>"
|
|
62
|
+
end
|
|
63
|
+
|
|
34
64
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
|
35
65
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
|
36
66
|
synchronize do
|
|
37
67
|
case pattern
|
|
38
68
|
when String
|
|
39
69
|
@string_subscribers[pattern] << subscriber
|
|
40
|
-
|
|
70
|
+
clear_cache(pattern)
|
|
41
71
|
when NilClass, Regexp
|
|
42
72
|
@other_subscribers << subscriber
|
|
43
|
-
|
|
73
|
+
clear_cache
|
|
44
74
|
else
|
|
45
75
|
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
|
46
76
|
end
|
|
@@ -53,69 +83,230 @@ module ActiveSupport
|
|
|
53
83
|
case subscriber_or_name
|
|
54
84
|
when String
|
|
55
85
|
@string_subscribers[subscriber_or_name].clear
|
|
56
|
-
|
|
86
|
+
clear_cache(subscriber_or_name)
|
|
57
87
|
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
|
58
88
|
else
|
|
59
89
|
pattern = subscriber_or_name.try(:pattern)
|
|
60
90
|
if String === pattern
|
|
61
91
|
@string_subscribers[pattern].delete(subscriber_or_name)
|
|
62
|
-
|
|
92
|
+
clear_cache(pattern)
|
|
63
93
|
else
|
|
64
94
|
@other_subscribers.delete(subscriber_or_name)
|
|
65
|
-
|
|
95
|
+
clear_cache
|
|
66
96
|
end
|
|
67
97
|
end
|
|
68
98
|
end
|
|
69
99
|
end
|
|
70
100
|
|
|
71
|
-
def
|
|
72
|
-
|
|
101
|
+
def clear_cache(key = nil) # :nodoc:
|
|
102
|
+
if key
|
|
103
|
+
@all_listeners_for.delete(key)
|
|
104
|
+
@groups_for.delete(key)
|
|
105
|
+
@silenceable_groups_for.delete(key)
|
|
106
|
+
else
|
|
107
|
+
@all_listeners_for.clear
|
|
108
|
+
@groups_for.clear
|
|
109
|
+
@silenceable_groups_for.clear
|
|
110
|
+
end
|
|
73
111
|
end
|
|
74
112
|
|
|
75
|
-
|
|
76
|
-
|
|
113
|
+
class BaseGroup # :nodoc:
|
|
114
|
+
include FanoutIteration
|
|
115
|
+
|
|
116
|
+
def initialize(listeners, name, id, payload)
|
|
117
|
+
@listeners = listeners
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def each(&block)
|
|
121
|
+
iterate_guarding_exceptions(@listeners, &block)
|
|
122
|
+
end
|
|
77
123
|
end
|
|
78
124
|
|
|
79
|
-
|
|
80
|
-
|
|
125
|
+
class BaseTimeGroup < BaseGroup # :nodoc:
|
|
126
|
+
def start(name, id, payload)
|
|
127
|
+
@start_time = now
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def finish(name, id, payload)
|
|
131
|
+
stop_time = now
|
|
132
|
+
each do |listener|
|
|
133
|
+
listener.call(name, @start_time, stop_time, id, payload)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
81
136
|
end
|
|
82
137
|
|
|
83
|
-
|
|
84
|
-
|
|
138
|
+
class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
|
|
139
|
+
private
|
|
140
|
+
def now
|
|
141
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
142
|
+
end
|
|
85
143
|
end
|
|
86
144
|
|
|
87
|
-
|
|
88
|
-
|
|
145
|
+
class TimedGroup < BaseTimeGroup # :nodoc:
|
|
146
|
+
private
|
|
147
|
+
def now
|
|
148
|
+
Time.now
|
|
149
|
+
end
|
|
150
|
+
end
|
|
89
151
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
152
|
+
class EventedGroup < BaseGroup # :nodoc:
|
|
153
|
+
def start(name, id, payload)
|
|
154
|
+
each do |s|
|
|
155
|
+
s.start(name, id, payload)
|
|
156
|
+
end
|
|
95
157
|
end
|
|
96
158
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else
|
|
101
|
-
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
|
159
|
+
def finish(name, id, payload)
|
|
160
|
+
each do |s|
|
|
161
|
+
s.finish(name, id, payload)
|
|
102
162
|
end
|
|
103
163
|
end
|
|
164
|
+
end
|
|
104
165
|
|
|
105
|
-
|
|
166
|
+
class EventObjectGroup < BaseGroup # :nodoc:
|
|
167
|
+
def start(name, id, payload)
|
|
168
|
+
@event = build_event(name, id, payload)
|
|
169
|
+
@event.start!
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def finish(name, id, payload)
|
|
173
|
+
@event.payload = payload
|
|
174
|
+
@event.finish!
|
|
175
|
+
|
|
176
|
+
each do |s|
|
|
177
|
+
s.call(@event)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private
|
|
182
|
+
def build_event(name, id, payload)
|
|
183
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
|
184
|
+
end
|
|
106
185
|
end
|
|
107
186
|
|
|
108
|
-
def
|
|
187
|
+
def groups_for(name) # :nodoc:
|
|
188
|
+
groups = @groups_for.compute_if_absent(name) do
|
|
189
|
+
all_listeners_for(name).reject(&:silenceable).group_by(&:group_class).transform_values do |s|
|
|
190
|
+
s.map(&:delegate)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
silenceable_groups = @silenceable_groups_for.compute_if_absent(name) do
|
|
195
|
+
all_listeners_for(name).select(&:silenceable).group_by(&:group_class).transform_values do |s|
|
|
196
|
+
s.map(&:delegate)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
unless silenceable_groups.empty?
|
|
201
|
+
groups = groups.dup
|
|
202
|
+
silenceable_groups.each do |group_class, subscriptions|
|
|
203
|
+
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
|
204
|
+
unless active_subscriptions.empty?
|
|
205
|
+
groups[group_class] = (groups[group_class] || []) + active_subscriptions
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
groups
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# A +Handle+ is used to record the start and finish time of event.
|
|
214
|
+
#
|
|
215
|
+
# Both #start and #finish must each be called exactly once.
|
|
216
|
+
#
|
|
217
|
+
# Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
|
|
218
|
+
# +Handle+ is a low-level API intended for cases where the block form can't be used.
|
|
219
|
+
#
|
|
220
|
+
# handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
|
|
221
|
+
# begin
|
|
222
|
+
# handle.start
|
|
223
|
+
# # work to be instrumented
|
|
224
|
+
# ensure
|
|
225
|
+
# handle.finish
|
|
226
|
+
# end
|
|
227
|
+
class Handle
|
|
228
|
+
def initialize(notifier, name, id, payload) # :nodoc:
|
|
229
|
+
@name = name
|
|
230
|
+
@id = id
|
|
231
|
+
@payload = payload
|
|
232
|
+
@groups = notifier.groups_for(name).map do |group_klass, grouped_listeners|
|
|
233
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
|
234
|
+
end
|
|
235
|
+
@state = :initialized
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def start
|
|
239
|
+
ensure_state! :initialized
|
|
240
|
+
@state = :started
|
|
241
|
+
|
|
242
|
+
@groups.each do |group|
|
|
243
|
+
group.start(@name, @id, @payload)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def finish
|
|
248
|
+
finish_with_values(@name, @id, @payload)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def finish_with_values(name, id, payload) # :nodoc:
|
|
252
|
+
ensure_state! :started
|
|
253
|
+
@state = :finished
|
|
254
|
+
|
|
255
|
+
@groups.each do |group|
|
|
256
|
+
group.finish(name, id, payload)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
private
|
|
261
|
+
def ensure_state!(expected)
|
|
262
|
+
if @state != expected
|
|
263
|
+
raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
include FanoutIteration
|
|
269
|
+
|
|
270
|
+
def build_handle(name, id, payload)
|
|
271
|
+
Handle.new(self, name, id, payload)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def start(name, id, payload)
|
|
275
|
+
handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
|
|
276
|
+
handle = build_handle(name, id, payload)
|
|
277
|
+
handle_stack << handle
|
|
278
|
+
handle.start
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def finish(name, id, payload, listeners = nil)
|
|
282
|
+
handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
|
|
283
|
+
handle = handle_stack.pop
|
|
284
|
+
handle.finish_with_values(name, id, payload)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def publish(name, *args)
|
|
288
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def publish_event(event)
|
|
292
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def all_listeners_for(name)
|
|
109
296
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
|
110
|
-
@
|
|
297
|
+
@all_listeners_for[name] || synchronize do
|
|
111
298
|
# use synchronisation when accessing @subscribers
|
|
112
|
-
@
|
|
299
|
+
@all_listeners_for[name] ||=
|
|
113
300
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
|
114
301
|
end
|
|
115
302
|
end
|
|
116
303
|
|
|
304
|
+
def listeners_for(name)
|
|
305
|
+
all_listeners_for(name).reject { |s| s.silenced?(name) }
|
|
306
|
+
end
|
|
307
|
+
|
|
117
308
|
def listening?(name)
|
|
118
|
-
|
|
309
|
+
all_listeners_for(name).any? { |s| !s.silenced?(name) }
|
|
119
310
|
end
|
|
120
311
|
|
|
121
312
|
# This is a sync queue, so there is no waiting.
|
|
@@ -180,15 +371,20 @@ module ActiveSupport
|
|
|
180
371
|
end
|
|
181
372
|
|
|
182
373
|
class Evented # :nodoc:
|
|
183
|
-
attr_reader :pattern
|
|
374
|
+
attr_reader :pattern, :delegate, :silenceable
|
|
184
375
|
|
|
185
376
|
def initialize(pattern, delegate)
|
|
186
377
|
@pattern = Matcher.wrap(pattern)
|
|
187
378
|
@delegate = delegate
|
|
379
|
+
@silenceable = delegate.respond_to?(:silenced?)
|
|
188
380
|
@can_publish = delegate.respond_to?(:publish)
|
|
189
381
|
@can_publish_event = delegate.respond_to?(:publish_event)
|
|
190
382
|
end
|
|
191
383
|
|
|
384
|
+
def group_class
|
|
385
|
+
EventedGroup
|
|
386
|
+
end
|
|
387
|
+
|
|
192
388
|
def publish(name, *args)
|
|
193
389
|
if @can_publish
|
|
194
390
|
@delegate.publish name, *args
|
|
@@ -203,12 +399,8 @@ module ActiveSupport
|
|
|
203
399
|
end
|
|
204
400
|
end
|
|
205
401
|
|
|
206
|
-
def
|
|
207
|
-
@delegate.
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def finish(name, id, payload)
|
|
211
|
-
@delegate.finish name, id, payload
|
|
402
|
+
def silenced?(name)
|
|
403
|
+
@silenceable && @delegate.silenced?(name)
|
|
212
404
|
end
|
|
213
405
|
|
|
214
406
|
def subscribed_to?(name)
|
|
@@ -221,63 +413,29 @@ module ActiveSupport
|
|
|
221
413
|
end
|
|
222
414
|
|
|
223
415
|
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
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def finish(name, id, payload)
|
|
234
|
-
timestack = IsolatedExecutionState[:_timestack]
|
|
235
|
-
started = timestack.pop
|
|
236
|
-
@delegate.call(name, started, Time.now, id, payload)
|
|
416
|
+
def group_class
|
|
417
|
+
TimedGroup
|
|
237
418
|
end
|
|
238
|
-
end
|
|
239
419
|
|
|
240
|
-
class MonotonicTimed < Evented # :nodoc:
|
|
241
420
|
def publish(name, *args)
|
|
242
421
|
@delegate.call name, *args
|
|
243
422
|
end
|
|
423
|
+
end
|
|
244
424
|
|
|
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)
|
|
425
|
+
class MonotonicTimed < Timed # :nodoc:
|
|
426
|
+
def group_class
|
|
427
|
+
MonotonicTimedGroup
|
|
254
428
|
end
|
|
255
429
|
end
|
|
256
430
|
|
|
257
431
|
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
|
|
432
|
+
def group_class
|
|
433
|
+
EventObjectGroup
|
|
271
434
|
end
|
|
272
435
|
|
|
273
436
|
def publish_event(event)
|
|
274
437
|
@delegate.call event
|
|
275
438
|
end
|
|
276
|
-
|
|
277
|
-
private
|
|
278
|
-
def build_event(name, id, payload)
|
|
279
|
-
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
|
280
|
-
end
|
|
281
439
|
end
|
|
282
440
|
end
|
|
283
441
|
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, :time, :end, :transaction_id
|
|
60
108
|
attr_accessor :payload
|
|
61
109
|
|
|
62
110
|
def initialize(name, start, ending, transaction_id, payload)
|
|
@@ -65,22 +113,13 @@ 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
|
|
73
120
|
end
|
|
74
121
|
|
|
75
|
-
def
|
|
76
|
-
@time / 1000.0 if @time
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def end
|
|
80
|
-
@end / 1000.0 if @end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def record # :nodoc:
|
|
122
|
+
def record
|
|
84
123
|
start!
|
|
85
124
|
begin
|
|
86
125
|
yield payload if block_given?
|
|
@@ -107,24 +146,42 @@ module ActiveSupport
|
|
|
107
146
|
@allocation_count_finish = now_allocations
|
|
108
147
|
end
|
|
109
148
|
|
|
110
|
-
# Returns the CPU time (in milliseconds) passed
|
|
111
|
-
#
|
|
149
|
+
# Returns the CPU time (in milliseconds) passed since the call to
|
|
150
|
+
# +start!+ and the call to +finish!+
|
|
112
151
|
def cpu_time
|
|
113
152
|
@cpu_time_finish - @cpu_time_start
|
|
114
153
|
end
|
|
115
154
|
|
|
116
|
-
# Returns the idle time time (in milliseconds) passed
|
|
117
|
-
#
|
|
155
|
+
# Returns the idle time time (in milliseconds) passed since the call to
|
|
156
|
+
# +start!+ and the call to +finish!+
|
|
118
157
|
def idle_time
|
|
119
|
-
duration - cpu_time
|
|
158
|
+
diff = duration - cpu_time
|
|
159
|
+
diff > 0.0 ? diff : 0.0
|
|
120
160
|
end
|
|
121
161
|
|
|
122
|
-
# Returns the number of allocations made
|
|
123
|
-
# the call to
|
|
162
|
+
# Returns the number of allocations made since the call to +start!+ and
|
|
163
|
+
# the call to +finish!+
|
|
124
164
|
def allocations
|
|
125
165
|
@allocation_count_finish - @allocation_count_start
|
|
126
166
|
end
|
|
127
167
|
|
|
168
|
+
def children # :nodoc:
|
|
169
|
+
ActiveSupport.deprecator.warn <<~EOM
|
|
170
|
+
ActiveSupport::Notifications::Event#children is deprecated and will
|
|
171
|
+
be removed in Rails 7.2.
|
|
172
|
+
EOM
|
|
173
|
+
[]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def parent_of?(event) # :nodoc:
|
|
177
|
+
ActiveSupport.deprecator.warn <<~EOM
|
|
178
|
+
ActiveSupport::Notifications::Event#parent_of? is deprecated and will
|
|
179
|
+
be removed in Rails 7.2.
|
|
180
|
+
EOM
|
|
181
|
+
start = (time - event.time) * 1000
|
|
182
|
+
start <= 0 && (start + duration >= event.duration)
|
|
183
|
+
end
|
|
184
|
+
|
|
128
185
|
# Returns the difference in milliseconds between when the execution of the
|
|
129
186
|
# event started and when it ended.
|
|
130
187
|
#
|
|
@@ -138,15 +195,7 @@ module ActiveSupport
|
|
|
138
195
|
#
|
|
139
196
|
# @event.duration # => 1000.138
|
|
140
197
|
def duration
|
|
141
|
-
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def <<(event)
|
|
145
|
-
@children << event
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def parent_of?(event)
|
|
149
|
-
@children.include? event
|
|
198
|
+
self.end - time
|
|
150
199
|
end
|
|
151
200
|
|
|
152
201
|
private
|
|
@@ -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
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "bigdecimal"
|
|
4
|
-
require "bigdecimal/util"
|
|
5
3
|
require "active_support/core_ext/big_decimal/conversions"
|
|
6
|
-
require "active_support/core_ext/object/blank"
|
|
7
4
|
require "active_support/core_ext/hash/keys"
|
|
8
5
|
require "active_support/i18n"
|
|
9
6
|
require "active_support/core_ext/class/attribute"
|
|
@@ -124,13 +121,14 @@ module ActiveSupport
|
|
|
124
121
|
|
|
125
122
|
def initialize(number, options)
|
|
126
123
|
@number = number
|
|
127
|
-
@opts
|
|
124
|
+
@opts = options.symbolize_keys
|
|
125
|
+
@options = nil
|
|
128
126
|
end
|
|
129
127
|
|
|
130
128
|
def execute
|
|
131
129
|
if !number
|
|
132
130
|
nil
|
|
133
|
-
elsif validate_float? && !
|
|
131
|
+
elsif validate_float? && !valid_float?
|
|
134
132
|
number
|
|
135
133
|
else
|
|
136
134
|
convert
|
|
@@ -175,15 +173,8 @@ module ActiveSupport
|
|
|
175
173
|
key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
|
|
176
174
|
end
|
|
177
175
|
|
|
178
|
-
def
|
|
179
|
-
|
|
180
|
-
when Float, Rational
|
|
181
|
-
number.to_d(0)
|
|
182
|
-
when String
|
|
183
|
-
BigDecimal(number, exception: false)
|
|
184
|
-
else
|
|
185
|
-
number.to_d rescue nil
|
|
186
|
-
end
|
|
176
|
+
def valid_float?
|
|
177
|
+
Float(number, exception: false)
|
|
187
178
|
end
|
|
188
179
|
end
|
|
189
180
|
end
|
|
@@ -10,13 +10,13 @@ module ActiveSupport
|
|
|
10
10
|
def convert
|
|
11
11
|
format = options[:format]
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
if
|
|
15
|
-
if
|
|
16
|
-
|
|
17
|
-
format = options[:negative_format] if (
|
|
13
|
+
number_f = valid_float?
|
|
14
|
+
if number_f
|
|
15
|
+
if number_f.negative?
|
|
16
|
+
number_f = number_f.abs
|
|
17
|
+
format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
|
|
18
18
|
end
|
|
19
|
-
number_s = NumberToRoundedConverter.convert(
|
|
19
|
+
number_s = NumberToRoundedConverter.convert(number_f, options)
|
|
20
20
|
else
|
|
21
21
|
number_s = number.to_s.strip
|
|
22
22
|
format = options[:negative_format] if number_s.sub!(/^-/, "")
|