activesupport 5.2.4.4 → 6.1.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 +353 -435
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support.rb +14 -1
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +29 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache.rb +142 -78
- data/lib/active_support/cache/file_store.rb +33 -33
- data/lib/active_support/cache/mem_cache_store.rb +32 -20
- data/lib/active_support/cache/memory_store.rb +59 -33
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +70 -43
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- data/lib/active_support/callbacks.rb +81 -64
- data/lib/active_support/concern.rb +70 -3
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +10 -14
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/enumerable.rb +171 -75
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/hash/conversions.rb +3 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +1 -30
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +76 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +14 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +34 -13
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +45 -6
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +70 -13
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +50 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +6 -1
- data/lib/active_support/current_attributes.rb +15 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +109 -34
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/deprecation/behaviors.rb +16 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/descendants_tracker.rb +59 -9
- data/lib/active_support/duration.rb +90 -38
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- data/lib/active_support/encrypted_configuration.rb +0 -4
- data/lib/active_support/encrypted_file.rb +22 -4
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +82 -117
- data/lib/active_support/execution_wrapper.rb +1 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +64 -41
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +2 -7
- data/lib/active_support/inflector/methods.rb +49 -58
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +11 -3
- data/lib/active_support/key_generator.rb +1 -33
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +39 -9
- data/lib/active_support/logger.rb +2 -17
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +50 -6
- data/lib/active_support/message_encryptor.rb +8 -13
- data/lib/active_support/message_verifier.rb +10 -10
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +10 -68
- data/lib/active_support/multibyte/unicode.rb +15 -327
- data/lib/active_support/notifications.rb +72 -8
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/number_helper/number_converter.rb +5 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/option_merger.rb +22 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +13 -3
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +72 -28
- data/lib/active_support/tagged_logging.rb +42 -8
- data/lib/active_support/test_case.rb +91 -0
- data/lib/active_support/testing/assertions.rb +30 -9
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +47 -12
- data/lib/active_support/time_with_zone.rb +81 -47
- data/lib/active_support/values/time_zone.rb +32 -17
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +10 -3
- metadata +58 -32
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -40,7 +40,7 @@ module ActiveSupport
|
|
40
40
|
# If the class has an initializer, it must accept no arguments.
|
41
41
|
module PerThreadRegistry
|
42
42
|
def self.extended(object)
|
43
|
-
object.instance_variable_set
|
43
|
+
object.instance_variable_set :@per_thread_registry_key, object.name.freeze
|
44
44
|
end
|
45
45
|
|
46
46
|
def instance
|
data/lib/active_support/rails.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# This is private interface.
|
3
|
+
# This is a private interface.
|
4
4
|
#
|
5
5
|
# Rails components cherry pick from Active Support as needed, but there are a
|
6
6
|
# few features that are used for sure in some way or another and it is not worth
|
@@ -13,9 +13,6 @@
|
|
13
13
|
# Defines Object#blank? and Object#present?.
|
14
14
|
require "active_support/core_ext/object/blank"
|
15
15
|
|
16
|
-
# Rails own autoload, eager_load, etc.
|
17
|
-
require "active_support/dependencies/autoload"
|
18
|
-
|
19
16
|
# Support for ClassMethods and the included macro.
|
20
17
|
require "active_support/concern"
|
21
18
|
|
@@ -27,9 +24,3 @@ require "active_support/core_ext/module/delegation"
|
|
27
24
|
|
28
25
|
# Defines ActiveSupport::Deprecation.
|
29
26
|
require "active_support/deprecation"
|
30
|
-
|
31
|
-
# Defines Regexp#match?.
|
32
|
-
#
|
33
|
-
# This should be removed when Rails needs Ruby 2.4 or later, and the require
|
34
|
-
# added where other Regexp extensions are being used (easy to grep).
|
35
|
-
require "active_support/core_ext/regexp"
|
@@ -22,12 +22,25 @@ module ActiveSupport
|
|
22
22
|
app.reloader.before_class_unload { ActiveSupport::CurrentAttributes.clear_all }
|
23
23
|
app.executor.to_run { ActiveSupport::CurrentAttributes.reset_all }
|
24
24
|
app.executor.to_complete { ActiveSupport::CurrentAttributes.reset_all }
|
25
|
+
|
26
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
27
|
+
require "active_support/current_attributes/test_helper"
|
28
|
+
include ActiveSupport::CurrentAttributes::TestHelper
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
initializer "active_support.deprecation_behavior" do |app|
|
28
33
|
if deprecation = app.config.active_support.deprecation
|
29
34
|
ActiveSupport::Deprecation.behavior = deprecation
|
30
35
|
end
|
36
|
+
|
37
|
+
if disallowed_deprecation = app.config.active_support.disallowed_deprecation
|
38
|
+
ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
|
39
|
+
end
|
40
|
+
|
41
|
+
if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
|
42
|
+
ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
# Sets the default value for Time.zone
|
@@ -65,15 +78,24 @@ module ActiveSupport
|
|
65
78
|
initializer "active_support.set_configs" do |app|
|
66
79
|
app.config.active_support.each do |k, v|
|
67
80
|
k = "#{k}="
|
68
|
-
ActiveSupport.
|
81
|
+
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
69
82
|
end
|
70
83
|
end
|
71
84
|
|
72
85
|
initializer "active_support.set_hash_digest_class" do |app|
|
73
86
|
config.after_initialize do
|
74
87
|
if app.config.active_support.use_sha1_digests
|
88
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
89
|
+
config.active_support.use_sha1_digests is deprecated and will
|
90
|
+
be removed from Rails 6.2. Use
|
91
|
+
config.active_support.hash_digest_class = ::Digest::SHA1 instead.
|
92
|
+
MSG
|
75
93
|
ActiveSupport::Digest.hash_digest_class = ::Digest::SHA1
|
76
94
|
end
|
95
|
+
|
96
|
+
if klass = app.config.active_support.hash_digest_class
|
97
|
+
ActiveSupport::Digest.hash_digest_class = klass
|
98
|
+
end
|
77
99
|
end
|
78
100
|
end
|
79
101
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/execution_wrapper"
|
4
|
+
require "active_support/executor"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
#--
|
@@ -49,11 +50,9 @@ module ActiveSupport
|
|
49
50
|
def self.reload!
|
50
51
|
executor.wrap do
|
51
52
|
new.tap do |instance|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
instance.complete!
|
56
|
-
end
|
53
|
+
instance.run!
|
54
|
+
ensure
|
55
|
+
instance.complete!
|
57
56
|
end
|
58
57
|
end
|
59
58
|
prepare!
|
@@ -14,12 +14,12 @@ module ActiveSupport
|
|
14
14
|
end
|
15
15
|
|
16
16
|
module ClassMethods
|
17
|
-
#
|
17
|
+
# Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
|
18
18
|
#
|
19
19
|
# <tt>rescue_from</tt> receives a series of exception classes or class
|
20
|
-
# names, and a trailing <tt>:with</tt>
|
21
|
-
#
|
22
|
-
# be given.
|
20
|
+
# names, and an exception handler specified by a trailing <tt>:with</tt>
|
21
|
+
# option containing the name of a method or a Proc object. Alternatively, a block
|
22
|
+
# can be given as the handler.
|
23
23
|
#
|
24
24
|
# Handlers that take one argument will be called with the exception, so
|
25
25
|
# that the exception can be inspected when dealing with it.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/security_utils"
|
4
|
+
require "active_support/messages/rotator"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
# The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
|
8
|
+
# and allows you to rotate a previously defined value to a new one.
|
9
|
+
#
|
10
|
+
# It can be used as follow:
|
11
|
+
#
|
12
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
|
13
|
+
# rotator.rotate('previous_production_value')
|
14
|
+
# rotator.secure_compare!('previous_production_value')
|
15
|
+
#
|
16
|
+
# One real use case example would be to rotate a basic auth credentials:
|
17
|
+
#
|
18
|
+
# class MyController < ApplicationController
|
19
|
+
# def authenticate_request
|
20
|
+
# rotator = ActiveSupport::SecureComparerotator.new('new_password')
|
21
|
+
# rotator.rotate('old_password')
|
22
|
+
#
|
23
|
+
# authenticate_or_request_with_http_basic do |username, password|
|
24
|
+
# rotator.secure_compare!(password)
|
25
|
+
# rescue ActiveSupport::SecureCompareRotator::InvalidMatch
|
26
|
+
# false
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
class SecureCompareRotator
|
31
|
+
include SecurityUtils
|
32
|
+
prepend Messages::Rotator
|
33
|
+
|
34
|
+
InvalidMatch = Class.new(StandardError)
|
35
|
+
|
36
|
+
def initialize(value, **_options)
|
37
|
+
@value = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def secure_compare!(other_value, on_rotation: @on_rotation)
|
41
|
+
secure_compare(@value, other_value) ||
|
42
|
+
run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
|
43
|
+
raise(InvalidMatch)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def build_rotation(previous_value, _options)
|
48
|
+
self.class.new(previous_value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
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.length == b.length && fixed_length_secure_compare(a, b)
|
28
35
|
end
|
29
36
|
module_function :secure_compare
|
30
37
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
|
+
|
3
5
|
module ActiveSupport
|
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
|
@@ -18,13 +20,12 @@ module ActiveSupport
|
|
18
20
|
# vehicle.bike? # => false
|
19
21
|
class StringInquirer < String
|
20
22
|
private
|
21
|
-
|
22
23
|
def respond_to_missing?(method_name, include_private = false)
|
23
|
-
(
|
24
|
+
method_name.end_with?("?") || super
|
24
25
|
end
|
25
26
|
|
26
27
|
def method_missing(method_name, *arguments)
|
27
|
-
if method_name
|
28
|
+
if method_name.end_with?("?")
|
28
29
|
self == method_name[0..-2]
|
29
30
|
else
|
30
31
|
super
|
@@ -24,22 +24,46 @@ module ActiveSupport
|
|
24
24
|
# After configured, whenever a "sql.active_record" notification is published,
|
25
25
|
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
|
26
26
|
# the +sql+ method.
|
27
|
+
#
|
28
|
+
# We can detach a subscriber as well:
|
29
|
+
#
|
30
|
+
# ActiveRecord::StatsSubscriber.detach_from(:active_record)
|
27
31
|
class Subscriber
|
28
32
|
class << self
|
29
33
|
# Attach the subscriber to a namespace.
|
30
|
-
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications)
|
34
|
+
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
|
31
35
|
@namespace = namespace
|
32
36
|
@subscriber = subscriber
|
33
37
|
@notifier = notifier
|
38
|
+
@inherit_all = inherit_all
|
34
39
|
|
35
40
|
subscribers << subscriber
|
36
41
|
|
37
42
|
# Add event subscribers for all existing methods on the class.
|
38
|
-
subscriber
|
43
|
+
fetch_public_methods(subscriber, inherit_all).each do |event|
|
39
44
|
add_event_subscriber(event)
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
48
|
+
# Detach the subscriber from a namespace.
|
49
|
+
def detach_from(namespace, notifier = ActiveSupport::Notifications)
|
50
|
+
@namespace = namespace
|
51
|
+
@subscriber = find_attached_subscriber
|
52
|
+
@notifier = notifier
|
53
|
+
|
54
|
+
return unless subscriber
|
55
|
+
|
56
|
+
subscribers.delete(subscriber)
|
57
|
+
|
58
|
+
# Remove event subscribers of all existing methods on the class.
|
59
|
+
fetch_public_methods(subscriber, true).each do |event|
|
60
|
+
remove_event_subscriber(event)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Reset notifier so that event subscribers will not add for new methods added to the class.
|
64
|
+
@notifier = nil
|
65
|
+
end
|
66
|
+
|
43
67
|
# Adds event subscribers for all new methods added to the class.
|
44
68
|
def method_added(event)
|
45
69
|
# Only public methods are added as subscribers, and only if a notifier
|
@@ -54,62 +78,82 @@ module ActiveSupport
|
|
54
78
|
@@subscribers ||= []
|
55
79
|
end
|
56
80
|
|
57
|
-
|
58
|
-
|
59
|
-
|
81
|
+
private
|
82
|
+
attr_reader :subscriber, :notifier, :namespace
|
83
|
+
|
84
|
+
def add_event_subscriber(event) # :doc:
|
85
|
+
return if invalid_event?(event)
|
60
86
|
|
61
|
-
|
87
|
+
pattern = prepare_pattern(event)
|
62
88
|
|
63
|
-
|
89
|
+
# Don't add multiple subscribers (e.g. if methods are redefined).
|
90
|
+
return if pattern_subscribed?(pattern)
|
64
91
|
|
65
|
-
|
66
|
-
|
92
|
+
subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
|
93
|
+
end
|
67
94
|
|
68
|
-
|
95
|
+
def remove_event_subscriber(event) # :doc:
|
96
|
+
return if invalid_event?(event)
|
69
97
|
|
70
|
-
|
71
|
-
return if subscriber.patterns.include?(pattern)
|
98
|
+
pattern = prepare_pattern(event)
|
72
99
|
|
73
|
-
|
74
|
-
|
75
|
-
|
100
|
+
return unless pattern_subscribed?(pattern)
|
101
|
+
|
102
|
+
notifier.unsubscribe(subscriber.patterns[pattern])
|
103
|
+
subscriber.patterns.delete(pattern)
|
104
|
+
end
|
105
|
+
|
106
|
+
def find_attached_subscriber
|
107
|
+
subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
|
108
|
+
end
|
109
|
+
|
110
|
+
def invalid_event?(event)
|
111
|
+
%i{ start finish }.include?(event.to_sym)
|
112
|
+
end
|
113
|
+
|
114
|
+
def prepare_pattern(event)
|
115
|
+
"#{event}.#{namespace}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def pattern_subscribed?(pattern)
|
119
|
+
subscriber.patterns.key?(pattern)
|
120
|
+
end
|
121
|
+
|
122
|
+
def fetch_public_methods(subscriber, inherit_all)
|
123
|
+
subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
|
124
|
+
end
|
76
125
|
end
|
77
126
|
|
78
127
|
attr_reader :patterns # :nodoc:
|
79
128
|
|
80
129
|
def initialize
|
81
130
|
@queue_key = [self.class.name, object_id].join "-"
|
82
|
-
@patterns =
|
131
|
+
@patterns = {}
|
83
132
|
super
|
84
133
|
end
|
85
134
|
|
86
135
|
def start(name, id, payload)
|
87
|
-
|
136
|
+
event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
|
137
|
+
event.start!
|
88
138
|
parent = event_stack.last
|
89
|
-
parent <<
|
139
|
+
parent << event if parent
|
90
140
|
|
91
|
-
event_stack.push
|
141
|
+
event_stack.push event
|
92
142
|
end
|
93
143
|
|
94
144
|
def finish(name, id, payload)
|
95
|
-
|
96
|
-
event
|
97
|
-
event.end = finished
|
145
|
+
event = event_stack.pop
|
146
|
+
event.finish!
|
98
147
|
event.payload.merge!(payload)
|
99
148
|
|
100
|
-
method = name.split("."
|
149
|
+
method = name.split(".").first
|
101
150
|
send(method, event)
|
102
151
|
end
|
103
152
|
|
104
153
|
private
|
105
|
-
|
106
154
|
def event_stack
|
107
155
|
SubscriberQueueRegistry.instance.get_queue(@queue_key)
|
108
156
|
end
|
109
|
-
|
110
|
-
def now
|
111
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
112
|
-
end
|
113
157
|
end
|
114
158
|
|
115
159
|
# This is a registry for all the event stacks kept for subscribers.
|
@@ -8,11 +8,20 @@ require "active_support/logger"
|
|
8
8
|
module ActiveSupport
|
9
9
|
# Wraps any standard Logger object to provide tagging capabilities.
|
10
10
|
#
|
11
|
+
# May be called with a block:
|
12
|
+
#
|
11
13
|
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
12
14
|
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
|
13
15
|
# logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
|
14
16
|
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
|
15
17
|
#
|
18
|
+
# If called without a block, a new logger will be returned with applied tags:
|
19
|
+
#
|
20
|
+
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
21
|
+
# logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
|
22
|
+
# logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
23
|
+
# logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
24
|
+
#
|
16
25
|
# This is used by the default Rails.logger as configured by Railties to make
|
17
26
|
# it easy to stamp log lines with subdomains, request ids, and anything else
|
18
27
|
# to aid debugging of multi-user production applications.
|
@@ -31,9 +40,10 @@ module ActiveSupport
|
|
31
40
|
end
|
32
41
|
|
33
42
|
def push_tags(*tags)
|
34
|
-
tags.flatten
|
35
|
-
|
36
|
-
|
43
|
+
tags.flatten!
|
44
|
+
tags.reject!(&:blank?)
|
45
|
+
current_tags.concat tags
|
46
|
+
tags
|
37
47
|
end
|
38
48
|
|
39
49
|
def pop_tags(size = 1)
|
@@ -46,21 +56,38 @@ module ActiveSupport
|
|
46
56
|
|
47
57
|
def current_tags
|
48
58
|
# We use our object ID here to avoid conflicting with other instances
|
49
|
-
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
|
59
|
+
thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
|
50
60
|
Thread.current[thread_key] ||= []
|
51
61
|
end
|
52
62
|
|
53
63
|
def tags_text
|
54
64
|
tags = current_tags
|
55
|
-
if tags.
|
65
|
+
if tags.one?
|
66
|
+
"[#{tags[0]}] "
|
67
|
+
elsif tags.any?
|
56
68
|
tags.collect { |tag| "[#{tag}] " }.join
|
57
69
|
end
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
73
|
+
module LocalTagStorage # :nodoc:
|
74
|
+
attr_accessor :current_tags
|
75
|
+
|
76
|
+
def self.extended(base)
|
77
|
+
base.current_tags = []
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
61
81
|
def self.new(logger)
|
62
|
-
|
63
|
-
|
82
|
+
logger = logger.dup
|
83
|
+
|
84
|
+
if logger.formatter
|
85
|
+
logger.formatter = logger.formatter.dup
|
86
|
+
else
|
87
|
+
# Ensure we set a default formatter so we aren't extending nil!
|
88
|
+
logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
|
89
|
+
end
|
90
|
+
|
64
91
|
logger.formatter.extend Formatter
|
65
92
|
logger.extend(self)
|
66
93
|
end
|
@@ -68,7 +95,14 @@ module ActiveSupport
|
|
68
95
|
delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
|
69
96
|
|
70
97
|
def tagged(*tags)
|
71
|
-
|
98
|
+
if block_given?
|
99
|
+
formatter.tagged(*tags) { yield self }
|
100
|
+
else
|
101
|
+
logger = ActiveSupport::TaggedLogging.new(self)
|
102
|
+
logger.formatter.extend LocalTagStorage
|
103
|
+
logger.push_tags(*formatter.current_tags, *tags)
|
104
|
+
logger
|
105
|
+
end
|
72
106
|
end
|
73
107
|
|
74
108
|
def flush
|