appsignal 3.10.0 → 3.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +197 -0
- data/Gemfile +1 -0
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +204 -130
- data/lib/appsignal/demo.rb +16 -26
- 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 +331 -19
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +14 -8
- 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/grape.rb +7 -0
- data/lib/appsignal/integrations/hanami.rb +8 -43
- 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 +8 -73
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +36 -14
- data/lib/appsignal/integrations/rake.rb +1 -5
- 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 -15
- data/lib/appsignal/integrations/sinatra.rb +8 -19
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +2 -5
- data/lib/appsignal/loaders/grape.rb +13 -0
- data/lib/appsignal/loaders/hanami.rb +40 -0
- data/lib/appsignal/loaders/padrino.rb +68 -0
- data/lib/appsignal/loaders/sinatra.rb +24 -0
- data/lib/appsignal/loaders.rb +92 -0
- 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 +20 -13
- data/lib/appsignal/rack/event_handler.rb +44 -13
- data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
- data/lib/appsignal/rack/grape_middleware.rb +2 -1
- data/lib/appsignal/rack/streaming_listener.rb +1 -0
- data/lib/appsignal/rack.rb +35 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +308 -101
- 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 +169 -14
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
- data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
- data/spec/lib/appsignal/config_spec.rb +291 -44
- data/spec/lib/appsignal/demo_spec.rb +1 -2
- data/spec/lib/appsignal/environment_spec.rb +4 -2
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
- data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
- data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
- data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
- data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
- data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
- data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
- data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
- data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
- data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
- data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
- data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
- data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
- data/spec/lib/appsignal/loaders_spec.rb +137 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/probes_spec.rb +6 -5
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
- data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
- data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/span_spec.rb +1 -3
- data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
- 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 +601 -36
- data/spec/lib/puma/appsignal_spec.rb +0 -3
- data/spec/spec_helper.rb +5 -4
- data/spec/support/helpers/config_helpers.rb +2 -1
- data/spec/support/helpers/loader_helper.rb +21 -0
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
- data/spec/support/testing.rb +47 -1
- metadata +19 -2
@@ -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,14 +127,21 @@ 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 = {}
|
@@ -90,6 +151,8 @@ module Appsignal
|
|
90
151
|
@options = options
|
91
152
|
@options[:params_method] ||= :params
|
92
153
|
@params = nil
|
154
|
+
@session_data = nil
|
155
|
+
@headers = nil
|
93
156
|
|
94
157
|
@ext = Appsignal::Extension.start_transaction(
|
95
158
|
@transaction_id,
|
@@ -108,38 +171,46 @@ module Appsignal
|
|
108
171
|
"because it was manually discarded."
|
109
172
|
return
|
110
173
|
end
|
111
|
-
|
174
|
+
_sample_data if @ext.finish(0)
|
112
175
|
@ext.complete
|
113
176
|
end
|
114
177
|
|
178
|
+
# @api private
|
115
179
|
def pause!
|
116
180
|
@paused = true
|
117
181
|
end
|
118
182
|
|
183
|
+
# @api private
|
119
184
|
def resume!
|
120
185
|
@paused = false
|
121
186
|
end
|
122
187
|
|
188
|
+
# @api private
|
123
189
|
def paused?
|
124
190
|
@paused == true
|
125
191
|
end
|
126
192
|
|
193
|
+
# @api private
|
127
194
|
def discard!
|
128
195
|
@discarded = true
|
129
196
|
end
|
130
197
|
|
198
|
+
# @api private
|
131
199
|
def restore!
|
132
200
|
@discarded = false
|
133
201
|
end
|
134
202
|
|
203
|
+
# @api private
|
135
204
|
def discarded?
|
136
205
|
@discarded == true
|
137
206
|
end
|
138
207
|
|
208
|
+
# @api private
|
139
209
|
def store(key)
|
140
210
|
@store[key]
|
141
211
|
end
|
142
212
|
|
213
|
+
# @api private
|
143
214
|
def params
|
144
215
|
parameters = @params || request_params
|
145
216
|
|
@@ -148,6 +219,9 @@ module Appsignal
|
|
148
219
|
else
|
149
220
|
parameters
|
150
221
|
end
|
222
|
+
rescue => e
|
223
|
+
Appsignal.internal_logger.error("Exception while fetching params: #{e.class}: #{e}")
|
224
|
+
nil
|
151
225
|
end
|
152
226
|
|
153
227
|
# Set parameters on the transaction.
|
@@ -166,7 +240,7 @@ module Appsignal
|
|
166
240
|
# @yield This block is called when the transaction is sampled. The block's
|
167
241
|
# return value will become the new parameters.
|
168
242
|
# @return [void]
|
169
|
-
# @see
|
243
|
+
# @see Helpers::Instrumentation#set_params
|
170
244
|
def set_params(given_params = nil, &block)
|
171
245
|
@params = block if block
|
172
246
|
@params = given_params if given_params
|
@@ -191,7 +265,9 @@ module Appsignal
|
|
191
265
|
# @yield This block is called when the transaction is sampled. The block's
|
192
266
|
# return value will become the new parameters.
|
193
267
|
# @return [void]
|
194
|
-
#
|
268
|
+
#
|
269
|
+
# @see #set_params
|
270
|
+
# @see Helpers::Instrumentation#set_params_if_nil
|
195
271
|
def set_params_if_nil(given_params = nil, &block)
|
196
272
|
set_params(given_params, &block) unless @params
|
197
273
|
end
|
@@ -214,6 +290,84 @@ module Appsignal
|
|
214
290
|
@tags.merge!(given_tags)
|
215
291
|
end
|
216
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
|
+
|
217
371
|
# Set custom data on the transaction.
|
218
372
|
#
|
219
373
|
# When this method is called multiple times, it will overwrite the
|
@@ -325,6 +479,8 @@ module Appsignal
|
|
325
479
|
@ext.set_namespace(namespace)
|
326
480
|
end
|
327
481
|
|
482
|
+
# @deprecated Use the {#set_action} helper.
|
483
|
+
# @api private
|
328
484
|
def set_http_or_background_action(from = request.params)
|
329
485
|
return unless from
|
330
486
|
|
@@ -337,8 +493,6 @@ module Appsignal
|
|
337
493
|
|
338
494
|
# Set queue start time for transaction.
|
339
495
|
#
|
340
|
-
# Most commononly called by {set_http_or_background_queue_start}.
|
341
|
-
#
|
342
496
|
# @param start [Integer] Queue start time in milliseconds.
|
343
497
|
# @raise [RangeError] When the queue start time value is too big, this
|
344
498
|
# method raises a RangeError.
|
@@ -368,14 +522,21 @@ module Appsignal
|
|
368
522
|
# AppSignal as seconds.
|
369
523
|
#
|
370
524
|
# @see https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html
|
525
|
+
# @deprecated Use {#set_queue_start} instead.
|
371
526
|
# @return [void]
|
372
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
|
+
|
373
533
|
start = http_queue_start || background_queue_start
|
374
534
|
return unless start
|
375
535
|
|
376
536
|
set_queue_start(start)
|
377
537
|
end
|
378
538
|
|
539
|
+
# @api private
|
379
540
|
def set_metadata(key, value)
|
380
541
|
return unless key && value
|
381
542
|
return if Appsignal.config[:filter_metadata].include?(key.to_s)
|
@@ -383,47 +544,29 @@ module Appsignal
|
|
383
544
|
@ext.set_metadata(key, value)
|
384
545
|
end
|
385
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
|
386
550
|
def set_sample_data(key, data)
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
"Invalid sample data for '#{key}'. Value is not an Array or Hash: '#{data.inspect}'"
|
392
|
-
)
|
393
|
-
return
|
394
|
-
end
|
395
|
-
|
396
|
-
@ext.set_sample_data(
|
397
|
-
key.to_s,
|
398
|
-
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."
|
399
555
|
)
|
400
|
-
|
401
|
-
begin
|
402
|
-
inspected_data = data.inspect
|
403
|
-
Appsignal.internal_logger.error(
|
404
|
-
"Error generating data (#{e.class}: #{e.message}) for '#{inspected_data}'"
|
405
|
-
)
|
406
|
-
rescue => e
|
407
|
-
Appsignal.internal_logger.error(
|
408
|
-
"Error generating data (#{e.class}: #{e.message}). Can't inspect data."
|
409
|
-
)
|
410
|
-
end
|
556
|
+
_set_sample_data(key, data)
|
411
557
|
end
|
412
558
|
|
559
|
+
# @deprecated No replacement.
|
560
|
+
# @api private
|
413
561
|
def sample_data
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
:tags => sanitized_tags,
|
420
|
-
:breadcrumbs => breadcrumbs,
|
421
|
-
:custom_data => custom_data
|
422
|
-
}.each do |key, data|
|
423
|
-
set_sample_data(key, data)
|
424
|
-
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
|
425
567
|
end
|
426
568
|
|
569
|
+
# @see Appsignal::Helpers::Instrumentation#set_error
|
427
570
|
def set_error(error)
|
428
571
|
unless error.is_a?(Exception)
|
429
572
|
Appsignal.internal_logger.error "Appsignal::Transaction#set_error: Cannot set error. " \
|
@@ -470,19 +613,23 @@ module Appsignal
|
|
470
613
|
|
471
614
|
causes_sample_data.last[:is_root_cause] = false if root_cause_missing
|
472
615
|
|
473
|
-
|
616
|
+
_set_sample_data(
|
474
617
|
"error_causes",
|
475
618
|
causes_sample_data
|
476
619
|
)
|
477
620
|
end
|
478
621
|
alias_method :add_exception, :set_error
|
479
622
|
|
623
|
+
# @see Helpers::Instrumentation#instrument
|
624
|
+
# @api private
|
480
625
|
def start_event
|
481
626
|
return if paused?
|
482
627
|
|
483
628
|
@ext.start_event(0)
|
484
629
|
end
|
485
630
|
|
631
|
+
# @see Helpers::Instrumentation#instrument
|
632
|
+
# @api private
|
486
633
|
def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
|
487
634
|
return if paused?
|
488
635
|
|
@@ -495,6 +642,8 @@ module Appsignal
|
|
495
642
|
)
|
496
643
|
end
|
497
644
|
|
645
|
+
# @see Helpers::Instrumentation#instrument
|
646
|
+
# @api private
|
498
647
|
def record_event(name, title, body, duration, body_format = Appsignal::EventFormatter::DEFAULT)
|
499
648
|
return if paused?
|
500
649
|
|
@@ -508,6 +657,7 @@ module Appsignal
|
|
508
657
|
)
|
509
658
|
end
|
510
659
|
|
660
|
+
# @see Helpers::Instrumentation#instrument
|
511
661
|
def instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT)
|
512
662
|
start_event
|
513
663
|
yield if block_given?
|
@@ -521,7 +671,8 @@ module Appsignal
|
|
521
671
|
end
|
522
672
|
alias_method :to_hash, :to_h
|
523
673
|
|
524
|
-
|
674
|
+
# @api private
|
675
|
+
class InternalGenericRequest
|
525
676
|
attr_reader :env
|
526
677
|
|
527
678
|
def initialize(env)
|
@@ -533,8 +684,64 @@ module Appsignal
|
|
533
684
|
end
|
534
685
|
end
|
535
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
|
+
|
536
702
|
private
|
537
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
|
+
|
538
745
|
# Returns calculated background queue start time in milliseconds, based on
|
539
746
|
# environment values.
|
540
747
|
#
|
@@ -558,25 +765,7 @@ module Appsignal
|
|
558
765
|
# @return [Integer] queue start in milliseconds.
|
559
766
|
def http_queue_start
|
560
767
|
env = environment
|
561
|
-
|
562
|
-
|
563
|
-
env_var = env["HTTP_X_QUEUE_START"] || env["HTTP_X_REQUEST_START"]
|
564
|
-
return unless env_var
|
565
|
-
|
566
|
-
cleaned_value = env_var.tr("^0-9", "")
|
567
|
-
return if cleaned_value.empty?
|
568
|
-
|
569
|
-
value = cleaned_value.to_i
|
570
|
-
if value > 4_102_441_200_000
|
571
|
-
# Value is in microseconds. Transform to milliseconds.
|
572
|
-
value / 1_000
|
573
|
-
elsif value < 946_681_200_000
|
574
|
-
# Value is too low to be plausible
|
575
|
-
nil
|
576
|
-
else
|
577
|
-
# Value is in milliseconds
|
578
|
-
value
|
579
|
-
end
|
768
|
+
Appsignal::Rack::Utils.queue_start_from(env)
|
580
769
|
end
|
581
770
|
|
582
771
|
def sanitized_params
|
@@ -592,28 +781,25 @@ module Appsignal
|
|
592
781
|
begin
|
593
782
|
request.send options[:params_method]
|
594
783
|
rescue => e
|
595
|
-
|
596
|
-
Appsignal.internal_logger.debug "Exception while getting params: #{e}"
|
784
|
+
Appsignal.internal_logger.warn "Exception while getting params: #{e}"
|
597
785
|
nil
|
598
786
|
end
|
599
787
|
end
|
600
788
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
# @return [Hash<String, Object>]
|
608
|
-
def sanitized_environment
|
609
|
-
env = environment
|
610
|
-
return if env.empty?
|
611
|
-
|
612
|
-
{}.tap do |out|
|
613
|
-
Appsignal.config[:request_headers].each do |key|
|
614
|
-
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
|
615
795
|
end
|
796
|
+
elsif request.respond_to?(:session)
|
797
|
+
request.session
|
616
798
|
end
|
799
|
+
rescue => e
|
800
|
+
Appsignal.internal_logger.error \
|
801
|
+
"Exception while fetching session data: #{e.class}: #{e}"
|
802
|
+
nil
|
617
803
|
end
|
618
804
|
|
619
805
|
# Returns sanitized session data.
|
@@ -625,23 +811,21 @@ module Appsignal
|
|
625
811
|
# @return [nil] if the {#request} session data is `nil`.
|
626
812
|
# @return [Hash<String, Object>]
|
627
813
|
def sanitized_session_data
|
628
|
-
return
|
629
|
-
!request.respond_to?(:session)
|
630
|
-
|
631
|
-
session = request.session
|
632
|
-
return unless session
|
814
|
+
return unless Appsignal.config[:send_session_data]
|
633
815
|
|
634
816
|
Appsignal::Utils::HashSanitizer.sanitize(
|
635
|
-
|
817
|
+
session_data&.to_hash, Appsignal.config[:filter_session_data]
|
636
818
|
)
|
637
819
|
end
|
638
820
|
|
639
|
-
# Returns sanitized metadata set
|
640
|
-
# {#environment}.
|
821
|
+
# Returns sanitized metadata set on the request environment.
|
641
822
|
#
|
642
823
|
# @return [Hash<String, Object>]
|
643
824
|
def sanitized_metadata
|
644
|
-
|
825
|
+
env = environment
|
826
|
+
return unless env
|
827
|
+
|
828
|
+
metadata = env[:metadata]
|
645
829
|
return unless metadata
|
646
830
|
|
647
831
|
metadata
|
@@ -649,17 +833,40 @@ module Appsignal
|
|
649
833
|
.reject { |key, _value| Appsignal.config[:filter_metadata].include?(key) }
|
650
834
|
end
|
651
835
|
|
652
|
-
|
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.
|
653
853
|
#
|
654
|
-
#
|
655
|
-
#
|
854
|
+
# The environment of a transaction can contain a lot of information, not
|
855
|
+
# all of it useful for debugging.
|
656
856
|
#
|
857
|
+
# @return [nil] if no environment is present.
|
657
858
|
# @return [Hash<String, Object>]
|
658
|
-
def
|
659
|
-
|
660
|
-
return
|
859
|
+
def sanitized_environment
|
860
|
+
env = environment
|
861
|
+
return unless env
|
862
|
+
return unless env.respond_to?(:empty?)
|
863
|
+
return if env.empty?
|
661
864
|
|
662
|
-
|
865
|
+
{}.tap do |out|
|
866
|
+
Appsignal.config[:request_headers].each do |key|
|
867
|
+
out[key] = env[key] if env[key]
|
868
|
+
end
|
869
|
+
end
|
663
870
|
end
|
664
871
|
|
665
872
|
# Only keep tags if they meet the following criteria:
|
data/lib/appsignal/utils/data.rb
CHANGED
@@ -2,20 +2,7 @@
|
|
2
2
|
|
3
3
|
module Appsignal
|
4
4
|
module Utils
|
5
|
-
# Subclass of logger with method to only log a warning once
|
6
|
-
# prevents the local log from filling up with repeated messages.
|
7
5
|
class IntegrationLogger < ::Logger
|
8
|
-
def seen_keys
|
9
|
-
@seen_keys ||= Set.new
|
10
|
-
end
|
11
|
-
|
12
|
-
def warn_once_then_debug(key, message)
|
13
|
-
if seen_keys.add?(key).nil?
|
14
|
-
debug message
|
15
|
-
else
|
16
|
-
warn message
|
17
|
-
end
|
18
|
-
end
|
19
6
|
end
|
20
7
|
end
|
21
8
|
end
|