appsignal 3.9.3-java → 3.11.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -19
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +180 -0
- data/Gemfile +1 -0
- data/README.md +0 -1
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/build_matrix.yml +10 -12
- data/gemfiles/webmachine1.gemfile +5 -4
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/config.rb +57 -97
- data/lib/appsignal/demo.rb +15 -20
- data/lib/appsignal/environment.rb +6 -1
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
- data/lib/appsignal/event_formatter.rb +3 -2
- data/lib/appsignal/helpers/instrumentation.rb +490 -16
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +15 -14
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/shoryuken.rb +3 -63
- data/lib/appsignal/integrations/action_cable.rb +5 -7
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
- data/lib/appsignal/integrations/data_mapper.rb +1 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
- data/lib/appsignal/integrations/dry_monitor.rb +1 -0
- data/lib/appsignal/integrations/excon.rb +1 -0
- data/lib/appsignal/integrations/http.rb +1 -0
- data/lib/appsignal/integrations/net_http.rb +1 -0
- data/lib/appsignal/integrations/object.rb +6 -0
- data/lib/appsignal/integrations/padrino.rb +21 -25
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +1 -1
- data/lib/appsignal/integrations/rake.rb +45 -15
- data/lib/appsignal/integrations/redis.rb +1 -0
- data/lib/appsignal/integrations/redis_client.rb +1 -0
- data/lib/appsignal/integrations/resque.rb +2 -5
- data/lib/appsignal/integrations/shoryuken.rb +75 -0
- data/lib/appsignal/integrations/sidekiq.rb +7 -25
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +12 -9
- data/lib/appsignal/logger.rb +7 -3
- data/lib/appsignal/probes/helpers.rb +1 -0
- data/lib/appsignal/probes/mri.rb +1 -0
- data/lib/appsignal/probes/sidekiq.rb +1 -0
- data/lib/appsignal/probes.rb +3 -0
- data/lib/appsignal/rack/abstract_middleware.rb +67 -24
- data/lib/appsignal/rack/body_wrapper.rb +143 -0
- data/lib/appsignal/rack/event_handler.rb +39 -8
- data/lib/appsignal/rack/generic_instrumentation.rb +6 -4
- data/lib/appsignal/rack/grape_middleware.rb +3 -2
- data/lib/appsignal/rack/hanami_middleware.rb +1 -1
- data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +1 -3
- data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
- data/lib/appsignal/rack/streaming_listener.rb +14 -59
- data/lib/appsignal/rack.rb +60 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +353 -104
- data/lib/appsignal/utils/data.rb +0 -1
- data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
- data/lib/appsignal/utils/integration_logger.rb +0 -13
- data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
- data/lib/appsignal/utils/json.rb +0 -1
- data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
- data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
- data/lib/appsignal/utils.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +9 -6
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +139 -43
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/rake_spec.rb +100 -17
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +181 -131
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -2
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -17
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +144 -11
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
- data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -17
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +43 -120
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/transaction_spec.rb +1675 -953
- data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
- data/spec/lib/appsignal_spec.rb +517 -13
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/mocks/dummy_app.rb +1 -1
- data/spec/support/testing.rb +1 -1
- metadata +12 -4
- data/support/check_versions +0 -22
@@ -6,28 +6,80 @@ module Appsignal
|
|
6
6
|
class Transaction
|
7
7
|
HTTP_REQUEST = "http_request"
|
8
8
|
BACKGROUND_JOB = "background_job"
|
9
|
+
# @api private
|
9
10
|
ACTION_CABLE = "action_cable"
|
11
|
+
# @api private
|
10
12
|
FRONTEND = "frontend"
|
13
|
+
# @api private
|
11
14
|
BLANK = ""
|
15
|
+
# @api private
|
12
16
|
ALLOWED_TAG_KEY_TYPES = [Symbol, String].freeze
|
13
|
-
|
17
|
+
# @api private
|
18
|
+
ALLOWED_TAG_VALUE_TYPES = [Symbol, String, Integer, TrueClass, FalseClass].freeze
|
19
|
+
# @api private
|
14
20
|
BREADCRUMB_LIMIT = 20
|
21
|
+
# @api private
|
15
22
|
ERROR_CAUSES_LIMIT = 10
|
16
23
|
|
17
24
|
class << self
|
18
|
-
|
25
|
+
# Create a new transaction and set it as the currently active
|
26
|
+
# transaction.
|
27
|
+
#
|
28
|
+
# @param id_or_namespace [String] Namespace of the to be created transaction.
|
29
|
+
# @return [Transaction]
|
30
|
+
def create(id_or_namespace, arg_namespace = nil, request = nil, options = {})
|
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
|
19
53
|
# Allow middleware to force a new transaction
|
20
|
-
|
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
|
21
69
|
|
22
70
|
# Check if we already have a running transaction
|
23
71
|
if Thread.current[:appsignal_transaction].nil?
|
24
72
|
# If not, start a new transaction
|
25
73
|
Thread.current[:appsignal_transaction] =
|
26
|
-
Appsignal::Transaction.new(
|
74
|
+
Appsignal::Transaction.new(
|
75
|
+
id,
|
76
|
+
namespace,
|
77
|
+
request,
|
78
|
+
options
|
79
|
+
)
|
27
80
|
else
|
28
81
|
# Otherwise, log the issue about trying to start another transaction
|
29
|
-
Appsignal.internal_logger.
|
30
|
-
:transaction_id,
|
82
|
+
Appsignal.internal_logger.warn(
|
31
83
|
"Trying to start new transaction with id " \
|
32
84
|
"'#{id}', but a transaction with id '#{current.transaction_id}' " \
|
33
85
|
"is already running. Using transaction '#{current.transaction_id}'."
|
@@ -56,6 +108,8 @@ module Appsignal
|
|
56
108
|
current && !current.nil_transaction?
|
57
109
|
end
|
58
110
|
|
111
|
+
# Complete the currently active transaction and unset it as the active
|
112
|
+
# transaction.
|
59
113
|
def complete_current!
|
60
114
|
current.complete
|
61
115
|
rescue => e
|
@@ -73,21 +127,32 @@ module Appsignal
|
|
73
127
|
end
|
74
128
|
end
|
75
129
|
|
130
|
+
# @api private
|
76
131
|
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options,
|
77
|
-
:
|
132
|
+
:breadcrumbs, :custom_data
|
78
133
|
|
79
|
-
|
134
|
+
# Use {.create} to create new transactions.
|
135
|
+
#
|
136
|
+
# @param transaction_id [String] ID of the to be created transaction.
|
137
|
+
# @param namespace [String] Namespace of the to be created transaction.
|
138
|
+
# @see create
|
139
|
+
# @api private
|
140
|
+
def initialize(transaction_id, namespace, request = nil, options = {})
|
80
141
|
@transaction_id = transaction_id
|
81
142
|
@action = nil
|
82
143
|
@namespace = namespace
|
83
|
-
@request = request
|
144
|
+
@request = request || InternalGenericRequest.new({})
|
84
145
|
@paused = false
|
85
146
|
@discarded = false
|
86
147
|
@tags = {}
|
148
|
+
@custom_data = nil
|
87
149
|
@breadcrumbs = []
|
88
150
|
@store = Hash.new({})
|
89
151
|
@options = options
|
90
152
|
@options[:params_method] ||= :params
|
153
|
+
@params = nil
|
154
|
+
@session_data = nil
|
155
|
+
@headers = nil
|
91
156
|
|
92
157
|
@ext = Appsignal::Extension.start_transaction(
|
93
158
|
@transaction_id,
|
@@ -106,42 +171,57 @@ module Appsignal
|
|
106
171
|
"because it was manually discarded."
|
107
172
|
return
|
108
173
|
end
|
109
|
-
|
174
|
+
_sample_data if @ext.finish(0)
|
110
175
|
@ext.complete
|
111
176
|
end
|
112
177
|
|
178
|
+
# @api private
|
113
179
|
def pause!
|
114
180
|
@paused = true
|
115
181
|
end
|
116
182
|
|
183
|
+
# @api private
|
117
184
|
def resume!
|
118
185
|
@paused = false
|
119
186
|
end
|
120
187
|
|
188
|
+
# @api private
|
121
189
|
def paused?
|
122
190
|
@paused == true
|
123
191
|
end
|
124
192
|
|
193
|
+
# @api private
|
125
194
|
def discard!
|
126
195
|
@discarded = true
|
127
196
|
end
|
128
197
|
|
198
|
+
# @api private
|
129
199
|
def restore!
|
130
200
|
@discarded = false
|
131
201
|
end
|
132
202
|
|
203
|
+
# @api private
|
133
204
|
def discarded?
|
134
205
|
@discarded == true
|
135
206
|
end
|
136
207
|
|
208
|
+
# @api private
|
137
209
|
def store(key)
|
138
210
|
@store[key]
|
139
211
|
end
|
140
212
|
|
213
|
+
# @api private
|
141
214
|
def params
|
142
|
-
|
215
|
+
parameters = @params || request_params
|
143
216
|
|
144
|
-
|
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
|
145
225
|
end
|
146
226
|
|
147
227
|
# Set parameters on the transaction.
|
@@ -152,9 +232,17 @@ module Appsignal
|
|
152
232
|
# The parameters set using {#set_params} are leading over those extracted
|
153
233
|
# from a request's environment.
|
154
234
|
#
|
235
|
+
# When both the `given_params` and a block is given to this method, the
|
236
|
+
# `given_params` argument is leading and the block will _not_ be called.
|
237
|
+
#
|
238
|
+
# @since 3.9.1
|
155
239
|
# @param given_params [Hash] The parameters to set on the transaction.
|
240
|
+
# @yield This block is called when the transaction is sampled. The block's
|
241
|
+
# return value will become the new parameters.
|
156
242
|
# @return [void]
|
157
|
-
|
243
|
+
# @see Helpers::Instrumentation#set_params
|
244
|
+
def set_params(given_params = nil, &block)
|
245
|
+
@params = block if block
|
158
246
|
@params = given_params if given_params
|
159
247
|
end
|
160
248
|
|
@@ -172,14 +260,22 @@ module Appsignal
|
|
172
260
|
# When no parameters are set this way, the transaction will look for
|
173
261
|
# parameters on the {#request} environment.
|
174
262
|
#
|
263
|
+
# @since 3.9.1
|
175
264
|
# @param given_params [Hash] The parameters to set on the transaction if none are already set.
|
265
|
+
# @yield This block is called when the transaction is sampled. The block's
|
266
|
+
# return value will become the new parameters.
|
176
267
|
# @return [void]
|
177
|
-
|
178
|
-
|
268
|
+
#
|
269
|
+
# @see #set_params
|
270
|
+
# @see Helpers::Instrumentation#set_params_if_nil
|
271
|
+
def set_params_if_nil(given_params = nil, &block)
|
272
|
+
set_params(given_params, &block) unless @params
|
179
273
|
end
|
180
274
|
|
181
275
|
# Set tags on the transaction.
|
182
276
|
#
|
277
|
+
# When this method is called multiple times, it will merge the tags.
|
278
|
+
#
|
183
279
|
# @param given_tags [Hash] Collection of tags.
|
184
280
|
# @option given_tags [String, Symbol, Integer] :any
|
185
281
|
# The name of the tag as a Symbol.
|
@@ -187,13 +283,112 @@ module Appsignal
|
|
187
283
|
# The name of the tag as a String.
|
188
284
|
# @return [void]
|
189
285
|
#
|
190
|
-
# @see
|
286
|
+
# @see Helpers::Instrumentation#tag_request
|
191
287
|
# @see https://docs.appsignal.com/ruby/instrumentation/tagging.html
|
192
288
|
# Tagging guide
|
193
289
|
def set_tags(given_tags = {})
|
194
290
|
@tags.merge!(given_tags)
|
195
291
|
end
|
196
292
|
|
293
|
+
# Set session data on the transaction.
|
294
|
+
#
|
295
|
+
# When both the `given_session_data` and a block is given to this method,
|
296
|
+
# the `given_session_data` argument is leading and the block will _not_ be
|
297
|
+
# called.
|
298
|
+
#
|
299
|
+
# @param given_session_data [Hash] A hash containing session data.
|
300
|
+
# @yield This block is called when the transaction is sampled. The block's
|
301
|
+
# return value will become the new session data.
|
302
|
+
# @return [void]
|
303
|
+
#
|
304
|
+
# @since 3.10.1
|
305
|
+
# @see Helpers::Instrumentation#set_session_data
|
306
|
+
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
307
|
+
# Sample data guide
|
308
|
+
def set_session_data(given_session_data = nil, &block)
|
309
|
+
@session_data = block if block
|
310
|
+
@session_data = given_session_data if given_session_data
|
311
|
+
end
|
312
|
+
|
313
|
+
# Set session data on the transaction if not already set.
|
314
|
+
#
|
315
|
+
# When both the `given_session_data` and a block is given to this method,
|
316
|
+
# the `given_session_data` argument is leading and the block will _not_ be
|
317
|
+
# called.
|
318
|
+
#
|
319
|
+
# @param given_session_data [Hash] A hash containing session data.
|
320
|
+
# @yield This block is called when the transaction is sampled. The block's
|
321
|
+
# return value will become the new session data.
|
322
|
+
# @return [void]
|
323
|
+
#
|
324
|
+
# @since 3.10.1
|
325
|
+
# @see #set_session_data
|
326
|
+
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
327
|
+
# Sample data guide
|
328
|
+
def set_session_data_if_nil(given_session_data = nil, &block)
|
329
|
+
set_session_data(given_session_data, &block) unless @session_data
|
330
|
+
end
|
331
|
+
|
332
|
+
# Set headers on the transaction.
|
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.
|
337
|
+
#
|
338
|
+
# @param given_headers [Hash] A hash containing headers.
|
339
|
+
# @yield This block is called when the transaction is sampled. The block's
|
340
|
+
# return value will become the new headers.
|
341
|
+
# @return [void]
|
342
|
+
#
|
343
|
+
# @since 3.10.1
|
344
|
+
# @see Helpers::Instrumentation#set_headers
|
345
|
+
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
346
|
+
# Sample data guide
|
347
|
+
def set_headers(given_headers = nil, &block)
|
348
|
+
@headers = block if block
|
349
|
+
@headers = given_headers if given_headers
|
350
|
+
end
|
351
|
+
|
352
|
+
# Set headers on the transaction if not already set.
|
353
|
+
#
|
354
|
+
# When both the `given_headers` and a block is given to this method,
|
355
|
+
# the `given_headers` argument is leading and the block will _not_ be
|
356
|
+
# called.
|
357
|
+
#
|
358
|
+
# @param given_headers [Hash] A hash containing headers.
|
359
|
+
# @yield This block is called when the transaction is sampled. The block's
|
360
|
+
# return value will become the new headers.
|
361
|
+
# @return [void]
|
362
|
+
#
|
363
|
+
# @since 3.10.1
|
364
|
+
# @see #set_headers
|
365
|
+
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
366
|
+
# Sample data guide
|
367
|
+
def set_headers_if_nil(given_headers = nil, &block)
|
368
|
+
set_headers(given_headers, &block) unless @headers
|
369
|
+
end
|
370
|
+
|
371
|
+
# Set custom data on the transaction.
|
372
|
+
#
|
373
|
+
# When this method is called multiple times, it will overwrite the
|
374
|
+
# previously set value.
|
375
|
+
#
|
376
|
+
# @since 3.10.0
|
377
|
+
# @see Appsignal.set_custom_data
|
378
|
+
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
379
|
+
# Sample data guide
|
380
|
+
# @param data [Hash/Array]
|
381
|
+
# @return [void]
|
382
|
+
def set_custom_data(data)
|
383
|
+
case data
|
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
|
390
|
+
end
|
391
|
+
|
197
392
|
# Add breadcrumbs to the transaction.
|
198
393
|
#
|
199
394
|
# @param category [String] category of breadcrumb
|
@@ -284,6 +479,8 @@ module Appsignal
|
|
284
479
|
@ext.set_namespace(namespace)
|
285
480
|
end
|
286
481
|
|
482
|
+
# @deprecated Use the {#set_action} helper.
|
483
|
+
# @api private
|
287
484
|
def set_http_or_background_action(from = request.params)
|
288
485
|
return unless from
|
289
486
|
|
@@ -296,8 +493,6 @@ module Appsignal
|
|
296
493
|
|
297
494
|
# Set queue start time for transaction.
|
298
495
|
#
|
299
|
-
# Most commononly called by {set_http_or_background_queue_start}.
|
300
|
-
#
|
301
496
|
# @param start [Integer] Queue start time in milliseconds.
|
302
497
|
# @raise [RangeError] When the queue start time value is too big, this
|
303
498
|
# method raises a RangeError.
|
@@ -327,14 +522,21 @@ module Appsignal
|
|
327
522
|
# AppSignal as seconds.
|
328
523
|
#
|
329
524
|
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
525
|
+
# @deprecated Use {#set_queue_start} instead.
|
330
526
|
# @return [void]
|
331
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
|
+
|
332
533
|
start = http_queue_start || background_queue_start
|
333
534
|
return unless start
|
334
535
|
|
335
536
|
set_queue_start(start)
|
336
537
|
end
|
337
538
|
|
539
|
+
# @api private
|
338
540
|
def set_metadata(key, value)
|
339
541
|
return unless key && value
|
340
542
|
return if Appsignal.config[:filter_metadata].include?(key.to_s)
|
@@ -342,46 +544,29 @@ module Appsignal
|
|
342
544
|
@ext.set_metadata(key, value)
|
343
545
|
end
|
344
546
|
|
547
|
+
# @deprecated Use one of the set_tags, set_params, set_session_data,
|
548
|
+
# set_params or set_custom_data helpers instead.
|
549
|
+
# @api private
|
345
550
|
def set_sample_data(key, data)
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
"Invalid sample data for '#{key}'. Value is not an Array or Hash: '#{data.inspect}'"
|
351
|
-
)
|
352
|
-
return
|
353
|
-
end
|
354
|
-
|
355
|
-
@ext.set_sample_data(
|
356
|
-
key.to_s,
|
357
|
-
Appsignal::Utils::Data.generate(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."
|
358
555
|
)
|
359
|
-
|
360
|
-
begin
|
361
|
-
inspected_data = data.inspect
|
362
|
-
Appsignal.internal_logger.error(
|
363
|
-
"Error generating data (#{e.class}: #{e.message}) for '#{inspected_data}'"
|
364
|
-
)
|
365
|
-
rescue => e
|
366
|
-
Appsignal.internal_logger.error(
|
367
|
-
"Error generating data (#{e.class}: #{e.message}). Can't inspect data."
|
368
|
-
)
|
369
|
-
end
|
556
|
+
_set_sample_data(key, data)
|
370
557
|
end
|
371
558
|
|
559
|
+
# @deprecated No replacement.
|
560
|
+
# @api private
|
372
561
|
def sample_data
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
:tags => sanitized_tags,
|
379
|
-
:breadcrumbs => breadcrumbs
|
380
|
-
}.each do |key, data|
|
381
|
-
set_sample_data(key, data)
|
382
|
-
end
|
562
|
+
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
563
|
+
"Appsignal::Transaction#sample_data is deprecated. " \
|
564
|
+
"Please remove any calls to this method."
|
565
|
+
)
|
566
|
+
_sample_data
|
383
567
|
end
|
384
568
|
|
569
|
+
# @see Appsignal::Helpers::Instrumentation#set_error
|
385
570
|
def set_error(error)
|
386
571
|
unless error.is_a?(Exception)
|
387
572
|
Appsignal.internal_logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
|
@@ -428,19 +613,23 @@ module Appsignal
|
|
428
613
|
|
429
614
|
causes_sample_data.last[:is_root_cause] = false if root_cause_missing
|
430
615
|
|
431
|
-
|
616
|
+
_set_sample_data(
|
432
617
|
"error_causes",
|
433
618
|
causes_sample_data
|
434
619
|
)
|
435
620
|
end
|
436
621
|
alias_method :add_exception, :set_error
|
437
622
|
|
623
|
+
# @see Helpers::Instrumentation#instrument
|
624
|
+
# @api private
|
438
625
|
def start_event
|
439
626
|
return if paused?
|
440
627
|
|
441
628
|
@ext.start_event(0)
|
442
629
|
end
|
443
630
|
|
631
|
+
# @see Helpers::Instrumentation#instrument
|
632
|
+
# @api private
|
444
633
|
def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
|
445
634
|
return if paused?
|
446
635
|
|
@@ -453,6 +642,8 @@ module Appsignal
|
|
453
642
|
)
|
454
643
|
end
|
455
644
|
|
645
|
+
# @see Helpers::Instrumentation#instrument
|
646
|
+
# @api private
|
456
647
|
def record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT)
|
457
648
|
return if paused?
|
458
649
|
|
@@ -466,6 +657,7 @@ module Appsignal
|
|
466
657
|
)
|
467
658
|
end
|
468
659
|
|
660
|
+
# @see Helpers::Instrumentation#instrument
|
469
661
|
def instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT)
|
470
662
|
start_event
|
471
663
|
yield if block_given?
|
@@ -479,7 +671,8 @@ module Appsignal
|
|
479
671
|
end
|
480
672
|
alias_method :to_hash, :to_h
|
481
673
|
|
482
|
-
|
674
|
+
# @api private
|
675
|
+
class InternalGenericRequest
|
483
676
|
attr_reader :env
|
484
677
|
|
485
678
|
def initialize(env)
|
@@ -491,8 +684,64 @@ module Appsignal
|
|
491
684
|
end
|
492
685
|
end
|
493
686
|
|
687
|
+
# @deprecated Use the instrumentation helpers to set metadata on the
|
688
|
+
# transaction, rather than rely on the GenericRequest automation. See the
|
689
|
+
# {Helpers::Instrumentation} module for a list of helpers.
|
690
|
+
# @api private
|
691
|
+
class GenericRequest < InternalGenericRequest
|
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
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
494
702
|
private
|
495
703
|
|
704
|
+
def _set_sample_data(key, data)
|
705
|
+
return unless key && data
|
706
|
+
|
707
|
+
if !data.is_a?(Array) && !data.is_a?(Hash)
|
708
|
+
Appsignal.internal_logger.error(
|
709
|
+
"Invalid sample data for '#{key}'. Value is not an Array or Hash: '#{data.inspect}'"
|
710
|
+
)
|
711
|
+
return
|
712
|
+
end
|
713
|
+
|
714
|
+
@ext.set_sample_data(
|
715
|
+
key.to_s,
|
716
|
+
Appsignal::Utils::Data.generate(data)
|
717
|
+
)
|
718
|
+
rescue RuntimeError => e
|
719
|
+
begin
|
720
|
+
inspected_data = data.inspect
|
721
|
+
Appsignal.internal_logger.error(
|
722
|
+
"Error generating data (#{e.class}: #{e.message}) for '#{inspected_data}'"
|
723
|
+
)
|
724
|
+
rescue => e
|
725
|
+
Appsignal.internal_logger.error(
|
726
|
+
"Error generating data (#{e.class}: #{e.message}). Can't inspect data."
|
727
|
+
)
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
def _sample_data
|
732
|
+
{
|
733
|
+
:params => sanitized_params,
|
734
|
+
:environment => sanitized_environment,
|
735
|
+
:session_data => sanitized_session_data,
|
736
|
+
:metadata => sanitized_metadata,
|
737
|
+
:tags => sanitized_tags,
|
738
|
+
:breadcrumbs => breadcrumbs,
|
739
|
+
:custom_data => custom_data
|
740
|
+
}.each do |key, data|
|
741
|
+
_set_sample_data(key, data)
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
496
745
|
# Returns calculated background queue start time in milliseconds, based on
|
497
746
|
# environment values.
|
498
747
|
#
|
@@ -516,25 +765,7 @@ module Appsignal
|
|
516
765
|
# @return [Integer] queue start in milliseconds.
|
517
766
|
def http_queue_start
|
518
767
|
env = environment
|
519
|
-
|
520
|
-
|
521
|
-
env_var = env["HTTP_X_QUEUE_START"] || env["HTTP_X_REQUEST_START"]
|
522
|
-
return unless env_var
|
523
|
-
|
524
|
-
cleaned_value = env_var.tr("^0-9", "")
|
525
|
-
return if cleaned_value.empty?
|
526
|
-
|
527
|
-
value = cleaned_value.to_i
|
528
|
-
if value > 4_102_441_200_000
|
529
|
-
# Value is in microseconds. Transform to milliseconds.
|
530
|
-
value / 1_000
|
531
|
-
elsif value < 946_681_200_000
|
532
|
-
# Value is too low to be plausible
|
533
|
-
nil
|
534
|
-
else
|
535
|
-
# Value is in milliseconds
|
536
|
-
value
|
537
|
-
end
|
768
|
+
Appsignal::Rack::Utils.queue_start_from(env)
|
538
769
|
end
|
539
770
|
|
540
771
|
def sanitized_params
|
@@ -550,28 +781,25 @@ module Appsignal
|
|
550
781
|
begin
|
551
782
|
request.send options[:params_method]
|
552
783
|
rescue => e
|
553
|
-
|
554
|
-
Appsignal.internal_logger.debug "Exception while getting params: #{e}"
|
784
|
+
Appsignal.internal_logger.warn "Exception while getting params: #{e}"
|
555
785
|
nil
|
556
786
|
end
|
557
787
|
end
|
558
788
|
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
# @return [Hash<String, Object>]
|
566
|
-
def sanitized_environment
|
567
|
-
env = environment
|
568
|
-
return if env.empty?
|
569
|
-
|
570
|
-
{}.tap do |out|
|
571
|
-
Appsignal.config[:request_headers].each do |key|
|
572
|
-
out[key] = env[key] if env[key]
|
789
|
+
def session_data
|
790
|
+
if @session_data
|
791
|
+
if @session_data.respond_to? :call
|
792
|
+
@session_data.call
|
793
|
+
else
|
794
|
+
@session_data
|
573
795
|
end
|
796
|
+
elsif request.respond_to?(:session)
|
797
|
+
request.session
|
574
798
|
end
|
799
|
+
rescue => e
|
800
|
+
Appsignal.internal_logger.error \
|
801
|
+
"Exception while fetching session data: #{e.class}: #{e}"
|
802
|
+
nil
|
575
803
|
end
|
576
804
|
|
577
805
|
# Returns sanitized session data.
|
@@ -583,23 +811,21 @@ module Appsignal
|
|
583
811
|
# @return [nil] if the {#request} session data is `nil`.
|
584
812
|
# @return [Hash<String, Object>]
|
585
813
|
def sanitized_session_data
|
586
|
-
return
|
587
|
-
!request.respond_to?(:session)
|
588
|
-
|
589
|
-
session = request.session
|
590
|
-
return unless session
|
814
|
+
return unless Appsignal.config[:send_session_data]
|
591
815
|
|
592
816
|
Appsignal::Utils::HashSanitizer.sanitize(
|
593
|
-
|
817
|
+
session_data&.to_hash, Appsignal.config[:filter_session_data]
|
594
818
|
)
|
595
819
|
end
|
596
820
|
|
597
|
-
# Returns sanitized metadata set
|
598
|
-
# {#environment}.
|
821
|
+
# Returns sanitized metadata set on the request environment.
|
599
822
|
#
|
600
823
|
# @return [Hash<String, Object>]
|
601
824
|
def sanitized_metadata
|
602
|
-
|
825
|
+
env = environment
|
826
|
+
return unless env
|
827
|
+
|
828
|
+
metadata = env[:metadata]
|
603
829
|
return unless metadata
|
604
830
|
|
605
831
|
metadata
|
@@ -607,17 +833,40 @@ module Appsignal
|
|
607
833
|
.reject { |key, _value| Appsignal.config[:filter_metadata].include?(key) }
|
608
834
|
end
|
609
835
|
|
610
|
-
|
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
|
846
|
+
rescue => e
|
847
|
+
Appsignal.internal_logger.error \
|
848
|
+
"Exception while fetching headers: #{e.class}: #{e}"
|
849
|
+
nil
|
850
|
+
end
|
851
|
+
|
852
|
+
# Returns sanitized environment for a transaction.
|
611
853
|
#
|
612
|
-
#
|
613
|
-
#
|
854
|
+
# The environment of a transaction can contain a lot of information, not
|
855
|
+
# all of it useful for debugging.
|
614
856
|
#
|
857
|
+
# @return [nil] if no environment is present.
|
615
858
|
# @return [Hash<String, Object>]
|
616
|
-
def
|
617
|
-
|
618
|
-
return
|
859
|
+
def sanitized_environment
|
860
|
+
env = environment
|
861
|
+
return unless env
|
862
|
+
return unless env.respond_to?(:empty?)
|
863
|
+
return if env.empty?
|
619
864
|
|
620
|
-
|
865
|
+
{}.tap do |out|
|
866
|
+
Appsignal.config[:request_headers].each do |key|
|
867
|
+
out[key] = env[key] if env[key]
|
868
|
+
end
|
869
|
+
end
|
621
870
|
end
|
622
871
|
|
623
872
|
# Only keep tags if they meet the following criteria:
|