appsignal 4.5.16-java → 4.6.0-java
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 +49 -0
- data/CLAUDE.md +177 -0
- data/README.md +17 -0
- data/appsignal.gemspec +1 -0
- data/build_matrix.yml +29 -0
- data/lib/appsignal/auth_check.rb +3 -3
- data/lib/appsignal/check_in/cron.rb +1 -1
- data/lib/appsignal/check_in/event.rb +1 -1
- data/lib/appsignal/check_in/scheduler.rb +3 -1
- data/lib/appsignal/check_in.rb +9 -6
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/cli.rb +1 -1
- data/lib/appsignal/config.rb +231 -30
- data/lib/appsignal/custom_marker.rb +3 -3
- data/lib/appsignal/environment.rb +7 -1
- data/lib/appsignal/event_formatter/action_view/render_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/faraday/request_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/sequel/sql_formatter.rb +1 -1
- data/lib/appsignal/event_formatter/view_component/render_formatter.rb +1 -1
- data/lib/appsignal/event_formatter.rb +41 -3
- data/lib/appsignal/extension.rb +1 -1
- data/lib/appsignal/garbage_collection.rb +1 -1
- data/lib/appsignal/helpers/instrumentation.rb +82 -35
- data/lib/appsignal/helpers/metrics.rb +12 -9
- data/lib/appsignal/hooks/action_cable.rb +1 -1
- data/lib/appsignal/hooks/action_mailer.rb +1 -0
- data/lib/appsignal/hooks/active_job.rb +1 -1
- data/lib/appsignal/hooks/active_support_notifications.rb +1 -1
- data/lib/appsignal/hooks/at_exit.rb +1 -1
- data/lib/appsignal/hooks/celluloid.rb +1 -1
- data/lib/appsignal/hooks/data_mapper.rb +1 -1
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/dry_monitor.rb +1 -1
- data/lib/appsignal/hooks/excon.rb +1 -1
- data/lib/appsignal/hooks/gvl.rb +1 -1
- data/lib/appsignal/hooks/http.rb +1 -1
- data/lib/appsignal/hooks/mongo_ruby_driver.rb +1 -1
- data/lib/appsignal/hooks/mri.rb +1 -1
- data/lib/appsignal/hooks/net_http.rb +1 -1
- data/lib/appsignal/hooks/ownership.rb +1 -1
- data/lib/appsignal/hooks/passenger.rb +1 -1
- data/lib/appsignal/hooks/puma.rb +1 -1
- data/lib/appsignal/hooks/que.rb +1 -1
- data/lib/appsignal/hooks/rake.rb +1 -1
- data/lib/appsignal/hooks/redis.rb +1 -1
- data/lib/appsignal/hooks/redis_client.rb +1 -1
- data/lib/appsignal/hooks/resque.rb +1 -1
- data/lib/appsignal/hooks/sequel.rb +2 -1
- data/lib/appsignal/hooks/shoryuken.rb +1 -1
- data/lib/appsignal/hooks/sidekiq.rb +1 -0
- data/lib/appsignal/hooks/unicorn.rb +1 -1
- data/lib/appsignal/hooks/webmachine.rb +1 -1
- data/lib/appsignal/hooks.rb +5 -3
- data/lib/appsignal/integrations/action_cable.rb +1 -1
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -1
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +1 -1
- data/lib/appsignal/integrations/data_mapper.rb +1 -1
- data/lib/appsignal/integrations/delayed_job_plugin.rb +1 -1
- data/lib/appsignal/integrations/dry_monitor.rb +1 -1
- data/lib/appsignal/integrations/excon.rb +1 -1
- data/lib/appsignal/integrations/http.rb +1 -1
- data/lib/appsignal/integrations/mongo_ruby_driver.rb +1 -1
- data/lib/appsignal/integrations/net_http.rb +1 -1
- data/lib/appsignal/integrations/object.rb +18 -2
- data/lib/appsignal/integrations/ownership.rb +1 -1
- data/lib/appsignal/integrations/puma.rb +1 -1
- data/lib/appsignal/integrations/que.rb +1 -1
- data/lib/appsignal/integrations/railtie.rb +2 -2
- data/lib/appsignal/integrations/rake.rb +2 -2
- data/lib/appsignal/integrations/redis.rb +1 -1
- data/lib/appsignal/integrations/redis_client.rb +1 -1
- data/lib/appsignal/integrations/resque.rb +2 -2
- data/lib/appsignal/integrations/shoryuken.rb +1 -1
- data/lib/appsignal/integrations/sidekiq.rb +3 -3
- data/lib/appsignal/integrations/unicorn.rb +1 -1
- data/lib/appsignal/integrations/webmachine.rb +1 -1
- data/lib/appsignal/internal_errors.rb +2 -2
- data/lib/appsignal/loaders.rb +1 -1
- data/lib/appsignal/logger.rb +120 -79
- data/lib/appsignal/marker.rb +1 -1
- data/lib/appsignal/probes/gvl.rb +4 -3
- data/lib/appsignal/probes/helpers.rb +1 -1
- data/lib/appsignal/probes/mri.rb +3 -3
- data/lib/appsignal/probes/sidekiq.rb +4 -3
- data/lib/appsignal/probes.rb +20 -15
- data/lib/appsignal/rack/body_wrapper.rb +1 -1
- data/lib/appsignal/rack.rb +1 -1
- data/lib/appsignal/sample_data.rb +31 -12
- data/lib/appsignal/span.rb +1 -1
- data/lib/appsignal/system.rb +9 -8
- data/lib/appsignal/transaction.rb +72 -52
- data/lib/appsignal/transmitter.rb +1 -1
- data/lib/appsignal/utils.rb +1 -1
- data/lib/appsignal/version.rb +2 -1
- data/lib/appsignal.rb +22 -14
- data/lib/puma/plugin/appsignal.rb +1 -1
- data/sig/appsignal.rbi +2599 -0
- data/sig/appsignal.rbs +2420 -0
- metadata +20 -6
data/lib/appsignal/logger.rb
CHANGED
@@ -9,9 +9,50 @@ module Appsignal
|
|
9
9
|
# @see https://docs.appsignal.com/logging/platforms/integrations/ruby.html
|
10
10
|
# AppSignal Ruby logging documentation.
|
11
11
|
class Logger < ::Logger
|
12
|
+
# A wrapper for a block that ensures it is only called once.
|
13
|
+
# If called again, it will return the result of the first call.
|
14
|
+
# This is useful for ensuring that a block is not executed multiple
|
15
|
+
# times when it is broadcasted to multiple loggers.
|
16
|
+
#
|
17
|
+
# @!visibility private
|
18
|
+
class BlockOnce
|
19
|
+
def initialize(&block)
|
20
|
+
@block = block
|
21
|
+
@called = false
|
22
|
+
@success = nil
|
23
|
+
@result = nil
|
24
|
+
@error = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(*args, **kwargs)
|
28
|
+
if @called
|
29
|
+
return @result if @success
|
30
|
+
|
31
|
+
raise @error
|
32
|
+
end
|
33
|
+
|
34
|
+
@called = true
|
35
|
+
@result = @block.call(*args, **kwargs)
|
36
|
+
@success = true
|
37
|
+
@result
|
38
|
+
rescue StandardError => e
|
39
|
+
@success = false
|
40
|
+
@error = e
|
41
|
+
raise @error
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_proc
|
45
|
+
method(:call).to_proc
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @!visibility private
|
12
50
|
PLAINTEXT = 0
|
51
|
+
# @!visibility private
|
13
52
|
LOGFMT = 1
|
53
|
+
# @!visibility private
|
14
54
|
JSON = 2
|
55
|
+
# @!visibility private
|
15
56
|
SEVERITY_MAP = {
|
16
57
|
DEBUG => 2,
|
17
58
|
INFO => 3,
|
@@ -20,30 +61,34 @@ module Appsignal
|
|
20
61
|
FATAL => 7
|
21
62
|
}.freeze
|
22
63
|
|
64
|
+
# Logging severity threshold
|
65
|
+
# @return [Integer]
|
23
66
|
attr_reader :level
|
24
67
|
|
25
68
|
# Create a new logger instance
|
26
69
|
#
|
27
|
-
# @param group Name of the group for this logger.
|
28
|
-
# @param level Minimum log level to report. Log lines below this
|
29
|
-
#
|
30
|
-
# @param
|
70
|
+
# @param group [String] Name of the group for this logger.
|
71
|
+
# @param level [Integer] Minimum log level to report. Log lines below this
|
72
|
+
# level will be ignored.
|
73
|
+
# @param format [Integer] Format to use to parse log line attributes.
|
74
|
+
# @param attributes [Hash<String, String>] Default attributes for all log lines.
|
31
75
|
# @return [void]
|
32
76
|
def initialize(group, level: INFO, format: PLAINTEXT, attributes: {})
|
33
77
|
raise TypeError, "group must be a string" unless group.is_a? String
|
34
78
|
|
35
79
|
@group = group
|
36
80
|
@level = level
|
81
|
+
@silenced = false
|
37
82
|
@format = format
|
38
83
|
@mutex = Mutex.new
|
39
84
|
@default_attributes = attributes
|
40
|
-
@appsignal_attributes =
|
85
|
+
@appsignal_attributes = attributes
|
41
86
|
@loggers = []
|
42
87
|
end
|
43
88
|
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
89
|
+
# Sets the formatter for this logger and all broadcasted loggers.
|
90
|
+
# @param formatter [Proc] The formatter to use for log messages.
|
91
|
+
# @return [Proc]
|
47
92
|
def formatter=(formatter)
|
48
93
|
super
|
49
94
|
@loggers.each { |logger| logger.formatter = formatter }
|
@@ -51,33 +96,44 @@ module Appsignal
|
|
51
96
|
|
52
97
|
# We support the various methods in the Ruby
|
53
98
|
# logger class by supplying this method.
|
54
|
-
#
|
55
|
-
def add(severity, message = nil, group = nil)
|
99
|
+
# @!visibility private
|
100
|
+
def add(severity, message = nil, group = nil, &block) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
101
|
+
# If we do not need to broadcast to any loggers and the severity is
|
102
|
+
# below the log level, we can return early.
|
56
103
|
severity ||= UNKNOWN
|
57
|
-
return true if severity < level
|
104
|
+
return true if severity < level && @loggers.empty?
|
105
|
+
|
106
|
+
# If the logger is silenced, we do not log *or broadcast* messages
|
107
|
+
# below the log level.
|
108
|
+
return true if @silenced && severity < @level
|
109
|
+
|
110
|
+
# Ensure that the block is only run once, even if several loggers
|
111
|
+
# are being broadcasted to.
|
112
|
+
block = BlockOnce.new(&block) unless block.nil?
|
58
113
|
|
114
|
+
# If the group is not set, we use the default group.
|
59
115
|
group = @group if group.nil?
|
60
|
-
|
61
|
-
|
62
|
-
message = yield
|
63
|
-
else
|
64
|
-
message = group
|
65
|
-
group = @group
|
66
|
-
end
|
67
|
-
end
|
68
|
-
return if message.nil?
|
116
|
+
|
117
|
+
did_not_log = true
|
69
118
|
|
70
119
|
@loggers.each do |logger|
|
71
|
-
|
120
|
+
# Loggers should return true if they did *not* log the message.
|
121
|
+
# If any of the broadcasted loggers logs the message, that counts
|
122
|
+
# as having logged the message.
|
123
|
+
did_not_log &&= logger.add(severity, message, group, &block)
|
72
124
|
rescue
|
73
125
|
nil
|
74
126
|
end
|
75
127
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
128
|
+
# If the severity is below the log level, we do not log the message.
|
129
|
+
return did_not_log if severity < level
|
130
|
+
|
131
|
+
message = block.call if block && message.nil?
|
132
|
+
|
133
|
+
return if message.nil?
|
134
|
+
|
135
|
+
if message.is_a?(Exception)
|
136
|
+
message = "#{message.class}: #{message.message} (#{message.backtrace[0]})"
|
81
137
|
end
|
82
138
|
|
83
139
|
message = formatter.call(severity, Time.now, group, message) if formatter
|
@@ -86,90 +142,67 @@ module Appsignal
|
|
86
142
|
group,
|
87
143
|
SEVERITY_MAP.fetch(severity, 0),
|
88
144
|
@format,
|
89
|
-
message,
|
145
|
+
message.to_s,
|
90
146
|
Appsignal::Utils::Data.generate(appsignal_attributes)
|
91
147
|
)
|
148
|
+
|
149
|
+
false
|
92
150
|
end
|
93
151
|
alias log add
|
94
152
|
|
95
153
|
# Log a debug level message
|
96
|
-
# @param message Message to log
|
97
|
-
# @param attributes Attributes to tag the log with
|
154
|
+
# @param message [String] Message to log
|
155
|
+
# @param attributes [Hash<String, Object>] Attributes to tag the log with
|
98
156
|
# @return [void]
|
99
|
-
def debug(message = nil, attributes = {})
|
100
|
-
|
101
|
-
|
102
|
-
message = yield if message.nil? && block_given?
|
103
|
-
return if message.nil?
|
104
|
-
|
105
|
-
add_with_attributes(DEBUG, message, @group, attributes)
|
157
|
+
def debug(message = nil, attributes = {}, &block)
|
158
|
+
add_with_attributes(DEBUG, message, @group, attributes, &block)
|
106
159
|
end
|
107
160
|
|
108
161
|
# Log an info level message
|
109
|
-
# @param message Message to log
|
110
|
-
# @param attributes Attributes to tag the log with
|
162
|
+
# @param message [String] Message to log
|
163
|
+
# @param attributes [Hash<String, Object>] Attributes to tag the log with
|
111
164
|
# @return [void]
|
112
|
-
def info(message = nil, attributes = {})
|
113
|
-
|
114
|
-
|
115
|
-
message = yield if message.nil? && block_given?
|
116
|
-
return if message.nil?
|
117
|
-
|
118
|
-
add_with_attributes(INFO, message, @group, attributes)
|
165
|
+
def info(message = nil, attributes = {}, &block)
|
166
|
+
add_with_attributes(INFO, message, @group, attributes, &block)
|
119
167
|
end
|
120
168
|
|
121
169
|
# Log a warn level message
|
122
|
-
# @param message Message to log
|
123
|
-
# @param attributes Attributes to tag the log with
|
170
|
+
# @param message [String] Message to log
|
171
|
+
# @param attributes [Hash<String, Object>] Attributes to tag the log with
|
124
172
|
# @return [void]
|
125
|
-
def warn(message = nil, attributes = {})
|
126
|
-
|
127
|
-
|
128
|
-
message = yield if message.nil? && block_given?
|
129
|
-
return if message.nil?
|
130
|
-
|
131
|
-
add_with_attributes(WARN, message, @group, attributes)
|
173
|
+
def warn(message = nil, attributes = {}, &block)
|
174
|
+
add_with_attributes(WARN, message, @group, attributes, &block)
|
132
175
|
end
|
133
176
|
|
134
177
|
# Log an error level message
|
135
|
-
# @param message Message to log
|
136
|
-
# @param attributes Attributes to tag the log with
|
178
|
+
# @param message [String, Exception] Message to log
|
179
|
+
# @param attributes [Hash<String, Object>] Attributes to tag the log with
|
137
180
|
# @return [void]
|
138
|
-
def error(message = nil, attributes = {})
|
139
|
-
|
140
|
-
|
141
|
-
message = yield if message.nil? && block_given?
|
142
|
-
return if message.nil?
|
143
|
-
|
144
|
-
message = "#{message.class}: #{message.message}" if message.is_a?(Exception)
|
145
|
-
|
146
|
-
add_with_attributes(ERROR, message, @group, attributes)
|
181
|
+
def error(message = nil, attributes = {}, &block)
|
182
|
+
add_with_attributes(ERROR, message, @group, attributes, &block)
|
147
183
|
end
|
148
184
|
|
149
185
|
# Log a fatal level message
|
150
|
-
# @param message Message to log
|
151
|
-
# @param attributes Attributes to tag the log with
|
186
|
+
# @param message [String, Exception] Message to log
|
187
|
+
# @param attributes [Hash<String, Object>] Attributes to tag the log with
|
152
188
|
# @return [void]
|
153
|
-
def fatal(message = nil, attributes = {})
|
154
|
-
|
155
|
-
|
156
|
-
message = yield if message.nil? && block_given?
|
157
|
-
return if message.nil?
|
158
|
-
|
159
|
-
add_with_attributes(FATAL, message, @group, attributes)
|
189
|
+
def fatal(message = nil, attributes = {}, &block)
|
190
|
+
add_with_attributes(FATAL, message, @group, attributes, &block)
|
160
191
|
end
|
161
192
|
|
162
193
|
# Log an info level message
|
163
194
|
#
|
164
195
|
# Returns the number of characters written.
|
165
196
|
#
|
166
|
-
# @param message Message to log
|
197
|
+
# @param message [String] Message to log
|
167
198
|
# @return [Integer]
|
168
199
|
def <<(message)
|
169
|
-
|
200
|
+
info(message)
|
170
201
|
message.length
|
171
202
|
end
|
172
203
|
|
204
|
+
# Temporarily silences the logger to a specified level while executing a block.
|
205
|
+
#
|
173
206
|
# When using ActiveSupport::TaggedLogging without the broadcast feature,
|
174
207
|
# the passed logger is required to respond to the `silence` method.
|
175
208
|
#
|
@@ -177,14 +210,22 @@ module Appsignal
|
|
177
210
|
#
|
178
211
|
# - https://github.com/rails/rails/blob/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/activesupport/lib/active_support/logger.rb#L60-L76
|
179
212
|
# - https://github.com/rails/rails/blob/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/activesupport/lib/active_support/logger_silence.rb
|
213
|
+
#
|
214
|
+
# @param severity [Integer] The minimum severity level to log during the block.
|
215
|
+
# @return [Object] The return value of the block.
|
180
216
|
def silence(severity = ERROR, &block)
|
181
217
|
previous_level = @level
|
182
218
|
@level = severity
|
219
|
+
@silenced = true
|
183
220
|
block.call(self)
|
184
221
|
ensure
|
185
222
|
@level = previous_level
|
223
|
+
@silenced = false
|
186
224
|
end
|
187
225
|
|
226
|
+
# Adds a logger to broadcast log messages to.
|
227
|
+
# @param logger [Logger] The logger to add to the broadcast list.
|
228
|
+
# @return [Array<Logger>]
|
188
229
|
def broadcast_to(logger)
|
189
230
|
@loggers << logger
|
190
231
|
end
|
@@ -193,11 +234,11 @@ module Appsignal
|
|
193
234
|
|
194
235
|
attr_reader :default_attributes, :appsignal_attributes
|
195
236
|
|
196
|
-
def add_with_attributes(severity, message, group, attributes)
|
237
|
+
def add_with_attributes(severity, message, group, attributes, &block)
|
197
238
|
@appsignal_attributes = default_attributes.merge(attributes)
|
198
|
-
add(severity, message, group)
|
239
|
+
add(severity, message, group, &block)
|
199
240
|
ensure
|
200
|
-
@appsignal_attributes =
|
241
|
+
@appsignal_attributes = default_attributes
|
201
242
|
end
|
202
243
|
end
|
203
244
|
end
|
data/lib/appsignal/marker.rb
CHANGED
@@ -20,7 +20,7 @@ module Appsignal
|
|
20
20
|
# @see Appsignal::CLI::NotifyOfDeploy
|
21
21
|
# @see https://docs.appsignal.com/appsignal/terminology.html#markers
|
22
22
|
# Terminology: Deploy marker
|
23
|
-
#
|
23
|
+
# @!visibility private
|
24
24
|
class Marker
|
25
25
|
# Path used on the AppSignal Push API
|
26
26
|
# https://push.appsignal.com/1/markers
|
data/lib/appsignal/probes/gvl.rb
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
module Appsignal
|
4
4
|
module Probes
|
5
|
+
# @!visibility private
|
5
6
|
class GvlProbe
|
6
7
|
include Helpers
|
7
8
|
|
8
|
-
#
|
9
|
+
# @!visibility private
|
9
10
|
def self.dependencies_present?
|
10
11
|
defined?(::GVLTools) && gvltools_0_2_or_newer? && ruby_3_2_or_newer? &&
|
11
12
|
!Appsignal::System.jruby?
|
12
13
|
end
|
13
14
|
|
14
|
-
#
|
15
|
+
# @!visibility private
|
15
16
|
def self.gvltools_0_2_or_newer?
|
16
17
|
Gem::Version.new(::GVLTools::VERSION) >= Gem::Version.new("0.2.0")
|
17
18
|
end
|
18
19
|
|
19
|
-
#
|
20
|
+
# @!visibility private
|
20
21
|
def self.ruby_3_2_or_newer?
|
21
22
|
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
|
22
23
|
end
|
data/lib/appsignal/probes/mri.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Appsignal
|
4
4
|
module Probes
|
5
|
-
#
|
5
|
+
# @!visibility private
|
6
6
|
class MriProbe
|
7
7
|
include Helpers
|
8
8
|
|
9
|
-
#
|
9
|
+
# @!visibility private
|
10
10
|
def self.dependencies_present?
|
11
11
|
defined?(::RubyVM) && ::RubyVM.respond_to?(:stat)
|
12
12
|
end
|
@@ -17,7 +17,7 @@ module Appsignal
|
|
17
17
|
@gc_profiler = gc_profiler
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# @!visibility private
|
21
21
|
def call
|
22
22
|
stat = RubyVM.stat
|
23
23
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Appsignal
|
4
4
|
module Probes
|
5
|
-
#
|
5
|
+
# @!visibility private
|
6
6
|
class SidekiqProbe
|
7
7
|
include Helpers
|
8
8
|
|
@@ -38,14 +38,15 @@ module Appsignal
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
#
|
41
|
+
# @!visibility private
|
42
42
|
attr_reader :config
|
43
43
|
|
44
|
+
# @!visibility private
|
44
45
|
def self.sidekiq7_and_greater?
|
45
46
|
Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("7.0.0")
|
46
47
|
end
|
47
48
|
|
48
|
-
#
|
49
|
+
# @!visibility private
|
49
50
|
def self.dependencies_present?
|
50
51
|
return true if sidekiq7_and_greater?
|
51
52
|
return false unless defined?(::Redis::VERSION) # Sidekiq <= 6
|
data/lib/appsignal/probes.rb
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
module Appsignal
|
4
4
|
module Probes
|
5
|
-
# @
|
5
|
+
# @return [Integer]
|
6
|
+
# @!visibility private
|
6
7
|
ITERATION_IN_SECONDS = 60
|
7
8
|
|
8
|
-
#
|
9
|
+
# @!visibility private
|
9
10
|
class ProbeCollection
|
10
11
|
def initialize
|
11
12
|
@probes = {}
|
@@ -23,13 +24,12 @@ module Appsignal
|
|
23
24
|
end
|
24
25
|
|
25
26
|
# Fetch a probe using its name.
|
26
|
-
# @param key [Symbol
|
27
|
+
# @param key [Symbol, String] The name of the probe to fetch.
|
27
28
|
# @return [Object] Returns the registered probe.
|
28
29
|
def [](key)
|
29
30
|
probes[key]
|
30
31
|
end
|
31
32
|
|
32
|
-
# @api private
|
33
33
|
def internal_register(name, probe)
|
34
34
|
if probes.key?(name)
|
35
35
|
logger.debug "A probe with the name `#{name}` is already " \
|
@@ -38,12 +38,10 @@ module Appsignal
|
|
38
38
|
probes[name] = probe
|
39
39
|
end
|
40
40
|
|
41
|
-
# @api private
|
42
41
|
def unregister(name)
|
43
42
|
probes.delete(name)
|
44
43
|
end
|
45
44
|
|
46
|
-
# @api private
|
47
45
|
def each(&block)
|
48
46
|
probes.each(&block)
|
49
47
|
end
|
@@ -58,14 +56,14 @@ module Appsignal
|
|
58
56
|
end
|
59
57
|
|
60
58
|
class << self
|
61
|
-
#
|
59
|
+
# @!visibility private
|
62
60
|
def mutex
|
63
61
|
@mutex ||= Thread::Mutex.new
|
64
62
|
end
|
65
63
|
|
66
64
|
# @see ProbeCollection
|
67
65
|
# @return [ProbeCollection] Returns list of probes.
|
68
|
-
#
|
66
|
+
# @!visibility private
|
69
67
|
def probes
|
70
68
|
@probes ||= ProbeCollection.new
|
71
69
|
end
|
@@ -129,7 +127,7 @@ module Appsignal
|
|
129
127
|
# # "started" # Printed on Appsignal::Probes.start
|
130
128
|
# # "called" # Repeated every minute
|
131
129
|
#
|
132
|
-
# @param name [Symbol
|
130
|
+
# @param name [Symbol, String] Name of the probe. Can be used with
|
133
131
|
# {ProbeCollection#[]}. This name will be used in errors in the log and
|
134
132
|
# allows overwriting of probes by registering new ones with the same
|
135
133
|
# name.
|
@@ -153,7 +151,7 @@ module Appsignal
|
|
153
151
|
# # Then unregister a probe if needed
|
154
152
|
# Appsignal::Probes.unregister :my_probe
|
155
153
|
#
|
156
|
-
# @param name [Symbol
|
154
|
+
# @param name [Symbol, String] Name of the probe used to {register} the
|
157
155
|
# probe.
|
158
156
|
# @return [void]
|
159
157
|
def unregister(name)
|
@@ -162,6 +160,7 @@ module Appsignal
|
|
162
160
|
uninitialize_probe(name)
|
163
161
|
end
|
164
162
|
|
163
|
+
# @return [void]
|
165
164
|
# @api private
|
166
165
|
def start
|
167
166
|
stop
|
@@ -184,8 +183,10 @@ module Appsignal
|
|
184
183
|
logger.debug("Gathering minutely metrics with '#{name}' probe")
|
185
184
|
probe.call
|
186
185
|
rescue => ex
|
187
|
-
logger.error
|
188
|
-
|
186
|
+
logger.error(
|
187
|
+
"Error in minutely probe '#{name}': #{ex.class}: #{ex.message}\n" \
|
188
|
+
"#{ex.backtrace.join("\n")}"
|
189
|
+
)
|
189
190
|
end
|
190
191
|
end
|
191
192
|
end_time = Time.now
|
@@ -212,13 +213,15 @@ module Appsignal
|
|
212
213
|
|
213
214
|
# Stop the minutely probes mechanism. Stop the thread and clear all probe
|
214
215
|
# instances.
|
216
|
+
#
|
217
|
+
# @return [void]
|
215
218
|
def stop
|
216
219
|
defined?(@thread) && @thread.kill
|
217
220
|
@started = false
|
218
221
|
probe_instances.clear
|
219
222
|
end
|
220
223
|
|
221
|
-
#
|
224
|
+
# @!visibility private
|
222
225
|
def wait_time
|
223
226
|
ITERATION_IN_SECONDS - Time.now.sec
|
224
227
|
end
|
@@ -256,8 +259,10 @@ module Appsignal
|
|
256
259
|
end
|
257
260
|
rescue => error
|
258
261
|
logger = Appsignal.internal_logger
|
259
|
-
logger.error
|
260
|
-
|
262
|
+
logger.error(
|
263
|
+
"Error while initializing minutely probe '#{name}': #{error.class}: #{error.message}\n" \
|
264
|
+
"#{error.backtrace.join("\n")}"
|
265
|
+
)
|
261
266
|
end
|
262
267
|
|
263
268
|
def uninitialize_probe(name)
|
@@ -4,7 +4,7 @@ module Appsignal
|
|
4
4
|
module Rack
|
5
5
|
# @api private
|
6
6
|
class BodyWrapper
|
7
|
-
IGNORED_ERRORS = [Errno::EPIPE].freeze
|
7
|
+
IGNORED_ERRORS = [Errno::EPIPE, Errno::ECONNRESET].freeze
|
8
8
|
|
9
9
|
def self.wrap(original_body, appsignal_transaction)
|
10
10
|
# The logic of how Rack treats a response body differs based on which methods
|
data/lib/appsignal/rack.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Appsignal
|
4
|
-
#
|
4
|
+
# @!visibility private
|
5
5
|
class SampleData
|
6
6
|
def initialize(key, accepted_type = nil)
|
7
7
|
@key = key
|
@@ -21,7 +21,6 @@ module Appsignal
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
# @api private
|
25
24
|
def set_empty_value!
|
26
25
|
@empty = true
|
27
26
|
@blocks.clear
|
@@ -36,12 +35,18 @@ module Appsignal
|
|
36
35
|
else
|
37
36
|
block_or_value
|
38
37
|
end
|
38
|
+
|
39
39
|
unless accepted_type?(new_value)
|
40
40
|
log_unsupported_data_type(new_value)
|
41
41
|
next
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
# Before trying to merge values, convert them to Ruby classes
|
45
|
+
# This way we don't need to check if something is of a type often
|
46
|
+
value_new = convert_to_ruby_class(new_value)
|
47
|
+
value_original = convert_to_ruby_class(value)
|
48
|
+
|
49
|
+
value = merge_values(value_original, value_new)
|
45
50
|
new_value
|
46
51
|
end
|
47
52
|
|
@@ -52,7 +57,6 @@ module Appsignal
|
|
52
57
|
@blocks.any?
|
53
58
|
end
|
54
59
|
|
55
|
-
# @api private
|
56
60
|
def empty?
|
57
61
|
@empty
|
58
62
|
end
|
@@ -81,15 +85,19 @@ module Appsignal
|
|
81
85
|
end
|
82
86
|
end
|
83
87
|
|
88
|
+
def mergable?(value_original, value_new)
|
89
|
+
value_new.instance_of?(value_original.class)
|
90
|
+
end
|
91
|
+
|
84
92
|
def merge_values(value_original, value_new)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
+
return value_new if value_original == UNSET_VALUE
|
94
|
+
|
95
|
+
unless mergable?(value_original, value_new)
|
96
|
+
Appsignal.internal_logger.warn(
|
97
|
+
"The sample data '#{@key}' changed type from " \
|
98
|
+
"'#{value_original.class}' to '#{value_new.class}'. " \
|
99
|
+
"These types can not be merged. Using new '#{value_new.class}' type."
|
100
|
+
)
|
93
101
|
return value_new
|
94
102
|
end
|
95
103
|
|
@@ -103,6 +111,17 @@ module Appsignal
|
|
103
111
|
end
|
104
112
|
end
|
105
113
|
|
114
|
+
# Convert any subclasses of Hash to a Ruby Hash class, so we don't have to
|
115
|
+
# account for the original value being a value that's not a pure Hash or
|
116
|
+
# Array object.
|
117
|
+
def convert_to_ruby_class(value)
|
118
|
+
if value.is_a? Hash
|
119
|
+
value.to_h
|
120
|
+
else
|
121
|
+
value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
106
125
|
def log_unsupported_data_type(value)
|
107
126
|
Appsignal.internal_logger.error(
|
108
127
|
"Sample data '#{@key}': Unsupported data type '#{value.class}' received: #{value.inspect}"
|