activesupport 6.0.6.1 → 7.1.3.2
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 +865 -438
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +30 -10
- data/lib/active_support/benchmarkable.rb +4 -3
- data/lib/active_support/broadcast_logger.rb +250 -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 +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +208 -63
- data/lib/active_support/cache/memory_store.rb +120 -38
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +201 -208
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -66
- data/lib/active_support/cache.rb +539 -261
- data/lib/active_support/callbacks.rb +273 -142
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +53 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +19 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +19 -29
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +18 -16
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +146 -72
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +5 -5
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
- data/lib/active_support/core_ext/module/concerning.rb +14 -8
- data/lib/active_support/core_ext/module/delegation.rb +75 -42
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +1 -26
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +15 -4
- 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 +52 -28
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- 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 +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- 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/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +51 -10
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +85 -194
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- 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/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +46 -8
- data/lib/active_support/core_ext/time/conversions.rb +16 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +54 -22
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +77 -38
- 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 +54 -0
- data/lib/active_support/deprecation/instance_delegator.rb +31 -5
- data/lib/active_support/deprecation/method_wrappers.rb +12 -28
- data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
- data/lib/active_support/deprecation/reporting.rb +76 -16
- data/lib/active_support/deprecation.rb +36 -4
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -68
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -12
- data/lib/active_support/duration.rb +136 -56
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +46 -13
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +86 -137
- 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 +31 -12
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +79 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +86 -42
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +29 -27
- data/lib/active_support/inflector/inflections.rb +26 -9
- data/lib/active_support/inflector/methods.rb +54 -64
- data/lib/active_support/inflector/transliterate.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +6 -5
- data/lib/active_support/json/encoding.rb +31 -45
- data/lib/active_support/key_generator.rb +32 -7
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +101 -32
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +24 -25
- data/lib/active_support/message_encryptor.rb +205 -58
- 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 +237 -86
- 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 +112 -46
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +35 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +15 -52
- data/lib/active_support/multibyte/unicode.rb +8 -122
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +310 -105
- data/lib/active_support/notifications/instrumenter.rb +113 -48
- data/lib/active_support/notifications.rb +56 -29
- data/lib/active_support/number_helper/number_converter.rb +15 -8
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +379 -304
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +23 -3
- data/lib/active_support/parameter_filter.rb +104 -75
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +90 -6
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +5 -3
- data/lib/active_support/subscriber.rb +23 -47
- data/lib/active_support/syntax_error_proxy.rb +70 -0
- data/lib/active_support/tagged_logging.rb +84 -23
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +73 -20
- 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 +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- 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 +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +89 -19
- data/lib/active_support/time_with_zone.rb +105 -70
- data/lib/active_support/values/time_zone.rb +59 -26
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +40 -1
- metadata +127 -40
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -25
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/security_utils"
|
4
|
+
require "active_support/messages/rotator"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
# = Secure Compare Rotator
|
8
|
+
#
|
9
|
+
# The ActiveSupport::SecureCompareRotator is a wrapper around ActiveSupport::SecurityUtils.secure_compare
|
10
|
+
# and allows you to rotate a previously defined value to a new one.
|
11
|
+
#
|
12
|
+
# It can be used as follow:
|
13
|
+
#
|
14
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
|
15
|
+
# rotator.rotate('previous_production_value')
|
16
|
+
# rotator.secure_compare!('previous_production_value')
|
17
|
+
#
|
18
|
+
# One real use case example would be to rotate a basic auth credentials:
|
19
|
+
#
|
20
|
+
# class MyController < ApplicationController
|
21
|
+
# def authenticate_request
|
22
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_password')
|
23
|
+
# rotator.rotate('old_password')
|
24
|
+
#
|
25
|
+
# authenticate_or_request_with_http_basic do |username, password|
|
26
|
+
# rotator.secure_compare!(password)
|
27
|
+
# rescue ActiveSupport::SecureCompareRotator::InvalidMatch
|
28
|
+
# false
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
class SecureCompareRotator
|
33
|
+
include SecurityUtils
|
34
|
+
|
35
|
+
InvalidMatch = Class.new(StandardError)
|
36
|
+
|
37
|
+
def initialize(value, on_rotation: nil)
|
38
|
+
@value = value
|
39
|
+
@rotate_values = []
|
40
|
+
@on_rotation = on_rotation
|
41
|
+
end
|
42
|
+
|
43
|
+
def rotate(previous_value)
|
44
|
+
@rotate_values << previous_value
|
45
|
+
end
|
46
|
+
|
47
|
+
def secure_compare!(other_value, on_rotation: @on_rotation)
|
48
|
+
if secure_compare(@value, other_value)
|
49
|
+
true
|
50
|
+
elsif @rotate_values.any? { |value| secure_compare(value, other_value) }
|
51
|
+
on_rotation&.call
|
52
|
+
true
|
53
|
+
else
|
54
|
+
raise InvalidMatch
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "digest/sha2"
|
4
|
-
|
5
3
|
module ActiveSupport
|
6
4
|
module SecurityUtils
|
7
5
|
# Constant time string comparison, for fixed length strings.
|
8
6
|
#
|
9
7
|
# The values compared should be of fixed length, such as strings
|
10
8
|
# that have already been processed by HMAC. Raises in case of length mismatch.
|
11
|
-
def fixed_length_secure_compare(a, b)
|
12
|
-
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
13
9
|
|
14
|
-
|
10
|
+
if defined?(OpenSSL.fixed_length_secure_compare)
|
11
|
+
def fixed_length_secure_compare(a, b)
|
12
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def fixed_length_secure_compare(a, b)
|
16
|
+
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
17
|
+
|
18
|
+
l = a.unpack "C#{a.bytesize}"
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
res = 0
|
21
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
22
|
+
res == 0
|
23
|
+
end
|
19
24
|
end
|
20
25
|
module_function :fixed_length_secure_compare
|
21
26
|
|
22
|
-
#
|
27
|
+
# Secure string comparison for strings of variable length.
|
23
28
|
#
|
24
|
-
#
|
25
|
-
# via
|
29
|
+
# While a timing attack would not be able to discern the content of
|
30
|
+
# a secret compared via secure_compare, it is possible to determine
|
31
|
+
# the secret length. This should be considered when using secure_compare
|
32
|
+
# to compare weak, short secrets to user input.
|
26
33
|
def secure_compare(a, b)
|
27
|
-
|
34
|
+
a.bytesize == b.bytesize && fixed_length_secure_compare(a, b)
|
28
35
|
end
|
29
36
|
module_function :secure_compare
|
30
37
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = \String Inquirer
|
5
|
+
#
|
4
6
|
# Wrapping a string in this class gives you a prettier way to test
|
5
7
|
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
|
6
8
|
# in a StringInquirer object, so instead of calling this:
|
@@ -11,7 +13,7 @@ module ActiveSupport
|
|
11
13
|
#
|
12
14
|
# Rails.env.production?
|
13
15
|
#
|
14
|
-
# == Instantiating a new StringInquirer
|
16
|
+
# == Instantiating a new \StringInquirer
|
15
17
|
#
|
16
18
|
# vehicle = ActiveSupport::StringInquirer.new('car')
|
17
19
|
# vehicle.car? # => true
|
@@ -19,11 +21,11 @@ module ActiveSupport
|
|
19
21
|
class StringInquirer < String
|
20
22
|
private
|
21
23
|
def respond_to_missing?(method_name, include_private = false)
|
22
|
-
(
|
24
|
+
method_name.end_with?("?") || super
|
23
25
|
end
|
24
26
|
|
25
27
|
def method_missing(method_name, *arguments)
|
26
|
-
if method_name
|
28
|
+
if method_name.end_with?("?")
|
27
29
|
self == method_name[0..-2]
|
28
30
|
else
|
29
31
|
super
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/per_thread_registry"
|
4
3
|
require "active_support/notifications"
|
5
4
|
|
6
5
|
module ActiveSupport
|
7
|
-
#
|
6
|
+
# = Active Support \Subscriber
|
7
|
+
#
|
8
|
+
# +ActiveSupport::Subscriber+ is an object set to consume
|
8
9
|
# ActiveSupport::Notifications. The subscriber dispatches notifications to
|
9
10
|
# a registered object based on its given namespace.
|
10
11
|
#
|
@@ -21,9 +22,9 @@ module ActiveSupport
|
|
21
22
|
# end
|
22
23
|
# end
|
23
24
|
#
|
24
|
-
# After configured, whenever a "sql.active_record" notification is
|
25
|
-
# it will properly dispatch the event
|
26
|
-
# the +sql+ method.
|
25
|
+
# After configured, whenever a <tt>"sql.active_record"</tt> notification is
|
26
|
+
# published, it will properly dispatch the event
|
27
|
+
# (ActiveSupport::Notifications::Event) to the +sql+ method.
|
27
28
|
#
|
28
29
|
# We can detach a subscriber as well:
|
29
30
|
#
|
@@ -31,15 +32,16 @@ module ActiveSupport
|
|
31
32
|
class Subscriber
|
32
33
|
class << self
|
33
34
|
# Attach the subscriber to a namespace.
|
34
|
-
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications)
|
35
|
+
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
|
35
36
|
@namespace = namespace
|
36
37
|
@subscriber = subscriber
|
37
38
|
@notifier = notifier
|
39
|
+
@inherit_all = inherit_all
|
38
40
|
|
39
41
|
subscribers << subscriber
|
40
42
|
|
41
43
|
# Add event subscribers for all existing methods on the class.
|
42
|
-
subscriber
|
44
|
+
fetch_public_methods(subscriber, inherit_all).each do |event|
|
43
45
|
add_event_subscriber(event)
|
44
46
|
end
|
45
47
|
end
|
@@ -55,7 +57,7 @@ module ActiveSupport
|
|
55
57
|
subscribers.delete(subscriber)
|
56
58
|
|
57
59
|
# Remove event subscribers of all existing methods on the class.
|
58
|
-
subscriber
|
60
|
+
fetch_public_methods(subscriber, true).each do |event|
|
59
61
|
remove_event_subscriber(event)
|
60
62
|
end
|
61
63
|
|
@@ -81,18 +83,18 @@ module ActiveSupport
|
|
81
83
|
attr_reader :subscriber, :notifier, :namespace
|
82
84
|
|
83
85
|
def add_event_subscriber(event) # :doc:
|
84
|
-
return if invalid_event?(event
|
86
|
+
return if invalid_event?(event)
|
85
87
|
|
86
88
|
pattern = prepare_pattern(event)
|
87
89
|
|
88
|
-
# Don't add multiple subscribers (
|
90
|
+
# Don't add multiple subscribers (e.g. if methods are redefined).
|
89
91
|
return if pattern_subscribed?(pattern)
|
90
92
|
|
91
93
|
subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
|
92
94
|
end
|
93
95
|
|
94
96
|
def remove_event_subscriber(event) # :doc:
|
95
|
-
return if invalid_event?(event
|
97
|
+
return if invalid_event?(event)
|
96
98
|
|
97
99
|
pattern = prepare_pattern(event)
|
98
100
|
|
@@ -107,7 +109,7 @@ module ActiveSupport
|
|
107
109
|
end
|
108
110
|
|
109
111
|
def invalid_event?(event)
|
110
|
-
%
|
112
|
+
%i{ start finish }.include?(event.to_sym)
|
111
113
|
end
|
112
114
|
|
113
115
|
def prepare_pattern(event)
|
@@ -117,53 +119,27 @@ module ActiveSupport
|
|
117
119
|
def pattern_subscribed?(pattern)
|
118
120
|
subscriber.patterns.key?(pattern)
|
119
121
|
end
|
122
|
+
|
123
|
+
def fetch_public_methods(subscriber, inherit_all)
|
124
|
+
subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
|
125
|
+
end
|
120
126
|
end
|
121
127
|
|
122
128
|
attr_reader :patterns # :nodoc:
|
123
129
|
|
124
130
|
def initialize
|
125
|
-
@queue_key = [self.class.name, object_id].join "-"
|
126
131
|
@patterns = {}
|
127
132
|
super
|
128
133
|
end
|
129
134
|
|
130
|
-
def
|
131
|
-
|
132
|
-
event.start!
|
133
|
-
parent = event_stack.last
|
134
|
-
parent << event if parent
|
135
|
-
|
136
|
-
event_stack.push event
|
137
|
-
end
|
138
|
-
|
139
|
-
def finish(name, id, payload)
|
140
|
-
event = event_stack.pop
|
141
|
-
event.finish!
|
142
|
-
event.payload.merge!(payload)
|
143
|
-
|
144
|
-
method = name.split(".").first
|
135
|
+
def call(event)
|
136
|
+
method = event.name[0, event.name.index(".")]
|
145
137
|
send(method, event)
|
146
138
|
end
|
147
139
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# This is a registry for all the event stacks kept for subscribers.
|
155
|
-
#
|
156
|
-
# See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
|
157
|
-
# for further details.
|
158
|
-
class SubscriberQueueRegistry # :nodoc:
|
159
|
-
extend PerThreadRegistry
|
160
|
-
|
161
|
-
def initialize
|
162
|
-
@registry = {}
|
163
|
-
end
|
164
|
-
|
165
|
-
def get_queue(queue_key)
|
166
|
-
@registry[queue_key] ||= []
|
140
|
+
def publish_event(event) # :nodoc:
|
141
|
+
method = event.name[0, event.name.index(".")]
|
142
|
+
send(method, event)
|
167
143
|
end
|
168
144
|
end
|
169
145
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
# This is a class for wrapping syntax errors. The purpose of this class
|
7
|
+
# is to enhance the backtraces on SyntaxError exceptions to include the
|
8
|
+
# source location of the syntax error. That way we can display the error
|
9
|
+
# source on error pages in development.
|
10
|
+
class SyntaxErrorProxy < DelegateClass(SyntaxError) # :nodoc:
|
11
|
+
def backtrace
|
12
|
+
parse_message_for_trace + super
|
13
|
+
end
|
14
|
+
|
15
|
+
class BacktraceLocation < Struct.new(:path, :lineno, :to_s) # :nodoc:
|
16
|
+
def spot(_)
|
17
|
+
end
|
18
|
+
|
19
|
+
def label
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
|
24
|
+
def initialize(loc, ex)
|
25
|
+
super(loc)
|
26
|
+
@ex = ex
|
27
|
+
end
|
28
|
+
|
29
|
+
def spot(_)
|
30
|
+
super(@ex.__getobj__)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def backtrace_locations
|
35
|
+
return nil if super.nil?
|
36
|
+
|
37
|
+
parse_message_for_trace.map { |trace|
|
38
|
+
file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
|
39
|
+
BacktraceLocation.new(file, line.to_i, trace)
|
40
|
+
# We have to wrap these backtrace locations because we need the
|
41
|
+
# spot information to come from the originating exception, not the
|
42
|
+
# proxy object that's generating these
|
43
|
+
} + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def parse_message_for_trace
|
48
|
+
if source_location_eval?
|
49
|
+
# If the exception is coming from a call to eval, we need to keep
|
50
|
+
# the path of the file in which eval was called to ensure we can
|
51
|
+
# return the right source fragment to show the location of the
|
52
|
+
# error
|
53
|
+
location = __getobj__.backtrace_locations[0]
|
54
|
+
["#{location.path}:#{location.lineno}: #{__getobj__}"]
|
55
|
+
else
|
56
|
+
__getobj__.to_s.split("\n")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if SyntaxError.method_defined?(:path) # Ruby 3.3+
|
61
|
+
def source_location_eval?
|
62
|
+
__getobj__.path.start_with?("(eval")
|
63
|
+
end
|
64
|
+
else # 3.2 and older versions of Ruby
|
65
|
+
def source_location_eval?
|
66
|
+
__getobj__.to_s.start_with?("(eval")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -6,12 +6,23 @@ require "logger"
|
|
6
6
|
require "active_support/logger"
|
7
7
|
|
8
8
|
module ActiveSupport
|
9
|
+
# = Active Support Tagged Logging
|
10
|
+
#
|
9
11
|
# Wraps any standard Logger object to provide tagging capabilities.
|
10
12
|
#
|
13
|
+
# May be called with a block:
|
14
|
+
#
|
11
15
|
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
12
|
-
# logger.tagged('BCX') { logger.info 'Stuff' }
|
13
|
-
# logger.tagged('BCX', "Jason") {
|
14
|
-
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } }
|
16
|
+
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
|
17
|
+
# logger.tagged('BCX', "Jason") { |tagged_logger| tagged_logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
|
18
|
+
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
|
19
|
+
#
|
20
|
+
# If called without a block, a new logger will be returned with applied tags:
|
21
|
+
#
|
22
|
+
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
23
|
+
# logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
|
24
|
+
# logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
25
|
+
# logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
15
26
|
#
|
16
27
|
# This is used by the default Rails.logger as configured by Railties to make
|
17
28
|
# it easy to stamp log lines with subdomains, request ids, and anything else
|
@@ -20,51 +31,94 @@ module ActiveSupport
|
|
20
31
|
module Formatter # :nodoc:
|
21
32
|
# This method is invoked when a log event occurs.
|
22
33
|
def call(severity, timestamp, progname, msg)
|
23
|
-
super(severity, timestamp, progname,
|
34
|
+
super(severity, timestamp, progname, tag_stack.format_message(msg))
|
24
35
|
end
|
25
36
|
|
26
37
|
def tagged(*tags)
|
27
|
-
|
38
|
+
pushed_count = tag_stack.push_tags(tags).size
|
28
39
|
yield self
|
29
40
|
ensure
|
30
|
-
pop_tags(
|
41
|
+
pop_tags(pushed_count)
|
31
42
|
end
|
32
43
|
|
33
44
|
def push_tags(*tags)
|
34
|
-
|
35
|
-
current_tags.concat new_tags
|
36
|
-
end
|
45
|
+
tag_stack.push_tags(tags)
|
37
46
|
end
|
38
47
|
|
39
|
-
def pop_tags(
|
40
|
-
|
48
|
+
def pop_tags(count = 1)
|
49
|
+
tag_stack.pop_tags(count)
|
41
50
|
end
|
42
51
|
|
43
52
|
def clear_tags!
|
44
|
-
|
53
|
+
tag_stack.clear
|
45
54
|
end
|
46
55
|
|
47
|
-
def
|
56
|
+
def tag_stack
|
48
57
|
# We use our object ID here to avoid conflicting with other instances
|
49
|
-
|
50
|
-
|
58
|
+
@thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
|
59
|
+
IsolatedExecutionState[@thread_key] ||= TagStack.new
|
60
|
+
end
|
61
|
+
|
62
|
+
def current_tags
|
63
|
+
tag_stack.tags
|
51
64
|
end
|
52
65
|
|
53
66
|
def tags_text
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
67
|
+
tag_stack.format_message("")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class TagStack # :nodoc:
|
72
|
+
attr_reader :tags
|
73
|
+
|
74
|
+
def initialize
|
75
|
+
@tags = []
|
76
|
+
@tags_string = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def push_tags(tags)
|
80
|
+
@tags_string = nil
|
81
|
+
tags.flatten!
|
82
|
+
tags.reject!(&:blank?)
|
83
|
+
@tags.concat(tags)
|
84
|
+
tags
|
85
|
+
end
|
86
|
+
|
87
|
+
def pop_tags(count)
|
88
|
+
@tags_string = nil
|
89
|
+
@tags.pop(count)
|
90
|
+
end
|
91
|
+
|
92
|
+
def clear
|
93
|
+
@tags_string = nil
|
94
|
+
@tags.clear
|
95
|
+
end
|
96
|
+
|
97
|
+
def format_message(message)
|
98
|
+
if @tags.empty?
|
99
|
+
message
|
100
|
+
elsif @tags.size == 1
|
101
|
+
"[#{@tags[0]}] #{message}"
|
102
|
+
else
|
103
|
+
@tags_string ||= "[#{@tags.join("] [")}] "
|
104
|
+
"#{@tags_string}#{message}"
|
59
105
|
end
|
60
106
|
end
|
61
107
|
end
|
62
108
|
|
109
|
+
module LocalTagStorage # :nodoc:
|
110
|
+
attr_accessor :tag_stack
|
111
|
+
|
112
|
+
def self.extended(base)
|
113
|
+
base.tag_stack = TagStack.new
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
63
117
|
def self.new(logger)
|
64
|
-
logger = logger.
|
118
|
+
logger = logger.clone
|
65
119
|
|
66
120
|
if logger.formatter
|
67
|
-
logger.formatter = logger.formatter.
|
121
|
+
logger.formatter = logger.formatter.clone
|
68
122
|
else
|
69
123
|
# Ensure we set a default formatter so we aren't extending nil!
|
70
124
|
logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
|
@@ -77,7 +131,14 @@ module ActiveSupport
|
|
77
131
|
delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
|
78
132
|
|
79
133
|
def tagged(*tags)
|
80
|
-
|
134
|
+
if block_given?
|
135
|
+
formatter.tagged(*tags) { yield self }
|
136
|
+
else
|
137
|
+
logger = ActiveSupport::TaggedLogging.new(self)
|
138
|
+
logger.formatter.extend LocalTagStorage
|
139
|
+
logger.push_tags(*formatter.current_tags, *tags)
|
140
|
+
logger
|
141
|
+
end
|
81
142
|
end
|
82
143
|
|
83
144
|
def flush
|