activesupport 7.2.2.1 → 8.1.3
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 +422 -145
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +73 -2
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +14 -4
- data/lib/active_support/cache/mem_cache_store.rb +30 -29
- data/lib/active_support/cache/memory_store.rb +11 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +43 -34
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +88 -20
- data/lib/active_support/callbacks.rb +28 -13
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +0 -15
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +26 -20
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +5 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/securerandom.rb +24 -8
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +12 -3
- data/lib/active_support/core_ext/string/output_safety.rb +29 -13
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +7 -2
- data/lib/active_support/core_ext/time/compatibility.rb +2 -19
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +27 -17
- data/lib/active_support/delegation.rb +25 -44
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/reporting.rb +4 -21
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +14 -10
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +81 -4
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -2
- data/lib/active_support/execution_context.rb +75 -7
- data/lib/active_support/execution_wrapper.rb +1 -1
- data/lib/active_support/file_update_checker.rb +8 -6
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +61 -38
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +34 -16
- data/lib/active_support/inflector/methods.rb +3 -3
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +17 -17
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +159 -21
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -6
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +6 -1
- data/lib/active_support/message_verifier.rb +9 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +12 -2
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +64 -43
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/railtie.rb +32 -9
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +0 -5
- data/lib/active_support/syntax_error_proxy.rb +7 -0
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/test_case.rb +67 -6
- data/lib/active_support/testing/assertions.rb +118 -27
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +17 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +15 -2
- data/lib/active_support/testing/parallelization/worker.rb +9 -3
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +9 -4
- data/lib/active_support/time_with_zone.rb +36 -23
- data/lib/active_support/values/time_zone.rb +19 -10
- data/lib/active_support/xml_mini.rb +3 -2
- data/lib/active_support.rb +21 -9
- metadata +35 -16
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/proxy_object.rb +0 -20
- data/lib/active_support/testing/strict_warnings.rb +0 -43
data/README.rdoc
CHANGED
|
@@ -35,6 +35,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
|
|
|
35
35
|
|
|
36
36
|
* https://github.com/rails/rails/issues
|
|
37
37
|
|
|
38
|
-
Feature requests should be discussed on the
|
|
38
|
+
Feature requests should be discussed on the rubyonrails-core forum here:
|
|
39
39
|
|
|
40
40
|
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
|
18
18
|
#
|
|
19
19
|
# bc = ActiveSupport::BacktraceCleaner.new
|
|
20
20
|
# root = "#{Rails.root}/"
|
|
21
|
-
# bc.add_filter { |line| line.
|
|
21
|
+
# bc.add_filter { |line| line.delete_prefix(root) } # strip the Rails.root prefix
|
|
22
22
|
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
|
23
23
|
# bc.clean(exception.backtrace) # perform the cleanup
|
|
24
24
|
#
|
|
@@ -56,6 +56,18 @@ module ActiveSupport
|
|
|
56
56
|
end
|
|
57
57
|
alias :filter :clean
|
|
58
58
|
|
|
59
|
+
# Given an array of Thread::Backtrace::Location objects, returns an array
|
|
60
|
+
# with the clean ones:
|
|
61
|
+
#
|
|
62
|
+
# clean_locations = backtrace_cleaner.clean_locations(caller_locations)
|
|
63
|
+
#
|
|
64
|
+
# Filters and silencers receive strings as usual. However, the +path+
|
|
65
|
+
# attributes of the locations in the returned array are the original,
|
|
66
|
+
# unfiltered ones, since locations are immutable.
|
|
67
|
+
def clean_locations(locations, kind = :silent)
|
|
68
|
+
locations.select { |location| clean_frame(location, kind) }
|
|
69
|
+
end
|
|
70
|
+
|
|
59
71
|
# Returns the frame with all filters applied.
|
|
60
72
|
# returns +nil+ if the frame was silenced.
|
|
61
73
|
def clean_frame(frame, kind = :silent)
|
|
@@ -74,12 +86,71 @@ module ActiveSupport
|
|
|
74
86
|
end
|
|
75
87
|
end
|
|
76
88
|
|
|
89
|
+
# Thread.each_caller_location does not accept a start in Ruby < 3.4.
|
|
90
|
+
if Thread.method(:each_caller_location).arity == 0
|
|
91
|
+
# Returns the first clean frame of the caller's backtrace, or +nil+.
|
|
92
|
+
#
|
|
93
|
+
# Frames are strings.
|
|
94
|
+
def first_clean_frame(kind = :silent)
|
|
95
|
+
caller_location_skipped = false
|
|
96
|
+
|
|
97
|
+
Thread.each_caller_location do |location|
|
|
98
|
+
unless caller_location_skipped
|
|
99
|
+
caller_location_skipped = true
|
|
100
|
+
next
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
frame = clean_frame(location, kind)
|
|
104
|
+
return frame if frame
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Returns the first clean location of the caller's call stack, or +nil+.
|
|
109
|
+
#
|
|
110
|
+
# Locations are Thread::Backtrace::Location objects. Since they are
|
|
111
|
+
# immutable, their +path+ attributes are the original ones, but filters
|
|
112
|
+
# are applied internally so silencers can still rely on them.
|
|
113
|
+
def first_clean_location(kind = :silent)
|
|
114
|
+
caller_location_skipped = false
|
|
115
|
+
|
|
116
|
+
Thread.each_caller_location do |location|
|
|
117
|
+
unless caller_location_skipped
|
|
118
|
+
caller_location_skipped = true
|
|
119
|
+
next
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
return location if clean_frame(location, kind)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
# Returns the first clean frame of the caller's backtrace, or +nil+.
|
|
127
|
+
#
|
|
128
|
+
# Frames are strings.
|
|
129
|
+
def first_clean_frame(kind = :silent)
|
|
130
|
+
Thread.each_caller_location(2) do |location|
|
|
131
|
+
frame = clean_frame(location, kind)
|
|
132
|
+
return frame if frame
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Returns the first clean location of the caller's call stack, or +nil+.
|
|
137
|
+
#
|
|
138
|
+
# Locations are Thread::Backtrace::Location objects. Since they are
|
|
139
|
+
# immutable, their +path+ attributes are the original ones, but filters
|
|
140
|
+
# are applied internally so silencers can still rely on them.
|
|
141
|
+
def first_clean_location(kind = :silent)
|
|
142
|
+
Thread.each_caller_location(2) do |location|
|
|
143
|
+
return location if clean_frame(location, kind)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
77
148
|
# Adds a filter from the block provided. Each line in the backtrace will be
|
|
78
149
|
# mapped against this filter.
|
|
79
150
|
#
|
|
80
151
|
# # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
|
|
81
152
|
# root = "#{Rails.root}/"
|
|
82
|
-
# backtrace_cleaner.add_filter { |line| line.
|
|
153
|
+
# backtrace_cleaner.add_filter { |line| line.delete_prefix(root) }
|
|
83
154
|
def add_filter(&block)
|
|
84
155
|
@filters << block
|
|
85
156
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module Benchmark # :nodoc:
|
|
5
|
+
# Benchmark realtime in the specified time unit. By default,
|
|
6
|
+
# the returned unit is in seconds.
|
|
7
|
+
#
|
|
8
|
+
# ActiveSupport::Benchmark.realtime { sleep 0.1 }
|
|
9
|
+
# # => 0.10007
|
|
10
|
+
#
|
|
11
|
+
# ActiveSupport::Benchmark.realtime(:float_millisecond) { sleep 0.1 }
|
|
12
|
+
# # => 100.07
|
|
13
|
+
#
|
|
14
|
+
# `unit` can be any of the values accepted by Ruby's `Process.clock_gettime`.
|
|
15
|
+
def self.realtime(unit = :float_second, &block)
|
|
16
|
+
time_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
|
|
17
|
+
yield
|
|
18
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, unit) - time_start
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/core_ext/benchmark"
|
|
4
3
|
require "active_support/core_ext/hash/keys"
|
|
5
4
|
|
|
6
5
|
module ActiveSupport
|
|
@@ -41,7 +40,9 @@ module ActiveSupport
|
|
|
41
40
|
options[:level] ||= :info
|
|
42
41
|
|
|
43
42
|
result = nil
|
|
44
|
-
ms = Benchmark.
|
|
43
|
+
ms = ActiveSupport::Benchmark.realtime(:float_millisecond) do
|
|
44
|
+
result = options[:silence] ? logger.silence(&block) : yield
|
|
45
|
+
end
|
|
45
46
|
logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
|
|
46
47
|
result
|
|
47
48
|
else
|
|
@@ -76,7 +76,6 @@ module ActiveSupport
|
|
|
76
76
|
|
|
77
77
|
# Returns all the logger that are part of this broadcast.
|
|
78
78
|
attr_reader :broadcasts
|
|
79
|
-
attr_reader :formatter
|
|
80
79
|
attr_accessor :progname
|
|
81
80
|
|
|
82
81
|
def initialize(*loggers)
|
|
@@ -105,131 +104,119 @@ module ActiveSupport
|
|
|
105
104
|
@broadcasts.delete(logger)
|
|
106
105
|
end
|
|
107
106
|
|
|
108
|
-
def level
|
|
109
|
-
@broadcasts.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def <<(message)
|
|
113
|
-
dispatch { |logger| logger.<<(message) }
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def add(...)
|
|
117
|
-
dispatch { |logger| logger.add(...) }
|
|
118
|
-
end
|
|
119
|
-
alias_method :log, :add
|
|
120
|
-
|
|
121
|
-
def debug(...)
|
|
122
|
-
dispatch { |logger| logger.debug(...) }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def info(...)
|
|
126
|
-
dispatch { |logger| logger.info(...) }
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def warn(...)
|
|
130
|
-
dispatch { |logger| logger.warn(...) }
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def error(...)
|
|
134
|
-
dispatch { |logger| logger.error(...) }
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def fatal(...)
|
|
138
|
-
dispatch { |logger| logger.fatal(...) }
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def unknown(...)
|
|
142
|
-
dispatch { |logger| logger.unknown(...) }
|
|
107
|
+
def local_level=(level)
|
|
108
|
+
@broadcasts.each do |logger|
|
|
109
|
+
logger.local_level = level if logger.respond_to?(:local_level=)
|
|
110
|
+
end
|
|
143
111
|
end
|
|
144
112
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
@formatter = formatter
|
|
149
|
-
end
|
|
113
|
+
def local_level
|
|
114
|
+
loggers = @broadcasts.select { |logger| logger.respond_to?(:local_level) }
|
|
150
115
|
|
|
151
|
-
|
|
152
|
-
|
|
116
|
+
loggers.map do |logger|
|
|
117
|
+
logger.local_level
|
|
118
|
+
end.first
|
|
153
119
|
end
|
|
154
|
-
alias_method :sev_threshold=, :level=
|
|
155
120
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
121
|
+
LOGGER_METHODS = %w[
|
|
122
|
+
<< log add debug info warn error fatal unknown
|
|
123
|
+
level= sev_threshold= close
|
|
124
|
+
formatter formatter=
|
|
125
|
+
] # :nodoc:
|
|
126
|
+
LOGGER_METHODS.each do |method|
|
|
127
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
128
|
+
def #{method}(...)
|
|
129
|
+
dispatch(:#{method}, ...)
|
|
130
|
+
end
|
|
131
|
+
RUBY
|
|
160
132
|
end
|
|
161
133
|
|
|
162
|
-
|
|
163
|
-
|
|
134
|
+
# Returns the lowest level of all the loggers in the broadcast.
|
|
135
|
+
def level
|
|
136
|
+
@broadcasts.map(&:level).min
|
|
164
137
|
end
|
|
165
138
|
|
|
166
|
-
#
|
|
167
|
-
# to at least one broadcast.
|
|
139
|
+
# True if the log level allows entries with severity +Logger::DEBUG+ to be written
|
|
140
|
+
# to at least one broadcast. False otherwise.
|
|
168
141
|
def debug?
|
|
169
142
|
@broadcasts.any? { |logger| logger.debug? }
|
|
170
143
|
end
|
|
171
144
|
|
|
172
|
-
# Sets the log level to Logger::DEBUG for the whole broadcast.
|
|
145
|
+
# Sets the log level to +Logger::DEBUG+ for the whole broadcast.
|
|
173
146
|
def debug!
|
|
174
|
-
dispatch
|
|
147
|
+
dispatch(:debug!)
|
|
175
148
|
end
|
|
176
149
|
|
|
177
|
-
#
|
|
178
|
-
# to at least one broadcast.
|
|
150
|
+
# True if the log level allows entries with severity +Logger::INFO+ to be written
|
|
151
|
+
# to at least one broadcast. False otherwise.
|
|
179
152
|
def info?
|
|
180
153
|
@broadcasts.any? { |logger| logger.info? }
|
|
181
154
|
end
|
|
182
155
|
|
|
183
|
-
# Sets the log level to Logger::INFO for the whole broadcast.
|
|
156
|
+
# Sets the log level to +Logger::INFO+ for the whole broadcast.
|
|
184
157
|
def info!
|
|
185
|
-
dispatch
|
|
158
|
+
dispatch(:info!)
|
|
186
159
|
end
|
|
187
160
|
|
|
188
|
-
#
|
|
189
|
-
# to at least one broadcast.
|
|
161
|
+
# True if the log level allows entries with severity +Logger::WARN+ to be written
|
|
162
|
+
# to at least one broadcast. False otherwise.
|
|
190
163
|
def warn?
|
|
191
164
|
@broadcasts.any? { |logger| logger.warn? }
|
|
192
165
|
end
|
|
193
166
|
|
|
194
|
-
# Sets the log level to Logger::WARN for the whole broadcast.
|
|
167
|
+
# Sets the log level to +Logger::WARN+ for the whole broadcast.
|
|
195
168
|
def warn!
|
|
196
|
-
dispatch
|
|
169
|
+
dispatch(:warn!)
|
|
197
170
|
end
|
|
198
171
|
|
|
199
|
-
#
|
|
200
|
-
# to at least one broadcast.
|
|
172
|
+
# True if the log level allows entries with severity +Logger::ERROR+ to be written
|
|
173
|
+
# to at least one broadcast. False otherwise.
|
|
201
174
|
def error?
|
|
202
175
|
@broadcasts.any? { |logger| logger.error? }
|
|
203
176
|
end
|
|
204
177
|
|
|
205
|
-
# Sets the log level to Logger::ERROR for the whole broadcast.
|
|
178
|
+
# Sets the log level to +Logger::ERROR+ for the whole broadcast.
|
|
206
179
|
def error!
|
|
207
|
-
dispatch
|
|
180
|
+
dispatch(:error!)
|
|
208
181
|
end
|
|
209
182
|
|
|
210
|
-
#
|
|
211
|
-
# to at least one broadcast.
|
|
183
|
+
# True if the log level allows entries with severity +Logger::FATAL+ to be written
|
|
184
|
+
# to at least one broadcast. False otherwise.
|
|
212
185
|
def fatal?
|
|
213
186
|
@broadcasts.any? { |logger| logger.fatal? }
|
|
214
187
|
end
|
|
215
188
|
|
|
216
|
-
# Sets the log level to Logger::FATAL for the whole broadcast.
|
|
189
|
+
# Sets the log level to +Logger::FATAL+ for the whole broadcast.
|
|
217
190
|
def fatal!
|
|
218
|
-
dispatch
|
|
191
|
+
dispatch(:fatal!)
|
|
219
192
|
end
|
|
220
193
|
|
|
221
194
|
def initialize_copy(other)
|
|
222
195
|
@broadcasts = []
|
|
223
196
|
@progname = other.progname.dup
|
|
224
|
-
@formatter = other.formatter.dup
|
|
225
197
|
|
|
226
198
|
broadcast_to(*other.broadcasts.map(&:dup))
|
|
227
199
|
end
|
|
228
200
|
|
|
229
201
|
private
|
|
230
|
-
def dispatch(&block)
|
|
231
|
-
|
|
232
|
-
|
|
202
|
+
def dispatch(method, *args, **kwargs, &block)
|
|
203
|
+
if block_given?
|
|
204
|
+
# Maintain semantics that the first logger yields the block
|
|
205
|
+
# as normal, but subsequent loggers won't re-execute the block.
|
|
206
|
+
# Instead, the initial result is immediately returned.
|
|
207
|
+
called, result = false, nil
|
|
208
|
+
block = proc { |*args, **kwargs|
|
|
209
|
+
if called then result
|
|
210
|
+
else
|
|
211
|
+
called = true
|
|
212
|
+
result = yield(*args, **kwargs)
|
|
213
|
+
end
|
|
214
|
+
}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
@broadcasts.map { |logger|
|
|
218
|
+
logger.send(method, *args, **kwargs, &block)
|
|
219
|
+
}.first
|
|
233
220
|
end
|
|
234
221
|
|
|
235
222
|
def method_missing(name, ...)
|
|
@@ -57,8 +57,13 @@ module ActiveSupport
|
|
|
57
57
|
# cache.write("baz", 5)
|
|
58
58
|
# cache.increment("baz") # => 6
|
|
59
59
|
#
|
|
60
|
-
def increment(name, amount = 1, options
|
|
61
|
-
|
|
60
|
+
def increment(name, amount = 1, **options)
|
|
61
|
+
options = merged_options(options)
|
|
62
|
+
key = normalize_key(name, options)
|
|
63
|
+
|
|
64
|
+
instrument(:increment, key, amount: amount) do
|
|
65
|
+
modify_value(name, amount, options)
|
|
66
|
+
end
|
|
62
67
|
end
|
|
63
68
|
|
|
64
69
|
# Decrement a cached integer value. Returns the updated value.
|
|
@@ -72,8 +77,13 @@ module ActiveSupport
|
|
|
72
77
|
# cache.write("baz", 5)
|
|
73
78
|
# cache.decrement("baz") # => 4
|
|
74
79
|
#
|
|
75
|
-
def decrement(name, amount = 1, options
|
|
76
|
-
|
|
80
|
+
def decrement(name, amount = 1, **options)
|
|
81
|
+
options = merged_options(options)
|
|
82
|
+
key = normalize_key(name, options)
|
|
83
|
+
|
|
84
|
+
instrument(:decrement, key, amount: amount) do
|
|
85
|
+
modify_value(name, -amount, options)
|
|
86
|
+
end
|
|
77
87
|
end
|
|
78
88
|
|
|
79
89
|
def delete_matched(matcher, options = nil)
|
|
@@ -41,7 +41,6 @@ module ActiveSupport
|
|
|
41
41
|
|
|
42
42
|
prepend Strategy::LocalCache
|
|
43
43
|
|
|
44
|
-
KEY_MAX_SIZE = 250
|
|
45
44
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
|
46
45
|
|
|
47
46
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
|
@@ -60,7 +59,7 @@ module ActiveSupport
|
|
|
60
59
|
pool_options = retrieve_pool_options(options)
|
|
61
60
|
|
|
62
61
|
if pool_options
|
|
63
|
-
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
|
62
|
+
ConnectionPool.new(**pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
|
64
63
|
else
|
|
65
64
|
Dalli::Client.new(addresses, options)
|
|
66
65
|
end
|
|
@@ -80,6 +79,7 @@ module ActiveSupport
|
|
|
80
79
|
if options.key?(:cache_nils)
|
|
81
80
|
options[:skip_nil] = !options.delete(:cache_nils)
|
|
82
81
|
end
|
|
82
|
+
options[:max_key_size] ||= MAX_KEY_SIZE
|
|
83
83
|
super(options)
|
|
84
84
|
|
|
85
85
|
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
|
@@ -90,6 +90,9 @@ module ActiveSupport
|
|
|
90
90
|
# The value "compress: false" prevents duplicate compression within Dalli.
|
|
91
91
|
@mem_cache_options[:compress] = false
|
|
92
92
|
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
|
93
|
+
# Set the default serializer for Dalli to prevent warning about
|
|
94
|
+
# inheriting the default serializer.
|
|
95
|
+
@mem_cache_options[:serializer] = Marshal
|
|
93
96
|
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
|
94
97
|
end
|
|
95
98
|
|
|
@@ -110,9 +113,6 @@ module ActiveSupport
|
|
|
110
113
|
# * <tt>raw: true</tt> - Sends the value directly to the server as raw
|
|
111
114
|
# bytes. The value must be a string or number. You can use memcached
|
|
112
115
|
# direct operations like +increment+ and +decrement+ only on raw values.
|
|
113
|
-
#
|
|
114
|
-
# * <tt>unless_exist: true</tt> - Prevents overwriting an existing cache
|
|
115
|
-
# entry.
|
|
116
116
|
|
|
117
117
|
# Increment a cached integer value using the memcached incr atomic operator.
|
|
118
118
|
# Returns the updated value.
|
|
@@ -129,6 +129,11 @@ module ActiveSupport
|
|
|
129
129
|
#
|
|
130
130
|
# Incrementing a non-numeric value, or a value written without
|
|
131
131
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
|
132
|
+
#
|
|
133
|
+
# To read the value later, call #read_counter:
|
|
134
|
+
#
|
|
135
|
+
# cache.increment("baz") # => 7
|
|
136
|
+
# cache.read_counter("baz") # 7
|
|
132
137
|
def increment(name, amount = 1, options = nil)
|
|
133
138
|
options = merged_options(options)
|
|
134
139
|
key = normalize_key(name, options)
|
|
@@ -155,6 +160,11 @@ module ActiveSupport
|
|
|
155
160
|
#
|
|
156
161
|
# Decrementing a non-numeric value, or a value written without
|
|
157
162
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
|
163
|
+
#
|
|
164
|
+
# To read the value later, call #read_counter:
|
|
165
|
+
#
|
|
166
|
+
# cache.decrement("baz") # => 3
|
|
167
|
+
# cache.read_counter("baz") # 3
|
|
158
168
|
def decrement(name, amount = 1, options = nil)
|
|
159
169
|
options = merged_options(options)
|
|
160
170
|
key = normalize_key(name, options)
|
|
@@ -212,26 +222,24 @@ module ActiveSupport
|
|
|
212
222
|
def read_multi_entries(names, **options)
|
|
213
223
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
|
214
224
|
|
|
215
|
-
|
|
216
|
-
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
217
|
-
rescue Dalli::UnmarshalError
|
|
218
|
-
{}
|
|
219
|
-
end
|
|
225
|
+
rescue_error_with({}) do
|
|
226
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
220
227
|
|
|
221
|
-
|
|
228
|
+
values = {}
|
|
222
229
|
|
|
223
|
-
|
|
224
|
-
|
|
230
|
+
raw_values.each do |key, value|
|
|
231
|
+
entry = deserialize_entry(value, raw: options[:raw])
|
|
225
232
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
|
234
|
+
begin
|
|
235
|
+
values[keys_to_names[key]] = entry.value
|
|
236
|
+
rescue DeserializationError
|
|
237
|
+
end
|
|
230
238
|
end
|
|
231
239
|
end
|
|
232
|
-
end
|
|
233
240
|
|
|
234
|
-
|
|
241
|
+
values
|
|
242
|
+
end
|
|
235
243
|
end
|
|
236
244
|
|
|
237
245
|
# Delete an entry from the cache.
|
|
@@ -251,19 +259,12 @@ module ActiveSupport
|
|
|
251
259
|
# before applying the regular expression to ensure we are escaping all
|
|
252
260
|
# characters properly.
|
|
253
261
|
def normalize_key(key, options)
|
|
254
|
-
key =
|
|
262
|
+
key = expand_and_namespace_key(key, options)
|
|
255
263
|
if key
|
|
256
264
|
key = key.dup.force_encoding(Encoding::ASCII_8BIT)
|
|
257
265
|
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
|
258
|
-
|
|
259
|
-
if key.size > KEY_MAX_SIZE
|
|
260
|
-
key_separator = ":hash:"
|
|
261
|
-
key_hash = ActiveSupport::Digest.hexdigest(key)
|
|
262
|
-
key_trim_size = KEY_MAX_SIZE - key_separator.size - key_hash.size
|
|
263
|
-
key = "#{key[0, key_trim_size]}#{key_separator}#{key_hash}"
|
|
264
|
-
end
|
|
265
266
|
end
|
|
266
|
-
key
|
|
267
|
+
truncate_key(key)
|
|
267
268
|
end
|
|
268
269
|
|
|
269
270
|
def deserialize_entry(payload, raw: false, **)
|
|
@@ -276,7 +277,7 @@ module ActiveSupport
|
|
|
276
277
|
|
|
277
278
|
def rescue_error_with(fallback)
|
|
278
279
|
yield
|
|
279
|
-
rescue Dalli::DalliError => error
|
|
280
|
+
rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
|
|
280
281
|
logger.error("DalliError (#{error}): #{error.message}") if logger
|
|
281
282
|
ActiveSupport.error_reporter&.report(
|
|
282
283
|
error,
|
|
@@ -26,6 +26,8 @@ module ActiveSupport
|
|
|
26
26
|
#
|
|
27
27
|
# +MemoryStore+ is thread-safe.
|
|
28
28
|
class MemoryStore < Store
|
|
29
|
+
prepend Strategy::LocalCache
|
|
30
|
+
|
|
29
31
|
module DupCoder # :nodoc:
|
|
30
32
|
extend self
|
|
31
33
|
|
|
@@ -146,8 +148,10 @@ module ActiveSupport
|
|
|
146
148
|
# cache.write("baz", 5)
|
|
147
149
|
# cache.increment("baz") # => 6
|
|
148
150
|
#
|
|
149
|
-
def increment(name, amount = 1, options
|
|
150
|
-
|
|
151
|
+
def increment(name, amount = 1, **options)
|
|
152
|
+
instrument(:increment, name, amount: amount) do
|
|
153
|
+
modify_value(name, amount, **options)
|
|
154
|
+
end
|
|
151
155
|
end
|
|
152
156
|
|
|
153
157
|
# Decrement a cached integer value. Returns the updated value.
|
|
@@ -161,8 +165,10 @@ module ActiveSupport
|
|
|
161
165
|
# cache.write("baz", 5)
|
|
162
166
|
# cache.decrement("baz") # => 4
|
|
163
167
|
#
|
|
164
|
-
def decrement(name, amount = 1, options
|
|
165
|
-
|
|
168
|
+
def decrement(name, amount = 1, **options)
|
|
169
|
+
instrument(:decrement, name, amount: amount) do
|
|
170
|
+
modify_value(name, -amount, **options)
|
|
171
|
+
end
|
|
166
172
|
end
|
|
167
173
|
|
|
168
174
|
# Deletes cache entries if the cache key matches a given pattern.
|
|
@@ -234,7 +240,7 @@ module ActiveSupport
|
|
|
234
240
|
|
|
235
241
|
# Modifies the amount of an integer value that is stored in the cache.
|
|
236
242
|
# If the key is not found it is created and set to +amount+.
|
|
237
|
-
def modify_value(name, amount, options)
|
|
243
|
+
def modify_value(name, amount, **options)
|
|
238
244
|
options = merged_options(options)
|
|
239
245
|
key = normalize_key(name, options)
|
|
240
246
|
version = normalize_version(name, options)
|
|
@@ -25,10 +25,10 @@ module ActiveSupport
|
|
|
25
25
|
def cleanup(options = nil)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def increment(name, amount = 1, options
|
|
28
|
+
def increment(name, amount = 1, **options)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def decrement(name, amount = 1, options
|
|
31
|
+
def decrement(name, amount = 1, **options)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def delete_matched(matcher, options = nil)
|