activesupport 5.1.7 → 7.0.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +259 -585
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +2 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +33 -5
- data/lib/active_support/benchmarkable.rb +5 -3
- data/lib/active_support/builder.rb +2 -0
- data/lib/active_support/cache/file_store.rb +50 -43
- data/lib/active_support/cache/mem_cache_store.rb +194 -67
- data/lib/active_support/cache/memory_store.rb +70 -34
- data/lib/active_support/cache/null_store.rb +18 -3
- data/lib/active_support/cache/redis_cache_store.rb +474 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -50
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
- data/lib/active_support/cache.rb +556 -220
- data/lib/active_support/callbacks.rb +264 -159
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +81 -8
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
- data/lib/active_support/concurrency/share_lock.rb +4 -3
- data/lib/active_support/configurable.rb +17 -16
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +18 -8
- data/lib/active_support/core_ext/array/conversions.rb +20 -17
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +8 -6
- data/lib/active_support/core_ext/array/inquiry.rb +4 -2
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +4 -1
- data/lib/active_support/core_ext/benchmark.rb +4 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
- data/lib/active_support/core_ext/big_decimal.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +50 -47
- data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +10 -24
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/date/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date/blank.rb +3 -1
- data/lib/active_support/core_ext/date/calculations.rb +17 -14
- data/lib/active_support/core_ext/date/conversions.rb +24 -22
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +2 -0
- data/lib/active_support/core_ext/date.rb +3 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date_time/blank.rb +3 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
- data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +3 -0
- data/lib/active_support/core_ext/digest/uuid.rb +42 -14
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +244 -72
- data/lib/active_support/core_ext/file/atomic.rb +6 -2
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +7 -6
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -31
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +2 -0
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +7 -14
- data/lib/active_support/core_ext/integer.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
- data/lib/active_support/core_ext/kernel.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +3 -8
- data/lib/active_support/core_ext/module/aliasing.rb +2 -0
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
- data/lib/active_support/core_ext/module/concerning.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +97 -58
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +18 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +3 -1
- data/lib/active_support/core_ext/name_error.rb +30 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric/time.rb +7 -15
- data/lib/active_support/core_ext/numeric.rb +3 -1
- data/lib/active_support/core_ext/object/acts_like.rb +41 -6
- data/lib/active_support/core_ext/object/blank.rb +15 -5
- data/lib/active_support/core_ext/object/conversions.rb +2 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
- data/lib/active_support/core_ext/object/duplicable.rb +16 -110
- data/lib/active_support/core_ext/object/inclusion.rb +2 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +51 -26
- data/lib/active_support/core_ext/object/to_param.rb +2 -0
- data/lib/active_support/core_ext/object/to_query.rb +4 -2
- data/lib/active_support/core_ext/object/try.rb +26 -14
- data/lib/active_support/core_ext/object/with_options.rb +24 -3
- data/lib/active_support/core_ext/object.rb +2 -0
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +6 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +3 -1
- data/lib/active_support/core_ext/range.rb +4 -1
- data/lib/active_support/core_ext/regexp.rb +10 -5
- data/lib/active_support/core_ext/securerandom.rb +25 -3
- data/lib/active_support/core_ext/string/access.rb +7 -16
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +5 -2
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +44 -1
- data/lib/active_support/core_ext/string/indent.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +69 -16
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +9 -4
- data/lib/active_support/core_ext/string/output_safety.rb +135 -27
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +2 -0
- data/lib/active_support/core_ext/string.rb +2 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/time/calculations.rb +81 -24
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +17 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +12 -25
- data/lib/active_support/core_ext/time.rb +3 -0
- data/lib/active_support/core_ext/uri.rb +4 -23
- data/lib/active_support/core_ext.rb +4 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +226 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +12 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +59 -715
- data/lib/active_support/deprecation/behaviors.rb +48 -13
- data/lib/active_support/deprecation/constant_accessor.rb +4 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +2 -1
- data/lib/active_support/deprecation/method_wrappers.rb +29 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
- data/lib/active_support/deprecation/reporting.rb +54 -9
- data/lib/active_support/deprecation.rb +10 -3
- data/lib/active_support/descendants_tracker.rb +192 -34
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +9 -9
- data/lib/active_support/duration/iso8601_serializer.rb +29 -15
- data/lib/active_support/duration.rb +158 -72
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +129 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +87 -122
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +46 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +2 -0
- data/lib/active_support/file_update_checker.rb +2 -1
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +7 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +126 -42
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +5 -1
- data/lib/active_support/i18n_railtie.rb +19 -14
- data/lib/active_support/inflections.rb +2 -0
- data/lib/active_support/inflector/inflections.rb +41 -14
- data/lib/active_support/inflector/methods.rb +73 -87
- data/lib/active_support/inflector/transliterate.rb +56 -18
- data/lib/active_support/inflector.rb +2 -0
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +27 -26
- data/lib/active_support/json/encoding.rb +16 -6
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/key_generator.rb +25 -38
- data/lib/active_support/lazy_load_hooks.rb +35 -6
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +4 -2
- data/lib/active_support/log_subscriber.rb +54 -13
- data/lib/active_support/logger.rb +4 -17
- data/lib/active_support/logger_silence.rb +13 -20
- data/lib/active_support/logger_thread_safe_level.rb +48 -10
- data/lib/active_support/message_encryptor.rb +111 -37
- data/lib/active_support/message_verifier.rb +124 -21
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +19 -76
- data/lib/active_support/multibyte/unicode.rb +9 -331
- data/lib/active_support/multibyte.rb +3 -1
- data/lib/active_support/notifications/fanout.rb +165 -37
- data/lib/active_support/notifications/instrumenter.rb +92 -11
- data/lib/active_support/notifications.rb +96 -30
- data/lib/active_support/number_helper/number_converter.rb +8 -9
- data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
- data/lib/active_support/number_helper/rounding_helper.rb +16 -34
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +19 -6
- data/lib/active_support/ordered_hash.rb +4 -2
- data/lib/active_support/ordered_options.rb +18 -6
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +8 -1
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +3 -10
- data/lib/active_support/railtie.rb +112 -11
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +19 -18
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +81 -42
- data/lib/active_support/tagged_logging.rb +45 -9
- data/lib/active_support/test_case.rb +86 -2
- data/lib/active_support/testing/assertions.rb +89 -21
- data/lib/active_support/testing/autorun.rb +2 -0
- data/lib/active_support/testing/constant_lookup.rb +2 -0
- data/lib/active_support/testing/declarative.rb +2 -0
- data/lib/active_support/testing/deprecation.rb +54 -2
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +6 -4
- data/lib/active_support/testing/method_call_assertions.rb +34 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/setup_and_teardown.rb +12 -7
- data/lib/active_support/testing/stream.rb +6 -7
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +91 -15
- data/lib/active_support/time.rb +2 -0
- data/lib/active_support/time_with_zone.rb +168 -56
- data/lib/active_support/values/time_zone.rb +85 -37
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +6 -5
- data/lib/active_support/xml_mini/libxml.rb +9 -7
- data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
- data/lib/active_support/xml_mini/nokogiri.rb +8 -6
- data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
- data/lib/active_support/xml_mini/rexml.rb +13 -4
- data/lib/active_support/xml_mini.rb +10 -15
- data/lib/active_support.rb +30 -9
- metadata +76 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/marshal.rb +0 -22
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,8 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "mutex_m"
|
2
4
|
require "concurrent/map"
|
5
|
+
require "set"
|
6
|
+
require "active_support/core_ext/object/try"
|
3
7
|
|
4
8
|
module ActiveSupport
|
5
9
|
module Notifications
|
10
|
+
class InstrumentationSubscriberError < RuntimeError
|
11
|
+
attr_reader :exceptions
|
12
|
+
|
13
|
+
def initialize(exceptions)
|
14
|
+
@exceptions = exceptions
|
15
|
+
exception_class_names = exceptions.map { |e| e.class.name }
|
16
|
+
super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
6
20
|
# This is a default queue implementation that ships with Notifications.
|
7
21
|
# It just pushes events to all registered log subscribers.
|
8
22
|
#
|
@@ -11,16 +25,25 @@ module ActiveSupport
|
|
11
25
|
include Mutex_m
|
12
26
|
|
13
27
|
def initialize
|
14
|
-
@
|
28
|
+
@string_subscribers = Hash.new { |h, k| h[k] = [] }
|
29
|
+
@other_subscribers = []
|
15
30
|
@listeners_for = Concurrent::Map.new
|
16
31
|
super
|
17
32
|
end
|
18
33
|
|
19
|
-
def subscribe(pattern = nil,
|
20
|
-
subscriber = Subscribers.new
|
34
|
+
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
35
|
+
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
21
36
|
synchronize do
|
22
|
-
|
23
|
-
|
37
|
+
case pattern
|
38
|
+
when String
|
39
|
+
@string_subscribers[pattern] << subscriber
|
40
|
+
@listeners_for.delete(pattern)
|
41
|
+
when NilClass, Regexp
|
42
|
+
@other_subscribers << subscriber
|
43
|
+
@listeners_for.clear
|
44
|
+
else
|
45
|
+
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
46
|
+
end
|
24
47
|
end
|
25
48
|
subscriber
|
26
49
|
end
|
@@ -29,32 +52,65 @@ module ActiveSupport
|
|
29
52
|
synchronize do
|
30
53
|
case subscriber_or_name
|
31
54
|
when String
|
32
|
-
@
|
55
|
+
@string_subscribers[subscriber_or_name].clear
|
56
|
+
@listeners_for.delete(subscriber_or_name)
|
57
|
+
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
33
58
|
else
|
34
|
-
|
59
|
+
pattern = subscriber_or_name.try(:pattern)
|
60
|
+
if String === pattern
|
61
|
+
@string_subscribers[pattern].delete(subscriber_or_name)
|
62
|
+
@listeners_for.delete(pattern)
|
63
|
+
else
|
64
|
+
@other_subscribers.delete(subscriber_or_name)
|
65
|
+
@listeners_for.clear
|
66
|
+
end
|
35
67
|
end
|
36
|
-
|
37
|
-
@listeners_for.clear
|
38
68
|
end
|
39
69
|
end
|
40
70
|
|
41
71
|
def start(name, id, payload)
|
42
|
-
listeners_for(name)
|
72
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.start(name, id, payload) }
|
43
73
|
end
|
44
74
|
|
45
75
|
def finish(name, id, payload, listeners = listeners_for(name))
|
46
|
-
listeners
|
76
|
+
iterate_guarding_exceptions(listeners) { |s| s.finish(name, id, payload) }
|
47
77
|
end
|
48
78
|
|
49
79
|
def publish(name, *args)
|
50
|
-
listeners_for(name)
|
80
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def publish_event(event)
|
84
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def iterate_guarding_exceptions(listeners)
|
88
|
+
exceptions = nil
|
89
|
+
|
90
|
+
listeners.each do |s|
|
91
|
+
yield s
|
92
|
+
rescue Exception => e
|
93
|
+
exceptions ||= []
|
94
|
+
exceptions << e
|
95
|
+
end
|
96
|
+
|
97
|
+
if exceptions
|
98
|
+
if exceptions.size == 1
|
99
|
+
raise exceptions.first
|
100
|
+
else
|
101
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
listeners
|
51
106
|
end
|
52
107
|
|
53
108
|
def listeners_for(name)
|
54
109
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
55
110
|
@listeners_for[name] || synchronize do
|
56
111
|
# use synchronisation when accessing @subscribers
|
57
|
-
@listeners_for[name] ||=
|
112
|
+
@listeners_for[name] ||=
|
113
|
+
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
58
114
|
end
|
59
115
|
end
|
60
116
|
|
@@ -67,25 +123,70 @@ module ActiveSupport
|
|
67
123
|
end
|
68
124
|
|
69
125
|
module Subscribers # :nodoc:
|
70
|
-
def self.new(pattern, listener)
|
126
|
+
def self.new(pattern, listener, monotonic)
|
127
|
+
subscriber_class = monotonic ? MonotonicTimed : Timed
|
128
|
+
|
71
129
|
if listener.respond_to?(:start) && listener.respond_to?(:finish)
|
72
|
-
|
130
|
+
subscriber_class = Evented
|
73
131
|
else
|
74
|
-
|
132
|
+
# Doing this to detect a single argument block or callable
|
133
|
+
# like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
|
134
|
+
# or `proc { |x, **y| }`
|
135
|
+
procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
|
136
|
+
|
137
|
+
if procish.arity == 1 && procish.parameters.length == 1
|
138
|
+
subscriber_class = EventObject
|
139
|
+
end
|
75
140
|
end
|
76
141
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
142
|
+
subscriber_class.new(pattern, listener)
|
143
|
+
end
|
144
|
+
|
145
|
+
class Matcher # :nodoc:
|
146
|
+
attr_reader :pattern, :exclusions
|
147
|
+
|
148
|
+
def self.wrap(pattern)
|
149
|
+
if String === pattern
|
150
|
+
pattern
|
151
|
+
elsif pattern.nil?
|
152
|
+
AllMessages.new
|
153
|
+
else
|
154
|
+
new(pattern)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def initialize(pattern)
|
159
|
+
@pattern = pattern
|
160
|
+
@exclusions = Set.new
|
161
|
+
end
|
162
|
+
|
163
|
+
def unsubscribe!(name)
|
164
|
+
exclusions << -name if pattern === name
|
165
|
+
end
|
166
|
+
|
167
|
+
def ===(name)
|
168
|
+
pattern === name && !exclusions.include?(name)
|
169
|
+
end
|
170
|
+
|
171
|
+
class AllMessages
|
172
|
+
def ===(name)
|
173
|
+
true
|
174
|
+
end
|
175
|
+
|
176
|
+
def unsubscribe!(*)
|
177
|
+
false
|
178
|
+
end
|
81
179
|
end
|
82
180
|
end
|
83
181
|
|
84
|
-
class Evented
|
182
|
+
class Evented # :nodoc:
|
183
|
+
attr_reader :pattern
|
184
|
+
|
85
185
|
def initialize(pattern, delegate)
|
86
|
-
@pattern = pattern
|
186
|
+
@pattern = Matcher.wrap(pattern)
|
87
187
|
@delegate = delegate
|
88
188
|
@can_publish = delegate.respond_to?(:publish)
|
189
|
+
@can_publish_event = delegate.respond_to?(:publish_event)
|
89
190
|
end
|
90
191
|
|
91
192
|
def publish(name, *args)
|
@@ -94,6 +195,14 @@ module ActiveSupport
|
|
94
195
|
end
|
95
196
|
end
|
96
197
|
|
198
|
+
def publish_event(event)
|
199
|
+
if @can_publish_event
|
200
|
+
@delegate.publish_event event
|
201
|
+
else
|
202
|
+
publish(event.name, event.time, event.end, event.transaction_id, event.payload)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
97
206
|
def start(name, id, payload)
|
98
207
|
@delegate.start name, id, payload
|
99
208
|
end
|
@@ -103,11 +212,11 @@ module ActiveSupport
|
|
103
212
|
end
|
104
213
|
|
105
214
|
def subscribed_to?(name)
|
106
|
-
|
215
|
+
pattern === name
|
107
216
|
end
|
108
217
|
|
109
|
-
def
|
110
|
-
|
218
|
+
def unsubscribe!(name)
|
219
|
+
pattern.unsubscribe!(name)
|
111
220
|
end
|
112
221
|
end
|
113
222
|
|
@@ -117,39 +226,58 @@ module ActiveSupport
|
|
117
226
|
end
|
118
227
|
|
119
228
|
def start(name, id, payload)
|
120
|
-
timestack =
|
229
|
+
timestack = IsolatedExecutionState[:_timestack] ||= []
|
121
230
|
timestack.push Time.now
|
122
231
|
end
|
123
232
|
|
124
233
|
def finish(name, id, payload)
|
125
|
-
timestack =
|
234
|
+
timestack = IsolatedExecutionState[:_timestack]
|
126
235
|
started = timestack.pop
|
127
236
|
@delegate.call(name, started, Time.now, id, payload)
|
128
237
|
end
|
129
238
|
end
|
130
239
|
|
131
|
-
class
|
132
|
-
def
|
133
|
-
@delegate
|
240
|
+
class MonotonicTimed < Evented # :nodoc:
|
241
|
+
def publish(name, *args)
|
242
|
+
@delegate.call name, *args
|
134
243
|
end
|
135
244
|
|
136
245
|
def start(name, id, payload)
|
137
|
-
|
246
|
+
timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
|
247
|
+
timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
138
248
|
end
|
139
249
|
|
140
250
|
def finish(name, id, payload)
|
141
|
-
|
251
|
+
timestack = IsolatedExecutionState[:_timestack_monotonic]
|
252
|
+
started = timestack.pop
|
253
|
+
@delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
|
142
254
|
end
|
255
|
+
end
|
143
256
|
|
144
|
-
|
145
|
-
|
257
|
+
class EventObject < Evented
|
258
|
+
def start(name, id, payload)
|
259
|
+
stack = IsolatedExecutionState[:_event_stack] ||= []
|
260
|
+
event = build_event name, id, payload
|
261
|
+
event.start!
|
262
|
+
stack.push event
|
146
263
|
end
|
147
264
|
|
148
|
-
def
|
149
|
-
|
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
|
150
271
|
end
|
151
272
|
|
152
|
-
|
273
|
+
def publish_event(event)
|
274
|
+
@delegate.call event
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
def build_event(name, id, payload)
|
279
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
280
|
+
end
|
153
281
|
end
|
154
282
|
end
|
155
283
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "securerandom"
|
2
4
|
|
3
5
|
module ActiveSupport
|
@@ -11,14 +13,15 @@ module ActiveSupport
|
|
11
13
|
@notifier = notifier
|
12
14
|
end
|
13
15
|
|
14
|
-
#
|
15
|
-
# and publish it.
|
16
|
-
#
|
16
|
+
# Given a block, instrument it by measuring the time taken to execute
|
17
|
+
# and publish it. Without a block, simply send a message via the
|
18
|
+
# notifier. Notice that events get sent even if an error occurs in the
|
19
|
+
# passed-in block.
|
17
20
|
def instrument(name, payload = {})
|
18
21
|
# some of the listeners might have state
|
19
22
|
listeners_state = start name, payload
|
20
23
|
begin
|
21
|
-
yield payload
|
24
|
+
yield payload if block_given?
|
22
25
|
rescue Exception => e
|
23
26
|
payload[:exception] = [e.class.name, e.message]
|
24
27
|
payload[:exception_object] = e
|
@@ -28,6 +31,10 @@ module ActiveSupport
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
34
|
+
def new_event(name, payload = {}) # :nodoc:
|
35
|
+
Event.new(name, nil, nil, @id, payload)
|
36
|
+
end
|
37
|
+
|
31
38
|
# Send a start notification with +name+ and +payload+.
|
32
39
|
def start(name, payload)
|
33
40
|
@notifier.start name, @id, payload
|
@@ -43,24 +50,71 @@ module ActiveSupport
|
|
43
50
|
end
|
44
51
|
|
45
52
|
private
|
46
|
-
|
47
53
|
def unique_id
|
48
54
|
SecureRandom.hex(10)
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
52
58
|
class Event
|
53
|
-
attr_reader :name, :time, :
|
54
|
-
attr_accessor :
|
59
|
+
attr_reader :name, :time, :end, :transaction_id, :children
|
60
|
+
attr_accessor :payload
|
55
61
|
|
56
62
|
def initialize(name, start, ending, transaction_id, payload)
|
57
63
|
@name = name
|
58
64
|
@payload = payload.dup
|
59
|
-
@time = start
|
65
|
+
@time = start ? start.to_f * 1_000.0 : start
|
60
66
|
@transaction_id = transaction_id
|
61
|
-
@end = ending
|
67
|
+
@end = ending ? ending.to_f * 1_000.0 : ending
|
62
68
|
@children = []
|
63
|
-
@
|
69
|
+
@cpu_time_start = 0.0
|
70
|
+
@cpu_time_finish = 0.0
|
71
|
+
@allocation_count_start = 0
|
72
|
+
@allocation_count_finish = 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def record
|
76
|
+
start!
|
77
|
+
begin
|
78
|
+
yield payload if block_given?
|
79
|
+
rescue Exception => e
|
80
|
+
payload[:exception] = [e.class.name, e.message]
|
81
|
+
payload[:exception_object] = e
|
82
|
+
raise e
|
83
|
+
ensure
|
84
|
+
finish!
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Record information at the time this event starts
|
89
|
+
def start!
|
90
|
+
@time = now
|
91
|
+
@cpu_time_start = now_cpu
|
92
|
+
@allocation_count_start = now_allocations
|
93
|
+
end
|
94
|
+
|
95
|
+
# Record information at the time this event finishes
|
96
|
+
def finish!
|
97
|
+
@cpu_time_finish = now_cpu
|
98
|
+
@end = now
|
99
|
+
@allocation_count_finish = now_allocations
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns the CPU time (in milliseconds) passed since the call to
|
103
|
+
# +start!+ and the call to +finish!+
|
104
|
+
def cpu_time
|
105
|
+
@cpu_time_finish - @cpu_time_start
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns the idle time time (in milliseconds) passed since the call to
|
109
|
+
# +start!+ and the call to +finish!+
|
110
|
+
def idle_time
|
111
|
+
duration - cpu_time
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the number of allocations made since the call to +start!+ and
|
115
|
+
# the call to +finish!+
|
116
|
+
def allocations
|
117
|
+
@allocation_count_finish - @allocation_count_start
|
64
118
|
end
|
65
119
|
|
66
120
|
# Returns the difference in milliseconds between when the execution of the
|
@@ -76,7 +130,7 @@ module ActiveSupport
|
|
76
130
|
#
|
77
131
|
# @event.duration # => 1000.138
|
78
132
|
def duration
|
79
|
-
|
133
|
+
self.end - time
|
80
134
|
end
|
81
135
|
|
82
136
|
def <<(event)
|
@@ -86,6 +140,33 @@ module ActiveSupport
|
|
86
140
|
def parent_of?(event)
|
87
141
|
@children.include? event
|
88
142
|
end
|
143
|
+
|
144
|
+
private
|
145
|
+
def now
|
146
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
147
|
+
end
|
148
|
+
|
149
|
+
begin
|
150
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
151
|
+
|
152
|
+
def now_cpu
|
153
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
154
|
+
end
|
155
|
+
rescue
|
156
|
+
def now_cpu # rubocop:disable Lint/DuplicateMethods
|
157
|
+
0.0
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
if GC.stat.key?(:total_allocated_objects)
|
162
|
+
def now_allocations
|
163
|
+
GC.stat(:total_allocated_objects)
|
164
|
+
end
|
165
|
+
else # Likely on JRuby, TruffleRuby
|
166
|
+
def now_allocations
|
167
|
+
0
|
168
|
+
end
|
169
|
+
end
|
89
170
|
end
|
90
171
|
end
|
91
172
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/notifications/instrumenter"
|
2
4
|
require "active_support/notifications/fanout"
|
3
|
-
require "active_support/per_thread_registry"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
|
-
# = Notifications
|
7
|
+
# = \Notifications
|
7
8
|
#
|
8
9
|
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
|
9
10
|
# Ruby.
|
@@ -32,10 +33,23 @@ module ActiveSupport
|
|
32
33
|
# name # => String, name of the event (such as 'render' from above)
|
33
34
|
# start # => Time, when the instrumented block started execution
|
34
35
|
# finish # => Time, when the instrumented block ended execution
|
35
|
-
# id # => String, unique ID for
|
36
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
37
|
+
# payload # => Hash, the payload
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# Here, the +start+ and +finish+ values represent wall-clock time. If you are
|
41
|
+
# concerned about accuracy, you can register a monotonic subscriber.
|
42
|
+
#
|
43
|
+
# ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
|
44
|
+
# name # => String, name of the event (such as 'render' from above)
|
45
|
+
# start # => Monotonic time, when the instrumented block started execution
|
46
|
+
# finish # => Monotonic time, when the instrumented block ended execution
|
47
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
36
48
|
# payload # => Hash, the payload
|
37
49
|
# end
|
38
50
|
#
|
51
|
+
# The +start+ and +finish+ values above represent monotonic time.
|
52
|
+
#
|
39
53
|
# For instance, let's store all "render" events in an array:
|
40
54
|
#
|
41
55
|
# events = []
|
@@ -57,7 +71,7 @@ module ActiveSupport
|
|
57
71
|
# event.payload # => { extra: :information }
|
58
72
|
#
|
59
73
|
# The block in the <tt>subscribe</tt> call gets the name of the event, start
|
60
|
-
# timestamp, end timestamp, a string with a unique identifier for that event
|
74
|
+
# timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
|
61
75
|
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
|
62
76
|
# that order.
|
63
77
|
#
|
@@ -65,9 +79,12 @@ module ActiveSupport
|
|
65
79
|
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
|
66
80
|
# the name of the exception class, and the exception message.
|
67
81
|
# The <tt>:exception_object</tt> key of the payload will have the exception
|
68
|
-
# itself as the value
|
82
|
+
# itself as the value:
|
83
|
+
#
|
84
|
+
# event.payload[:exception] # => ["ArgumentError", "Invalid value"]
|
85
|
+
# event.payload[:exception_object] # => #<ArgumentError: Invalid value>
|
69
86
|
#
|
70
|
-
# As the
|
87
|
+
# As the earlier example depicts, the class ActiveSupport::Notifications::Event
|
71
88
|
# is able to take the arguments as they come and provide an object-oriented
|
72
89
|
# interface to that data.
|
73
90
|
#
|
@@ -130,6 +147,16 @@ module ActiveSupport
|
|
130
147
|
# during the execution of the block. The callback is unsubscribed automatically
|
131
148
|
# after that.
|
132
149
|
#
|
150
|
+
# To record +started+ and +finished+ values with monotonic time,
|
151
|
+
# specify the optional <tt>:monotonic</tt> option to the
|
152
|
+
# <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
|
153
|
+
# to +false+ by default.
|
154
|
+
#
|
155
|
+
# callback = lambda {|name, started, finished, unique_id, payload| ... }
|
156
|
+
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
|
157
|
+
# ...
|
158
|
+
# end
|
159
|
+
#
|
133
160
|
# === Manual Unsubscription
|
134
161
|
#
|
135
162
|
# The +subscribe+ method returns a subscriber object:
|
@@ -148,6 +175,15 @@ module ActiveSupport
|
|
148
175
|
#
|
149
176
|
# ActiveSupport::Notifications.unsubscribe("render")
|
150
177
|
#
|
178
|
+
# Subscribers using a regexp or other pattern-matching object will remain subscribed
|
179
|
+
# to all events that match their original pattern, unless those events match a string
|
180
|
+
# passed to +unsubscribe+:
|
181
|
+
#
|
182
|
+
# subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
|
183
|
+
# ActiveSupport::Notifications.unsubscribe('render_template.action_view')
|
184
|
+
# subscriber.matches?('render_template.action_view') # => false
|
185
|
+
# subscriber.matches?('render_partial.action_view') # => true
|
186
|
+
#
|
151
187
|
# == Default Queue
|
152
188
|
#
|
153
189
|
# Notifications ships with a queue implementation that consumes and publishes events
|
@@ -161,6 +197,10 @@ module ActiveSupport
|
|
161
197
|
notifier.publish(name, *args)
|
162
198
|
end
|
163
199
|
|
200
|
+
def publish_event(event) # :nodoc:
|
201
|
+
notifier.publish_event(event)
|
202
|
+
end
|
203
|
+
|
164
204
|
def instrument(name, payload = {})
|
165
205
|
if notifier.listening?(name)
|
166
206
|
instrumenter.instrument(name, payload) { yield payload if block_given? }
|
@@ -169,12 +209,53 @@ module ActiveSupport
|
|
169
209
|
end
|
170
210
|
end
|
171
211
|
|
172
|
-
|
173
|
-
|
212
|
+
# Subscribe to a given event name with the passed +block+.
|
213
|
+
#
|
214
|
+
# You can subscribe to events by passing a String to match exact event
|
215
|
+
# names, or by passing a Regexp to match all events that match a pattern.
|
216
|
+
#
|
217
|
+
# ActiveSupport::Notifications.subscribe(/render/) do |*args|
|
218
|
+
# @event = ActiveSupport::Notifications::Event.new(*args)
|
219
|
+
# end
|
220
|
+
#
|
221
|
+
# The +block+ will receive five parameters with information about the event:
|
222
|
+
#
|
223
|
+
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
|
224
|
+
# name # => String, name of the event (such as 'render' from above)
|
225
|
+
# start # => Time, when the instrumented block started execution
|
226
|
+
# finish # => Time, when the instrumented block ended execution
|
227
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
228
|
+
# payload # => Hash, the payload
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# If the block passed to the method only takes one parameter,
|
232
|
+
# it will yield an event object to the block:
|
233
|
+
#
|
234
|
+
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
235
|
+
# @event = event
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# Raises an error if invalid event name type is passed:
|
239
|
+
#
|
240
|
+
# ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
|
241
|
+
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
242
|
+
#
|
243
|
+
def subscribe(pattern = nil, callback = nil, &block)
|
244
|
+
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Performs the same functionality as #subscribe, but the +start+ and
|
248
|
+
# +finish+ block arguments are in monotonic time instead of wall-clock
|
249
|
+
# time. Monotonic time will not jump forward or backward (due to NTP or
|
250
|
+
# Daylights Savings). Use +monotonic_subscribe+ when accuracy of time
|
251
|
+
# duration is important. For example, computing elapsed time between
|
252
|
+
# two events.
|
253
|
+
def monotonic_subscribe(pattern = nil, callback = nil, &block)
|
254
|
+
notifier.subscribe(pattern, callback, monotonic: true, &block)
|
174
255
|
end
|
175
256
|
|
176
|
-
def subscribed(callback,
|
177
|
-
subscriber = subscribe(
|
257
|
+
def subscribed(callback, pattern = nil, monotonic: false, &block)
|
258
|
+
subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
|
178
259
|
yield
|
179
260
|
ensure
|
180
261
|
unsubscribe(subscriber)
|
@@ -185,28 +266,13 @@ module ActiveSupport
|
|
185
266
|
end
|
186
267
|
|
187
268
|
def instrumenter
|
188
|
-
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
# This class is a registry which holds all of the +Instrumenter+ objects
|
193
|
-
# in a particular thread local. To access the +Instrumenter+ object for a
|
194
|
-
# particular +notifier+, you can call the following method:
|
195
|
-
#
|
196
|
-
# InstrumentationRegistry.instrumenter_for(notifier)
|
197
|
-
#
|
198
|
-
# The instrumenters for multiple notifiers are held in a single instance of
|
199
|
-
# this class.
|
200
|
-
class InstrumentationRegistry # :nodoc:
|
201
|
-
extend ActiveSupport::PerThreadRegistry
|
202
|
-
|
203
|
-
def initialize
|
204
|
-
@registry = {}
|
269
|
+
registry[notifier] ||= Instrumenter.new(notifier)
|
205
270
|
end
|
206
271
|
|
207
|
-
|
208
|
-
|
209
|
-
|
272
|
+
private
|
273
|
+
def registry
|
274
|
+
ActiveSupport::IsolatedExecutionState[:active_support_notifications_registry] ||= {}
|
275
|
+
end
|
210
276
|
end
|
211
277
|
|
212
278
|
self.notifier = Fanout.new
|