appsignal 3.12.6-java → 4.0.0.beta.1-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/.github/workflows/ci.yml +499 -487
- data/CHANGELOG.md +151 -0
- data/Rakefile +31 -7
- data/benchmark.rake +4 -6
- data/build_matrix.yml +45 -39
- data/ext/agent.rb +27 -27
- data/ext/appsignal_extension.c +25 -0
- data/gemfiles/rails-7.2.gemfile +11 -0
- data/lib/appsignal/check_in/cron.rb +67 -0
- data/lib/appsignal/check_in.rb +46 -0
- data/lib/appsignal/cli/diagnose.rb +37 -28
- data/lib/appsignal/cli/install.rb +5 -1
- data/lib/appsignal/config.rb +57 -119
- data/lib/appsignal/demo.rb +2 -2
- data/lib/appsignal/extension/jruby.rb +14 -0
- data/lib/appsignal/helpers/instrumentation.rb +139 -414
- data/lib/appsignal/helpers/metrics.rb +0 -16
- data/lib/appsignal/hooks/action_cable.rb +8 -8
- data/lib/appsignal/hooks/active_job.rb +2 -2
- data/lib/appsignal/hooks/at_exit.rb +37 -0
- data/lib/appsignal/hooks.rb +1 -16
- data/lib/appsignal/integrations/action_cable.rb +2 -2
- data/lib/appsignal/integrations/capistrano/appsignal.cap +2 -4
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +1 -4
- data/lib/appsignal/integrations/delayed_job_plugin.rb +3 -3
- data/lib/appsignal/integrations/http.rb +2 -7
- data/lib/appsignal/integrations/que.rb +2 -2
- data/lib/appsignal/integrations/railtie.rb +26 -59
- data/lib/appsignal/integrations/rake.rb +2 -2
- data/lib/appsignal/integrations/resque.rb +2 -2
- data/lib/appsignal/integrations/shoryuken.rb +4 -4
- data/lib/appsignal/integrations/sidekiq.rb +3 -3
- data/lib/appsignal/integrations/webmachine.rb +2 -2
- data/lib/appsignal/loaders.rb +1 -1
- data/lib/appsignal/probes.rb +0 -9
- data/lib/appsignal/rack/abstract_middleware.rb +4 -26
- data/lib/appsignal/rack/event_handler.rb +4 -4
- data/lib/appsignal/rack/rails_instrumentation.rb +1 -1
- data/lib/appsignal/rack.rb +0 -25
- data/lib/appsignal/sample_data.rb +95 -0
- data/lib/appsignal/transaction.rb +235 -361
- data/lib/appsignal/utils/rails_helper.rb +4 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +20 -62
- data/spec/lib/appsignal/auth_check_spec.rb +1 -1
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/capistrano3_spec.rb +53 -13
- data/spec/lib/appsignal/{heartbeat_spec.rb → check_in_spec.rb} +45 -36
- data/spec/lib/appsignal/cli/demo_spec.rb +7 -27
- data/spec/lib/appsignal/cli/diagnose_spec.rb +145 -110
- data/spec/lib/appsignal/config_spec.rb +304 -379
- data/spec/lib/appsignal/extension_install_failure_spec.rb +5 -1
- data/spec/lib/appsignal/extension_spec.rb +5 -1
- data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +1 -1
- data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +1 -2
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +1 -0
- data/spec/lib/appsignal/hooks/activejob_spec.rb +7 -12
- data/spec/lib/appsignal/hooks/at_exit_spec.rb +72 -0
- data/spec/lib/appsignal/hooks/gvl_spec.rb +10 -5
- data/spec/lib/appsignal/hooks/http_spec.rb +3 -3
- data/spec/lib/appsignal/hooks/net_http_spec.rb +3 -3
- data/spec/lib/appsignal/hooks/rake_spec.rb +6 -9
- data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -10
- data/spec/lib/appsignal/hooks/redis_spec.rb +4 -7
- data/spec/lib/appsignal/hooks/resque_spec.rb +3 -5
- data/spec/lib/appsignal/hooks_spec.rb +0 -41
- data/spec/lib/appsignal/integrations/data_mapper_spec.rb +29 -20
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +4 -9
- data/spec/lib/appsignal/integrations/http_spec.rb +0 -21
- data/spec/lib/appsignal/integrations/railtie_spec.rb +179 -157
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +3 -5
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +48 -62
- data/spec/lib/appsignal/loaders/hanami_spec.rb +6 -9
- data/spec/lib/appsignal/loaders/padrino_spec.rb +6 -10
- data/spec/lib/appsignal/loaders/sinatra_spec.rb +6 -9
- data/spec/lib/appsignal/loaders_spec.rb +8 -1
- data/spec/lib/appsignal/marker_spec.rb +1 -1
- data/spec/lib/appsignal/probes_spec.rb +4 -83
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +4 -63
- data/spec/lib/appsignal/rack/event_handler_spec.rb +18 -15
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +3 -11
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +4 -5
- data/spec/lib/appsignal/sample_data_spec.rb +174 -0
- data/spec/lib/appsignal/transaction_spec.rb +791 -1031
- data/spec/lib/appsignal/transmitter_spec.rb +6 -8
- data/spec/lib/appsignal_spec.rb +294 -643
- data/spec/spec_helper.rb +1 -3
- data/spec/support/fixtures/projects/valid/config/appsignal.yml +4 -7
- data/spec/support/fixtures/projects/valid_with_rails_app/config/application.rb +16 -0
- data/spec/support/fixtures/projects/valid_with_rails_app/config/appsignal.yml +56 -0
- data/spec/support/fixtures/projects/valid_with_rails_app/config/environment.rb +5 -0
- data/spec/support/helpers/api_request_helper.rb +3 -2
- data/spec/support/helpers/config_helpers.rb +41 -11
- data/spec/support/helpers/dependency_helper.rb +8 -0
- data/spec/support/helpers/log_helpers.rb +1 -0
- data/spec/support/helpers/rails_helper.rb +6 -6
- data/spec/support/helpers/transaction_helpers.rb +2 -24
- data/spec/support/matchers/transaction.rb +3 -3
- data/spec/support/mocks/appsignal_mock.rb +3 -3
- data/spec/support/mocks/mock_probe.rb +2 -0
- data/spec/support/testing.rb +2 -2
- metadata +14 -23
- data/gemfiles/que_beta.gemfile +0 -5
- data/lib/appsignal/heartbeat.rb +0 -59
- data/lib/appsignal/helpers/heartbeats.rb +0 -44
- data/lib/appsignal/integrations/grape.rb +0 -35
- data/lib/appsignal/integrations/hanami.rb +0 -13
- data/lib/appsignal/integrations/padrino.rb +0 -13
- data/lib/appsignal/integrations/sinatra.rb +0 -13
- data/lib/appsignal/rack/generic_instrumentation.rb +0 -22
- data/lib/appsignal/rack/streaming_listener.rb +0 -28
- data/spec/lib/appsignal/integrations/grape_spec.rb +0 -36
- data/spec/lib/appsignal/integrations/hanami_spec.rb +0 -17
- data/spec/lib/appsignal/integrations/padrino_spec.rb +0 -15
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -15
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +0 -81
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +0 -69
- data/spec/support/fixtures/projects/valid/config/environments/development.rb +0 -0
- data/spec/support/fixtures/projects/valid/config/environments/production.rb +0 -0
- data/spec/support/fixtures/projects/valid/config/environments/test.rb +0 -0
- data/spec/support/rails/my_app.rb +0 -6
- /data/spec/support/fixtures/projects/{valid/config/application.rb → valid_with_rails_app/log/.gitkeep} +0 -0
@@ -9,8 +9,6 @@ module Appsignal
|
|
9
9
|
# @api private
|
10
10
|
ACTION_CABLE = "action_cable"
|
11
11
|
# @api private
|
12
|
-
FRONTEND = "frontend"
|
13
|
-
# @api private
|
14
12
|
BLANK = ""
|
15
13
|
# @api private
|
16
14
|
ALLOWED_TAG_KEY_TYPES = [Symbol, String].freeze
|
@@ -20,69 +18,27 @@ module Appsignal
|
|
20
18
|
BREADCRUMB_LIMIT = 20
|
21
19
|
# @api private
|
22
20
|
ERROR_CAUSES_LIMIT = 10
|
21
|
+
ERRORS_LIMIT = 10
|
23
22
|
|
24
23
|
class << self
|
25
24
|
# Create a new transaction and set it as the currently active
|
26
25
|
# transaction.
|
27
26
|
#
|
28
|
-
# @param
|
27
|
+
# @param namespace [String] Namespace of the to be created transaction.
|
29
28
|
# @return [Transaction]
|
30
|
-
def create(
|
31
|
-
if id_or_namespace && arg_namespace
|
32
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
33
|
-
"Appsignal::Transaction.create: " \
|
34
|
-
"A new Transaction is created using the transaction ID argument. " \
|
35
|
-
"This argument is deprecated without replacement."
|
36
|
-
)
|
37
|
-
end
|
38
|
-
if arg_namespace
|
39
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
40
|
-
"Appsignal::Transaction.create: " \
|
41
|
-
"A Transaction is created using the namespace argument. " \
|
42
|
-
"Specify the namespace as the first argument to the 'create' " \
|
43
|
-
"method without the ID argument."
|
44
|
-
)
|
45
|
-
end
|
46
|
-
if request
|
47
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
48
|
-
"Appsignal::Transaction.create: " \
|
49
|
-
"A Transaction is created using the request argument. " \
|
50
|
-
"This argument is deprecated. Please use the `Appsignal.set_*` helpers instead."
|
51
|
-
)
|
52
|
-
end
|
53
|
-
# Allow middleware to force a new transaction
|
54
|
-
if options[:force]
|
55
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
56
|
-
"Appsignal::Transaction.create: " \
|
57
|
-
"A Transaction is created using the `:force => true` option argument. " \
|
58
|
-
"The options argument is deprecated without replacement."
|
59
|
-
)
|
60
|
-
Thread.current[:appsignal_transaction] = nil
|
61
|
-
end
|
62
|
-
if arg_namespace
|
63
|
-
id = id_or_namespace
|
64
|
-
namespace = arg_namespace
|
65
|
-
else
|
66
|
-
id = SecureRandom.uuid
|
67
|
-
namespace = id_or_namespace
|
68
|
-
end
|
69
|
-
|
29
|
+
def create(namespace)
|
70
30
|
# Check if we already have a running transaction
|
71
31
|
if Thread.current[:appsignal_transaction].nil?
|
72
32
|
# If not, start a new transaction
|
73
|
-
|
74
|
-
Appsignal::Transaction.new(
|
75
|
-
|
76
|
-
namespace,
|
77
|
-
request,
|
78
|
-
options
|
79
|
-
)
|
33
|
+
set_current_transaction(
|
34
|
+
Appsignal::Transaction.new(SecureRandom.uuid, namespace)
|
35
|
+
)
|
80
36
|
else
|
81
37
|
# Otherwise, log the issue about trying to start another transaction
|
82
38
|
Appsignal.internal_logger.warn(
|
83
|
-
"Trying to start new transaction
|
84
|
-
"
|
85
|
-
"
|
39
|
+
"Trying to start new transaction, but a transaction " \
|
40
|
+
"with id '#{current.transaction_id}' is already running. " \
|
41
|
+
"Using transaction '#{current.transaction_id}'."
|
86
42
|
)
|
87
43
|
|
88
44
|
# And return the current transaction instead
|
@@ -90,6 +46,23 @@ module Appsignal
|
|
90
46
|
end
|
91
47
|
end
|
92
48
|
|
49
|
+
# @api private
|
50
|
+
def set_current_transaction(transaction)
|
51
|
+
Thread.current[:appsignal_transaction] = transaction
|
52
|
+
end
|
53
|
+
|
54
|
+
# Set the current for the duration of the given block.
|
55
|
+
# It restores the original transaction (if any) when the block has executed.
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
def with_transaction(transaction)
|
59
|
+
original_transaction = current if current?
|
60
|
+
set_current_transaction(transaction)
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
set_current_transaction(original_transaction)
|
64
|
+
end
|
65
|
+
|
93
66
|
# Returns currently active transaction or a {NilTransaction} if none is
|
94
67
|
# active.
|
95
68
|
#
|
@@ -125,11 +98,19 @@ module Appsignal
|
|
125
98
|
def clear_current_transaction!
|
126
99
|
Thread.current[:appsignal_transaction] = nil
|
127
100
|
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
def last_errors
|
104
|
+
@last_errors ||= []
|
105
|
+
end
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
attr_writer :last_errors
|
128
109
|
end
|
129
110
|
|
130
111
|
# @api private
|
131
112
|
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options,
|
132
|
-
:breadcrumbs, :
|
113
|
+
:breadcrumbs, :is_duplicate, :error_blocks
|
133
114
|
|
134
115
|
# Use {.create} to create new transactions.
|
135
116
|
#
|
@@ -137,24 +118,25 @@ module Appsignal
|
|
137
118
|
# @param namespace [String] Namespace of the to be created transaction.
|
138
119
|
# @see create
|
139
120
|
# @api private
|
140
|
-
def initialize(transaction_id, namespace,
|
121
|
+
def initialize(transaction_id, namespace, ext: nil)
|
141
122
|
@transaction_id = transaction_id
|
142
123
|
@action = nil
|
143
124
|
@namespace = namespace
|
144
|
-
@request = request || InternalGenericRequest.new({})
|
145
125
|
@paused = false
|
146
126
|
@discarded = false
|
147
127
|
@tags = {}
|
148
|
-
@custom_data = nil
|
149
128
|
@breadcrumbs = []
|
150
129
|
@store = Hash.new({})
|
151
|
-
@
|
152
|
-
@
|
153
|
-
@
|
154
|
-
|
155
|
-
@
|
130
|
+
@error_blocks = Hash.new { |hash, key| hash[key] = [] }
|
131
|
+
@is_duplicate = false
|
132
|
+
@error_set = nil
|
133
|
+
|
134
|
+
@params = Appsignal::SampleData.new(:params)
|
135
|
+
@session_data = Appsignal::SampleData.new(:session_data, Hash)
|
136
|
+
@headers = Appsignal::SampleData.new(:headers, Hash)
|
137
|
+
@custom_data = Appsignal::SampleData.new(:custom_data)
|
156
138
|
|
157
|
-
@ext = Appsignal::Extension.start_transaction(
|
139
|
+
@ext = ext || Appsignal::Extension.start_transaction(
|
158
140
|
@transaction_id,
|
159
141
|
@namespace,
|
160
142
|
0
|
@@ -171,8 +153,44 @@ module Appsignal
|
|
171
153
|
"because it was manually discarded."
|
172
154
|
return
|
173
155
|
end
|
174
|
-
|
175
|
-
|
156
|
+
|
157
|
+
# If the transaction is a duplicate, we don't want to finish it,
|
158
|
+
# because we want its finish time to be the finish time of the
|
159
|
+
# original transaction.
|
160
|
+
# Duplicate transactions should always be sampled, as we only
|
161
|
+
# create duplicates for errors, which are always sampled.
|
162
|
+
should_sample = true
|
163
|
+
|
164
|
+
unless is_duplicate
|
165
|
+
self.class.last_errors = @error_blocks.keys
|
166
|
+
should_sample = ext.finish(0)
|
167
|
+
end
|
168
|
+
|
169
|
+
@error_blocks.each do |error, blocks|
|
170
|
+
# Ignore the error that is already set in this transaction.
|
171
|
+
next if error == @error_set
|
172
|
+
|
173
|
+
duplicate.tap do |transaction|
|
174
|
+
# In the duplicate transaction for each error, set an error
|
175
|
+
# with a block that calls all the blocks set for that error
|
176
|
+
# in the original transaction.
|
177
|
+
transaction.set_error(error) do
|
178
|
+
blocks.each { |block| block.call(transaction) }
|
179
|
+
end
|
180
|
+
|
181
|
+
transaction.complete
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
if @error_set && @error_blocks[@error_set].any?
|
186
|
+
self.class.with_transaction(self) do
|
187
|
+
@error_blocks[@error_set].each do |block|
|
188
|
+
block.call(self)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
sample_data if should_sample
|
193
|
+
ext.complete
|
176
194
|
end
|
177
195
|
|
178
196
|
# @api private
|
@@ -210,69 +228,40 @@ module Appsignal
|
|
210
228
|
@store[key]
|
211
229
|
end
|
212
230
|
|
213
|
-
#
|
214
|
-
def params
|
215
|
-
parameters = @params || request_params
|
216
|
-
|
217
|
-
if parameters.respond_to? :call
|
218
|
-
parameters.call
|
219
|
-
else
|
220
|
-
parameters
|
221
|
-
end
|
222
|
-
rescue => e
|
223
|
-
Appsignal.internal_logger.error("Exception while fetching params: #{e.class}: #{e}")
|
224
|
-
nil
|
225
|
-
end
|
226
|
-
|
227
|
-
# Set parameters on the transaction.
|
228
|
-
#
|
229
|
-
# When no parameters are set this way, the transaction will look for
|
230
|
-
# parameters on the {#request} environment.
|
231
|
+
# Add parameters to the transaction.
|
231
232
|
#
|
232
|
-
#
|
233
|
-
# from a request's environment.
|
233
|
+
# When this method is called multiple times, it will merge the request parameters.
|
234
234
|
#
|
235
235
|
# When both the `given_params` and a block is given to this method, the
|
236
|
-
#
|
236
|
+
# block is leading and the argument will _not_ be used.
|
237
237
|
#
|
238
|
-
# @since
|
238
|
+
# @since 4.0.0
|
239
239
|
# @param given_params [Hash] The parameters to set on the transaction.
|
240
240
|
# @yield This block is called when the transaction is sampled. The block's
|
241
241
|
# return value will become the new parameters.
|
242
242
|
# @return [void]
|
243
|
-
# @see Helpers::Instrumentation#
|
244
|
-
def
|
245
|
-
@params
|
246
|
-
@params = given_params if given_params
|
247
|
-
end
|
248
|
-
|
249
|
-
# @deprecated Use {#set_params} or {#set_params_if_nil} instead.
|
250
|
-
def params=(given_params)
|
251
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
252
|
-
"Transaction#params= is deprecated." \
|
253
|
-
"Use Transaction#set_params or #set_params_if_nil instead."
|
254
|
-
)
|
255
|
-
set_params(given_params)
|
243
|
+
# @see Helpers::Instrumentation#add_params
|
244
|
+
def add_params(given_params = nil, &block)
|
245
|
+
@params.add(given_params, &block)
|
256
246
|
end
|
247
|
+
alias :set_params :add_params
|
257
248
|
|
258
|
-
#
|
249
|
+
# Add parameters to the transaction if not already set.
|
259
250
|
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
263
|
-
# @since 3.9.1
|
251
|
+
# @api private
|
252
|
+
# @since 4.0.0
|
264
253
|
# @param given_params [Hash] The parameters to set on the transaction if none are already set.
|
265
254
|
# @yield This block is called when the transaction is sampled. The block's
|
266
255
|
# return value will become the new parameters.
|
267
256
|
# @return [void]
|
268
257
|
#
|
269
|
-
# @see #
|
270
|
-
|
271
|
-
|
272
|
-
set_params(given_params, &block) unless @params
|
258
|
+
# @see #add_params
|
259
|
+
def add_params_if_nil(given_params = nil, &block)
|
260
|
+
add_params(given_params, &block) unless @params.value?
|
273
261
|
end
|
262
|
+
alias :set_params_if_nil :add_params_if_nil
|
274
263
|
|
275
|
-
#
|
264
|
+
# Add tags to the transaction.
|
276
265
|
#
|
277
266
|
# When this method is called multiple times, it will merge the tags.
|
278
267
|
#
|
@@ -283,32 +272,34 @@ module Appsignal
|
|
283
272
|
# The name of the tag as a String.
|
284
273
|
# @return [void]
|
285
274
|
#
|
286
|
-
# @see Helpers::Instrumentation#
|
275
|
+
# @see Helpers::Instrumentation#add_tags
|
287
276
|
# @see https://docs.appsignal.com/ruby/instrumentation/tagging.html
|
288
277
|
# Tagging guide
|
289
|
-
def
|
278
|
+
def add_tags(given_tags = {})
|
290
279
|
@tags.merge!(given_tags)
|
291
280
|
end
|
281
|
+
alias :set_tags add_tags
|
292
282
|
|
293
|
-
#
|
283
|
+
# Add session data to the transaction.
|
284
|
+
#
|
285
|
+
# When this method is called multiple times, it will merge the session data.
|
294
286
|
#
|
295
287
|
# When both the `given_session_data` and a block is given to this method,
|
296
|
-
# the
|
297
|
-
# called.
|
288
|
+
# the block is leading and the argument will _not_ be used.
|
298
289
|
#
|
299
290
|
# @param given_session_data [Hash] A hash containing session data.
|
300
291
|
# @yield This block is called when the transaction is sampled. The block's
|
301
292
|
# return value will become the new session data.
|
302
293
|
# @return [void]
|
303
294
|
#
|
304
|
-
# @since
|
305
|
-
# @see Helpers::Instrumentation#
|
295
|
+
# @since 4.0.0
|
296
|
+
# @see Helpers::Instrumentation#add_session_data
|
306
297
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
307
298
|
# Sample data guide
|
308
|
-
def
|
309
|
-
@session_data
|
310
|
-
@session_data = given_session_data if given_session_data
|
299
|
+
def add_session_data(given_session_data = nil, &block)
|
300
|
+
@session_data.add(given_session_data, &block)
|
311
301
|
end
|
302
|
+
alias :set_session_data :add_session_data
|
312
303
|
|
313
304
|
# Set session data on the transaction if not already set.
|
314
305
|
#
|
@@ -321,73 +312,64 @@ module Appsignal
|
|
321
312
|
# return value will become the new session data.
|
322
313
|
# @return [void]
|
323
314
|
#
|
324
|
-
# @
|
325
|
-
# @
|
315
|
+
# @api private
|
316
|
+
# @since 4.0.0
|
317
|
+
# @see #add_session_data
|
326
318
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
327
319
|
# Sample data guide
|
328
|
-
def
|
329
|
-
|
320
|
+
def add_session_data_if_nil(given_session_data = nil, &block)
|
321
|
+
add_session_data(given_session_data, &block) unless @session_data.value?
|
330
322
|
end
|
323
|
+
alias :set_session_data_if_nil :add_session_data_if_nil
|
331
324
|
|
332
|
-
#
|
333
|
-
#
|
334
|
-
# When both the `given_headers` and a block is given to this method,
|
335
|
-
# the `given_headers` argument is leading and the block will _not_ be
|
336
|
-
# called.
|
325
|
+
# Add headers to the transaction.
|
337
326
|
#
|
338
327
|
# @param given_headers [Hash] A hash containing headers.
|
339
328
|
# @yield This block is called when the transaction is sampled. The block's
|
340
329
|
# return value will become the new headers.
|
341
330
|
# @return [void]
|
342
331
|
#
|
343
|
-
# @since
|
344
|
-
# @see Helpers::Instrumentation#
|
332
|
+
# @since 4.0.0
|
333
|
+
# @see Helpers::Instrumentation#add_headers
|
345
334
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
346
335
|
# Sample data guide
|
347
|
-
def
|
348
|
-
@headers
|
349
|
-
@headers = given_headers if given_headers
|
336
|
+
def add_headers(given_headers = nil, &block)
|
337
|
+
@headers.add(given_headers, &block)
|
350
338
|
end
|
339
|
+
alias :set_headers :add_headers
|
351
340
|
|
352
|
-
#
|
341
|
+
# Add headers to the transaction if not already set.
|
353
342
|
#
|
354
343
|
# When both the `given_headers` and a block is given to this method,
|
355
|
-
# the
|
356
|
-
# called.
|
344
|
+
# the block is leading and the argument will _not_ be used.
|
357
345
|
#
|
358
346
|
# @param given_headers [Hash] A hash containing headers.
|
359
347
|
# @yield This block is called when the transaction is sampled. The block's
|
360
348
|
# return value will become the new headers.
|
361
349
|
# @return [void]
|
362
350
|
#
|
363
|
-
# @
|
364
|
-
# @
|
351
|
+
# @api private
|
352
|
+
# @since 4.0.0
|
353
|
+
# @see #add_headers
|
365
354
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
366
355
|
# Sample data guide
|
367
|
-
def
|
368
|
-
|
356
|
+
def add_headers_if_nil(given_headers = nil, &block)
|
357
|
+
add_headers(given_headers, &block) unless @headers.value?
|
369
358
|
end
|
359
|
+
alias :set_headers_if_nil :add_headers_if_nil
|
370
360
|
|
371
|
-
#
|
361
|
+
# Add custom data to the transaction.
|
372
362
|
#
|
373
|
-
#
|
374
|
-
#
|
375
|
-
#
|
376
|
-
# @since 3.10.0
|
377
|
-
# @see Appsignal.set_custom_data
|
363
|
+
# @since 4.0.0
|
364
|
+
# @see Helpers::Instrumentation#add_custom_data
|
378
365
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
379
366
|
# Sample data guide
|
380
367
|
# @param data [Hash/Array]
|
381
368
|
# @return [void]
|
382
|
-
def
|
383
|
-
|
384
|
-
when Array, Hash
|
385
|
-
@custom_data = data
|
386
|
-
else
|
387
|
-
Appsignal.internal_logger
|
388
|
-
.error("set_custom_data: Unsupported data type #{data.class} received.")
|
389
|
-
end
|
369
|
+
def add_custom_data(data)
|
370
|
+
@custom_data.add(data)
|
390
371
|
end
|
372
|
+
alias :set_custom_data :add_custom_data
|
391
373
|
|
392
374
|
# Add breadcrumbs to the transaction.
|
393
375
|
#
|
@@ -479,18 +461,6 @@ module Appsignal
|
|
479
461
|
@ext.set_namespace(namespace)
|
480
462
|
end
|
481
463
|
|
482
|
-
# @deprecated Use the {#set_action} helper.
|
483
|
-
# @api private
|
484
|
-
def set_http_or_background_action(from = request.params)
|
485
|
-
return unless from
|
486
|
-
|
487
|
-
group_and_action = [
|
488
|
-
from[:controller] || from[:class],
|
489
|
-
from[:action] || from[:method]
|
490
|
-
]
|
491
|
-
set_action_if_nil(group_and_action.compact.join("#"))
|
492
|
-
end
|
493
|
-
|
494
464
|
# Set queue start time for transaction.
|
495
465
|
#
|
496
466
|
# @param start [Integer] Queue start time in milliseconds.
|
@@ -507,35 +477,6 @@ module Appsignal
|
|
507
477
|
Appsignal.internal_logger.warn("Queue start value #{start} is too big")
|
508
478
|
end
|
509
479
|
|
510
|
-
# Set the queue time based on the HTTP header or `:queue_start` env key
|
511
|
-
# value.
|
512
|
-
#
|
513
|
-
# This method will first try to read the queue time from the HTTP headers
|
514
|
-
# `X-Request-Start` or `X-Queue-Start`. Which are parsed by Rack as
|
515
|
-
# `HTTP_X_QUEUE_START` and `HTTP_X_REQUEST_START`.
|
516
|
-
# The header value is parsed by AppSignal as either milliseconds or
|
517
|
-
# microseconds.
|
518
|
-
#
|
519
|
-
# If no headers are found, or the value could not be parsed, it falls back
|
520
|
-
# on the `:queue_start` env key on this Transaction's {request} environment
|
521
|
-
# (called like `request.env[:queue_start]`). This value is parsed by
|
522
|
-
# AppSignal as seconds.
|
523
|
-
#
|
524
|
-
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
525
|
-
# @deprecated Use {#set_queue_start} instead.
|
526
|
-
# @return [void]
|
527
|
-
def set_http_or_background_queue_start
|
528
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning \
|
529
|
-
"The Appsignal::Transaction#set_http_or_background_queue_start " \
|
530
|
-
"method has been deprecated. " \
|
531
|
-
"Please use the Appsignal::Transaction#set_queue_start method instead."
|
532
|
-
|
533
|
-
start = http_queue_start || background_queue_start
|
534
|
-
return unless start
|
535
|
-
|
536
|
-
set_queue_start(start)
|
537
|
-
end
|
538
|
-
|
539
480
|
# @api private
|
540
481
|
def set_metadata(key, value)
|
541
482
|
return unless key && value
|
@@ -544,81 +485,33 @@ module Appsignal
|
|
544
485
|
@ext.set_metadata(key, value)
|
545
486
|
end
|
546
487
|
|
547
|
-
# @
|
548
|
-
|
549
|
-
# @api private
|
550
|
-
def set_sample_data(key, data)
|
551
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
552
|
-
"Appsignal::Transaction#set_sample_data is deprecated. " \
|
553
|
-
"Please use one of the instrumentation helpers: set_tags, " \
|
554
|
-
"set_params, set_session_data, set_params or set_custom_data."
|
555
|
-
)
|
556
|
-
_set_sample_data(key, data)
|
557
|
-
end
|
558
|
-
|
559
|
-
# @deprecated No replacement.
|
560
|
-
# @api private
|
561
|
-
def sample_data
|
562
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
563
|
-
"Appsignal::Transaction#sample_data is deprecated. " \
|
564
|
-
"Please remove any calls to this method."
|
565
|
-
)
|
566
|
-
_sample_data
|
567
|
-
end
|
568
|
-
|
569
|
-
# @see Appsignal::Helpers::Instrumentation#set_error
|
570
|
-
def set_error(error)
|
488
|
+
# @see Appsignal::Helpers::Instrumentation#add_error
|
489
|
+
def add_error(error, &block)
|
571
490
|
unless error.is_a?(Exception)
|
572
|
-
Appsignal.internal_logger.error "Appsignal::Transaction#
|
491
|
+
Appsignal.internal_logger.error "Appsignal::Transaction#add_error: Cannot add error. " \
|
573
492
|
"The given value is not an exception: #{error.inspect}"
|
574
493
|
return
|
575
494
|
end
|
495
|
+
|
576
496
|
return unless error
|
577
497
|
return unless Appsignal.active?
|
578
498
|
|
579
|
-
|
580
|
-
@ext.set_error(
|
581
|
-
error.class.name,
|
582
|
-
cleaned_error_message(error),
|
583
|
-
backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
|
584
|
-
)
|
585
|
-
|
586
|
-
root_cause_missing = false
|
587
|
-
|
588
|
-
causes = []
|
589
|
-
while error
|
590
|
-
error = error.cause
|
591
|
-
|
592
|
-
break unless error
|
499
|
+
_set_error(error) if @error_blocks.empty?
|
593
500
|
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
break
|
600
|
-
end
|
601
|
-
|
602
|
-
causes << error
|
501
|
+
if !@error_blocks.include?(error) && @error_blocks.length >= ERRORS_LIMIT
|
502
|
+
Appsignal.internal_logger.warn "Appsignal::Transaction#add_error: Transaction has more " \
|
503
|
+
"than #{ERRORS_LIMIT} distinct errors. Only the first " \
|
504
|
+
"#{ERRORS_LIMIT} distinct errors will be reported."
|
505
|
+
return
|
603
506
|
end
|
604
507
|
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
{
|
609
|
-
:name => e.class.name,
|
610
|
-
:message => cleaned_error_message(e)
|
611
|
-
}
|
612
|
-
end
|
508
|
+
@error_blocks[error] << block
|
509
|
+
@error_blocks[error].compact!
|
510
|
+
end
|
613
511
|
|
614
|
-
|
512
|
+
alias :set_error :add_error
|
615
513
|
|
616
|
-
|
617
|
-
"error_causes",
|
618
|
-
causes_sample_data
|
619
|
-
)
|
620
|
-
end
|
621
|
-
alias_method :add_exception, :set_error
|
514
|
+
alias_method :add_exception, :add_error
|
622
515
|
|
623
516
|
# @see Helpers::Instrumentation#instrument
|
624
517
|
# @api private
|
@@ -671,37 +564,56 @@ module Appsignal
|
|
671
564
|
end
|
672
565
|
alias_method :to_hash, :to_h
|
673
566
|
|
674
|
-
|
675
|
-
class InternalGenericRequest
|
676
|
-
attr_reader :env
|
567
|
+
protected
|
677
568
|
|
678
|
-
|
679
|
-
|
680
|
-
|
569
|
+
attr_writer :is_duplicate, :tags, :custom_data, :breadcrumbs, :params, :session_data, :headers
|
570
|
+
|
571
|
+
private
|
572
|
+
|
573
|
+
def _set_error(error)
|
574
|
+
backtrace = cleaned_backtrace(error.backtrace)
|
575
|
+
@ext.set_error(
|
576
|
+
error.class.name,
|
577
|
+
cleaned_error_message(error),
|
578
|
+
backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
|
579
|
+
)
|
580
|
+
@error_set = error
|
581
|
+
|
582
|
+
root_cause_missing = false
|
583
|
+
|
584
|
+
causes = []
|
585
|
+
while error
|
586
|
+
error = error.cause
|
587
|
+
|
588
|
+
break unless error
|
589
|
+
|
590
|
+
if causes.length >= ERROR_CAUSES_LIMIT
|
591
|
+
Appsignal.internal_logger.debug "Appsignal::Transaction#add_error: Error has more " \
|
592
|
+
"than #{ERROR_CAUSES_LIMIT} error causes. Only the first #{ERROR_CAUSES_LIMIT} " \
|
593
|
+
"will be reported."
|
594
|
+
root_cause_missing = true
|
595
|
+
break
|
596
|
+
end
|
681
597
|
|
682
|
-
|
683
|
-
env[:params]
|
598
|
+
causes << error
|
684
599
|
end
|
685
|
-
end
|
686
600
|
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
def initialize(_env)
|
693
|
-
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
694
|
-
"The use of Appsignal::Transaction::GenericRequest is deprecated. " \
|
695
|
-
"Use the `Appsignal.set_*` helpers instead. " \
|
696
|
-
"https://docs.appsignal.com/guides/custom-data/sample-data.html"
|
697
|
-
)
|
698
|
-
super
|
601
|
+
causes_sample_data = causes.map do |e|
|
602
|
+
{
|
603
|
+
:name => e.class.name,
|
604
|
+
:message => cleaned_error_message(e)
|
605
|
+
}
|
699
606
|
end
|
700
|
-
end
|
701
607
|
|
702
|
-
|
608
|
+
causes_sample_data.last[:is_root_cause] = false if root_cause_missing
|
609
|
+
|
610
|
+
set_sample_data(
|
611
|
+
"error_causes",
|
612
|
+
causes_sample_data
|
613
|
+
)
|
614
|
+
end
|
703
615
|
|
704
|
-
def
|
616
|
+
def set_sample_data(key, data)
|
705
617
|
return unless key && data
|
706
618
|
|
707
619
|
if !data.is_a?(Array) && !data.is_a?(Hash)
|
@@ -728,44 +640,43 @@ module Appsignal
|
|
728
640
|
end
|
729
641
|
end
|
730
642
|
|
731
|
-
def
|
643
|
+
def sample_data
|
732
644
|
{
|
733
645
|
:params => sanitized_params,
|
734
|
-
:environment =>
|
646
|
+
:environment => sanitized_request_headers,
|
735
647
|
:session_data => sanitized_session_data,
|
736
|
-
:metadata => sanitized_metadata,
|
737
648
|
:tags => sanitized_tags,
|
738
649
|
:breadcrumbs => breadcrumbs,
|
739
650
|
:custom_data => custom_data
|
740
651
|
}.each do |key, data|
|
741
|
-
|
652
|
+
set_sample_data(key, data)
|
742
653
|
end
|
743
654
|
end
|
744
655
|
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
656
|
+
def duplicate
|
657
|
+
new_transaction_id = SecureRandom.uuid
|
658
|
+
|
659
|
+
self.class.new(
|
660
|
+
new_transaction_id,
|
661
|
+
namespace,
|
662
|
+
:ext => ext.duplicate(new_transaction_id)
|
663
|
+
).tap do |transaction|
|
664
|
+
transaction.is_duplicate = true
|
665
|
+
transaction.tags = @tags.dup
|
666
|
+
transaction.custom_data = @custom_data.dup
|
667
|
+
transaction.breadcrumbs = @breadcrumbs.dup
|
668
|
+
transaction.params = @params.dup
|
669
|
+
transaction.session_data = @session_data.dup
|
670
|
+
transaction.headers = @headers.dup
|
671
|
+
end
|
759
672
|
end
|
760
673
|
|
761
|
-
#
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
env = environment
|
768
|
-
Appsignal::Rack::Utils.queue_start_from(env)
|
674
|
+
# @api private
|
675
|
+
def params
|
676
|
+
@params.value
|
677
|
+
rescue => e
|
678
|
+
Appsignal.internal_logger.error("Exception while fetching params: #{e.class}: #{e}")
|
679
|
+
nil
|
769
680
|
end
|
770
681
|
|
771
682
|
def sanitized_params
|
@@ -775,27 +686,8 @@ module Appsignal
|
|
775
686
|
Appsignal::Utils::HashSanitizer.sanitize params, filter_keys
|
776
687
|
end
|
777
688
|
|
778
|
-
def request_params
|
779
|
-
return unless request.respond_to?(options[:params_method])
|
780
|
-
|
781
|
-
begin
|
782
|
-
request.send options[:params_method]
|
783
|
-
rescue => e
|
784
|
-
Appsignal.internal_logger.warn "Exception while getting params: #{e}"
|
785
|
-
nil
|
786
|
-
end
|
787
|
-
end
|
788
|
-
|
789
689
|
def session_data
|
790
|
-
|
791
|
-
if @session_data.respond_to? :call
|
792
|
-
@session_data.call
|
793
|
-
else
|
794
|
-
@session_data
|
795
|
-
end
|
796
|
-
elsif request.respond_to?(:session)
|
797
|
-
request.session
|
798
|
-
end
|
690
|
+
@session_data.value
|
799
691
|
rescue => e
|
800
692
|
Appsignal.internal_logger.error \
|
801
693
|
"Exception while fetching session data: #{e.class}: #{e}"
|
@@ -814,35 +706,12 @@ module Appsignal
|
|
814
706
|
return unless Appsignal.config[:send_session_data]
|
815
707
|
|
816
708
|
Appsignal::Utils::HashSanitizer.sanitize(
|
817
|
-
session_data
|
709
|
+
session_data, Appsignal.config[:filter_session_data]
|
818
710
|
)
|
819
711
|
end
|
820
712
|
|
821
|
-
|
822
|
-
|
823
|
-
# @return [Hash<String, Object>]
|
824
|
-
def sanitized_metadata
|
825
|
-
env = environment
|
826
|
-
return unless env
|
827
|
-
|
828
|
-
metadata = env[:metadata]
|
829
|
-
return unless metadata
|
830
|
-
|
831
|
-
metadata
|
832
|
-
.transform_keys(&:to_s)
|
833
|
-
.reject { |key, _value| Appsignal.config[:filter_metadata].include?(key) }
|
834
|
-
end
|
835
|
-
|
836
|
-
def environment
|
837
|
-
if @headers
|
838
|
-
if @headers.respond_to? :call
|
839
|
-
@headers.call
|
840
|
-
else
|
841
|
-
@headers
|
842
|
-
end
|
843
|
-
elsif request.respond_to?(:env)
|
844
|
-
request.env
|
845
|
-
end
|
713
|
+
def request_headers
|
714
|
+
@headers.value
|
846
715
|
rescue => e
|
847
716
|
Appsignal.internal_logger.error \
|
848
717
|
"Exception while fetching headers: #{e.class}: #{e}"
|
@@ -856,15 +725,13 @@ module Appsignal
|
|
856
725
|
#
|
857
726
|
# @return [nil] if no environment is present.
|
858
727
|
# @return [Hash<String, Object>]
|
859
|
-
def
|
860
|
-
|
861
|
-
return unless
|
862
|
-
return unless env.respond_to?(:empty?)
|
863
|
-
return if env.empty?
|
728
|
+
def sanitized_request_headers
|
729
|
+
headers = request_headers
|
730
|
+
return unless headers
|
864
731
|
|
865
732
|
{}.tap do |out|
|
866
733
|
Appsignal.config[:request_headers].each do |key|
|
867
|
-
out[key] =
|
734
|
+
out[key] = headers[key] if headers[key]
|
868
735
|
end
|
869
736
|
end
|
870
737
|
end
|
@@ -890,6 +757,13 @@ module Appsignal
|
|
890
757
|
end
|
891
758
|
end
|
892
759
|
|
760
|
+
def custom_data
|
761
|
+
@custom_data.value
|
762
|
+
rescue => e
|
763
|
+
Appsignal.internal_logger.error("Exception while fetching custom data: #{e.class}: #{e}")
|
764
|
+
nil
|
765
|
+
end
|
766
|
+
|
893
767
|
# Clean error messages that are known to potentially contain user data.
|
894
768
|
# Returns an unchanged message otherwise.
|
895
769
|
def cleaned_error_message(error)
|