appsignal 3.13.0-java → 4.0.0.beta.2-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 +121 -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 +2 -15
- 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 +152 -416
- 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/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 +108 -0
- data/lib/appsignal/transaction.rb +241 -359
- data/lib/appsignal/utils/rails_helper.rb +4 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +19 -71
- 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/check_in_spec.rb +1 -207
- 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/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 +213 -0
- data/spec/lib/appsignal/transaction_spec.rb +817 -1046
- data/spec/lib/appsignal/transmitter_spec.rb +6 -8
- data/spec/lib/appsignal_spec.rb +311 -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 +12 -22
- data/gemfiles/que_beta.gemfile +0 -5
- data/lib/appsignal/helpers/heartbeat.rb +0 -20
- 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,48 @@ 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
|
|
243
|
+
# @see Helpers::Instrumentation#add_params
|
|
244
|
+
def add_params(given_params = nil, &block)
|
|
245
|
+
@params.add(given_params, &block)
|
|
247
246
|
end
|
|
247
|
+
alias :set_params :add_params
|
|
248
248
|
|
|
249
|
-
# @
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
set_params(given_params)
|
|
249
|
+
# @api private
|
|
250
|
+
# @since 4.0.0
|
|
251
|
+
# @return [void]
|
|
252
|
+
# @see Helpers::Instrumentation#set_empty_params!
|
|
253
|
+
def set_empty_params!
|
|
254
|
+
@params.set_empty_value!
|
|
256
255
|
end
|
|
257
256
|
|
|
258
|
-
#
|
|
257
|
+
# Add parameters to the transaction if not already set.
|
|
259
258
|
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
263
|
-
# @since 3.9.1
|
|
259
|
+
# @api private
|
|
260
|
+
# @since 4.0.0
|
|
264
261
|
# @param given_params [Hash] The parameters to set on the transaction if none are already set.
|
|
265
262
|
# @yield This block is called when the transaction is sampled. The block's
|
|
266
263
|
# return value will become the new parameters.
|
|
267
264
|
# @return [void]
|
|
268
265
|
#
|
|
269
|
-
# @see #
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
set_params(given_params, &block) unless @params
|
|
266
|
+
# @see #add_params
|
|
267
|
+
def add_params_if_nil(given_params = nil, &block)
|
|
268
|
+
add_params(given_params, &block) if !@params.value? && !@params.empty?
|
|
273
269
|
end
|
|
270
|
+
alias :set_params_if_nil :add_params_if_nil
|
|
274
271
|
|
|
275
|
-
#
|
|
272
|
+
# Add tags to the transaction.
|
|
276
273
|
#
|
|
277
274
|
# When this method is called multiple times, it will merge the tags.
|
|
278
275
|
#
|
|
@@ -283,32 +280,34 @@ module Appsignal
|
|
|
283
280
|
# The name of the tag as a String.
|
|
284
281
|
# @return [void]
|
|
285
282
|
#
|
|
286
|
-
# @see Helpers::Instrumentation#
|
|
283
|
+
# @see Helpers::Instrumentation#add_tags
|
|
287
284
|
# @see https://docs.appsignal.com/ruby/instrumentation/tagging.html
|
|
288
285
|
# Tagging guide
|
|
289
|
-
def
|
|
286
|
+
def add_tags(given_tags = {})
|
|
290
287
|
@tags.merge!(given_tags)
|
|
291
288
|
end
|
|
289
|
+
alias :set_tags add_tags
|
|
292
290
|
|
|
293
|
-
#
|
|
291
|
+
# Add session data to the transaction.
|
|
292
|
+
#
|
|
293
|
+
# When this method is called multiple times, it will merge the session data.
|
|
294
294
|
#
|
|
295
295
|
# When both the `given_session_data` and a block is given to this method,
|
|
296
|
-
# the
|
|
297
|
-
# called.
|
|
296
|
+
# the block is leading and the argument will _not_ be used.
|
|
298
297
|
#
|
|
299
298
|
# @param given_session_data [Hash] A hash containing session data.
|
|
300
299
|
# @yield This block is called when the transaction is sampled. The block's
|
|
301
300
|
# return value will become the new session data.
|
|
302
301
|
# @return [void]
|
|
303
302
|
#
|
|
304
|
-
# @since
|
|
305
|
-
# @see Helpers::Instrumentation#
|
|
303
|
+
# @since 4.0.0
|
|
304
|
+
# @see Helpers::Instrumentation#add_session_data
|
|
306
305
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
|
307
306
|
# Sample data guide
|
|
308
|
-
def
|
|
309
|
-
@session_data
|
|
310
|
-
@session_data = given_session_data if given_session_data
|
|
307
|
+
def add_session_data(given_session_data = nil, &block)
|
|
308
|
+
@session_data.add(given_session_data, &block)
|
|
311
309
|
end
|
|
310
|
+
alias :set_session_data :add_session_data
|
|
312
311
|
|
|
313
312
|
# Set session data on the transaction if not already set.
|
|
314
313
|
#
|
|
@@ -321,73 +320,64 @@ module Appsignal
|
|
|
321
320
|
# return value will become the new session data.
|
|
322
321
|
# @return [void]
|
|
323
322
|
#
|
|
324
|
-
# @
|
|
325
|
-
# @
|
|
323
|
+
# @api private
|
|
324
|
+
# @since 4.0.0
|
|
325
|
+
# @see #add_session_data
|
|
326
326
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
|
327
327
|
# Sample data guide
|
|
328
|
-
def
|
|
329
|
-
|
|
328
|
+
def add_session_data_if_nil(given_session_data = nil, &block)
|
|
329
|
+
add_session_data(given_session_data, &block) unless @session_data.value?
|
|
330
330
|
end
|
|
331
|
+
alias :set_session_data_if_nil :add_session_data_if_nil
|
|
331
332
|
|
|
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.
|
|
333
|
+
# Add headers to the transaction.
|
|
337
334
|
#
|
|
338
335
|
# @param given_headers [Hash] A hash containing headers.
|
|
339
336
|
# @yield This block is called when the transaction is sampled. The block's
|
|
340
337
|
# return value will become the new headers.
|
|
341
338
|
# @return [void]
|
|
342
339
|
#
|
|
343
|
-
# @since
|
|
344
|
-
# @see Helpers::Instrumentation#
|
|
340
|
+
# @since 4.0.0
|
|
341
|
+
# @see Helpers::Instrumentation#add_headers
|
|
345
342
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
|
346
343
|
# Sample data guide
|
|
347
|
-
def
|
|
348
|
-
@headers
|
|
349
|
-
@headers = given_headers if given_headers
|
|
344
|
+
def add_headers(given_headers = nil, &block)
|
|
345
|
+
@headers.add(given_headers, &block)
|
|
350
346
|
end
|
|
347
|
+
alias :set_headers :add_headers
|
|
351
348
|
|
|
352
|
-
#
|
|
349
|
+
# Add headers to the transaction if not already set.
|
|
353
350
|
#
|
|
354
351
|
# When both the `given_headers` and a block is given to this method,
|
|
355
|
-
# the
|
|
356
|
-
# called.
|
|
352
|
+
# the block is leading and the argument will _not_ be used.
|
|
357
353
|
#
|
|
358
354
|
# @param given_headers [Hash] A hash containing headers.
|
|
359
355
|
# @yield This block is called when the transaction is sampled. The block's
|
|
360
356
|
# return value will become the new headers.
|
|
361
357
|
# @return [void]
|
|
362
358
|
#
|
|
363
|
-
# @
|
|
364
|
-
# @
|
|
359
|
+
# @api private
|
|
360
|
+
# @since 4.0.0
|
|
361
|
+
# @see #add_headers
|
|
365
362
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
|
366
363
|
# Sample data guide
|
|
367
|
-
def
|
|
368
|
-
|
|
364
|
+
def add_headers_if_nil(given_headers = nil, &block)
|
|
365
|
+
add_headers(given_headers, &block) unless @headers.value?
|
|
369
366
|
end
|
|
367
|
+
alias :set_headers_if_nil :add_headers_if_nil
|
|
370
368
|
|
|
371
|
-
#
|
|
369
|
+
# Add custom data to the transaction.
|
|
372
370
|
#
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
# @since 3.10.0
|
|
377
|
-
# @see Appsignal.set_custom_data
|
|
371
|
+
# @since 4.0.0
|
|
372
|
+
# @see Helpers::Instrumentation#add_custom_data
|
|
378
373
|
# @see https://docs.appsignal.com/guides/custom-data/sample-data.html
|
|
379
374
|
# Sample data guide
|
|
380
375
|
# @param data [Hash/Array]
|
|
381
376
|
# @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
|
|
377
|
+
def add_custom_data(data)
|
|
378
|
+
@custom_data.add(data)
|
|
390
379
|
end
|
|
380
|
+
alias :set_custom_data :add_custom_data
|
|
391
381
|
|
|
392
382
|
# Add breadcrumbs to the transaction.
|
|
393
383
|
#
|
|
@@ -479,18 +469,6 @@ module Appsignal
|
|
|
479
469
|
@ext.set_namespace(namespace)
|
|
480
470
|
end
|
|
481
471
|
|
|
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
472
|
# Set queue start time for transaction.
|
|
495
473
|
#
|
|
496
474
|
# @param start [Integer] Queue start time in milliseconds.
|
|
@@ -507,35 +485,6 @@ module Appsignal
|
|
|
507
485
|
Appsignal.internal_logger.warn("Queue start value #{start} is too big")
|
|
508
486
|
end
|
|
509
487
|
|
|
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
488
|
# @api private
|
|
540
489
|
def set_metadata(key, value)
|
|
541
490
|
return unless key && value
|
|
@@ -544,81 +493,33 @@ module Appsignal
|
|
|
544
493
|
@ext.set_metadata(key, value)
|
|
545
494
|
end
|
|
546
495
|
|
|
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)
|
|
496
|
+
# @see Appsignal::Helpers::Instrumentation#add_error
|
|
497
|
+
def add_error(error, &block)
|
|
571
498
|
unless error.is_a?(Exception)
|
|
572
|
-
Appsignal.internal_logger.error "Appsignal::Transaction#
|
|
499
|
+
Appsignal.internal_logger.error "Appsignal::Transaction#add_error: Cannot add error. " \
|
|
573
500
|
"The given value is not an exception: #{error.inspect}"
|
|
574
501
|
return
|
|
575
502
|
end
|
|
503
|
+
|
|
576
504
|
return unless error
|
|
577
505
|
return unless Appsignal.active?
|
|
578
506
|
|
|
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
|
|
507
|
+
_set_error(error) if @error_blocks.empty?
|
|
593
508
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
break
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
causes << error
|
|
509
|
+
if !@error_blocks.include?(error) && @error_blocks.length >= ERRORS_LIMIT
|
|
510
|
+
Appsignal.internal_logger.warn "Appsignal::Transaction#add_error: Transaction has more " \
|
|
511
|
+
"than #{ERRORS_LIMIT} distinct errors. Only the first " \
|
|
512
|
+
"#{ERRORS_LIMIT} distinct errors will be reported."
|
|
513
|
+
return
|
|
603
514
|
end
|
|
604
515
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
{
|
|
609
|
-
:name => e.class.name,
|
|
610
|
-
:message => cleaned_error_message(e)
|
|
611
|
-
}
|
|
612
|
-
end
|
|
516
|
+
@error_blocks[error] << block
|
|
517
|
+
@error_blocks[error].compact!
|
|
518
|
+
end
|
|
613
519
|
|
|
614
|
-
|
|
520
|
+
alias :set_error :add_error
|
|
615
521
|
|
|
616
|
-
|
|
617
|
-
"error_causes",
|
|
618
|
-
causes_sample_data
|
|
619
|
-
)
|
|
620
|
-
end
|
|
621
|
-
alias_method :add_exception, :set_error
|
|
522
|
+
alias_method :add_exception, :add_error
|
|
622
523
|
|
|
623
524
|
# @see Helpers::Instrumentation#instrument
|
|
624
525
|
# @api private
|
|
@@ -671,37 +572,56 @@ module Appsignal
|
|
|
671
572
|
end
|
|
672
573
|
alias_method :to_hash, :to_h
|
|
673
574
|
|
|
674
|
-
|
|
675
|
-
class InternalGenericRequest
|
|
676
|
-
attr_reader :env
|
|
575
|
+
protected
|
|
677
576
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
577
|
+
attr_writer :is_duplicate, :tags, :custom_data, :breadcrumbs, :params, :session_data, :headers
|
|
578
|
+
|
|
579
|
+
private
|
|
580
|
+
|
|
581
|
+
def _set_error(error)
|
|
582
|
+
backtrace = cleaned_backtrace(error.backtrace)
|
|
583
|
+
@ext.set_error(
|
|
584
|
+
error.class.name,
|
|
585
|
+
cleaned_error_message(error),
|
|
586
|
+
backtrace ? Appsignal::Utils::Data.generate(backtrace) : Appsignal::Extension.data_array_new
|
|
587
|
+
)
|
|
588
|
+
@error_set = error
|
|
589
|
+
|
|
590
|
+
root_cause_missing = false
|
|
591
|
+
|
|
592
|
+
causes = []
|
|
593
|
+
while error
|
|
594
|
+
error = error.cause
|
|
595
|
+
|
|
596
|
+
break unless error
|
|
597
|
+
|
|
598
|
+
if causes.length >= ERROR_CAUSES_LIMIT
|
|
599
|
+
Appsignal.internal_logger.debug "Appsignal::Transaction#add_error: Error has more " \
|
|
600
|
+
"than #{ERROR_CAUSES_LIMIT} error causes. Only the first #{ERROR_CAUSES_LIMIT} " \
|
|
601
|
+
"will be reported."
|
|
602
|
+
root_cause_missing = true
|
|
603
|
+
break
|
|
604
|
+
end
|
|
681
605
|
|
|
682
|
-
|
|
683
|
-
env[:params]
|
|
606
|
+
causes << error
|
|
684
607
|
end
|
|
685
|
-
end
|
|
686
608
|
|
|
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
|
|
609
|
+
causes_sample_data = causes.map do |e|
|
|
610
|
+
{
|
|
611
|
+
:name => e.class.name,
|
|
612
|
+
:message => cleaned_error_message(e)
|
|
613
|
+
}
|
|
699
614
|
end
|
|
700
|
-
end
|
|
701
615
|
|
|
702
|
-
|
|
616
|
+
causes_sample_data.last[:is_root_cause] = false if root_cause_missing
|
|
617
|
+
|
|
618
|
+
set_sample_data(
|
|
619
|
+
"error_causes",
|
|
620
|
+
causes_sample_data
|
|
621
|
+
)
|
|
622
|
+
end
|
|
703
623
|
|
|
704
|
-
def
|
|
624
|
+
def set_sample_data(key, data)
|
|
705
625
|
return unless key && data
|
|
706
626
|
|
|
707
627
|
if !data.is_a?(Array) && !data.is_a?(Hash)
|
|
@@ -728,44 +648,43 @@ module Appsignal
|
|
|
728
648
|
end
|
|
729
649
|
end
|
|
730
650
|
|
|
731
|
-
def
|
|
651
|
+
def sample_data
|
|
732
652
|
{
|
|
733
653
|
:params => sanitized_params,
|
|
734
|
-
:environment =>
|
|
654
|
+
:environment => sanitized_request_headers,
|
|
735
655
|
:session_data => sanitized_session_data,
|
|
736
|
-
:metadata => sanitized_metadata,
|
|
737
656
|
:tags => sanitized_tags,
|
|
738
657
|
:breadcrumbs => breadcrumbs,
|
|
739
658
|
:custom_data => custom_data
|
|
740
659
|
}.each do |key, data|
|
|
741
|
-
|
|
660
|
+
set_sample_data(key, data)
|
|
742
661
|
end
|
|
743
662
|
end
|
|
744
663
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
664
|
+
def duplicate
|
|
665
|
+
new_transaction_id = SecureRandom.uuid
|
|
666
|
+
|
|
667
|
+
self.class.new(
|
|
668
|
+
new_transaction_id,
|
|
669
|
+
namespace,
|
|
670
|
+
:ext => ext.duplicate(new_transaction_id)
|
|
671
|
+
).tap do |transaction|
|
|
672
|
+
transaction.is_duplicate = true
|
|
673
|
+
transaction.tags = @tags.dup
|
|
674
|
+
transaction.custom_data = @custom_data.dup
|
|
675
|
+
transaction.breadcrumbs = @breadcrumbs.dup
|
|
676
|
+
transaction.params = @params.dup
|
|
677
|
+
transaction.session_data = @session_data.dup
|
|
678
|
+
transaction.headers = @headers.dup
|
|
679
|
+
end
|
|
759
680
|
end
|
|
760
681
|
|
|
761
|
-
#
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
env = environment
|
|
768
|
-
Appsignal::Rack::Utils.queue_start_from(env)
|
|
682
|
+
# @api private
|
|
683
|
+
def params
|
|
684
|
+
@params.value
|
|
685
|
+
rescue => e
|
|
686
|
+
Appsignal.internal_logger.error("Exception while fetching params: #{e.class}: #{e}")
|
|
687
|
+
nil
|
|
769
688
|
end
|
|
770
689
|
|
|
771
690
|
def sanitized_params
|
|
@@ -775,27 +694,8 @@ module Appsignal
|
|
|
775
694
|
Appsignal::Utils::HashSanitizer.sanitize params, filter_keys
|
|
776
695
|
end
|
|
777
696
|
|
|
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
697
|
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
|
|
698
|
+
@session_data.value
|
|
799
699
|
rescue => e
|
|
800
700
|
Appsignal.internal_logger.error \
|
|
801
701
|
"Exception while fetching session data: #{e.class}: #{e}"
|
|
@@ -814,35 +714,12 @@ module Appsignal
|
|
|
814
714
|
return unless Appsignal.config[:send_session_data]
|
|
815
715
|
|
|
816
716
|
Appsignal::Utils::HashSanitizer.sanitize(
|
|
817
|
-
session_data
|
|
717
|
+
session_data, Appsignal.config[:filter_session_data]
|
|
818
718
|
)
|
|
819
719
|
end
|
|
820
720
|
|
|
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
|
|
721
|
+
def request_headers
|
|
722
|
+
@headers.value
|
|
846
723
|
rescue => e
|
|
847
724
|
Appsignal.internal_logger.error \
|
|
848
725
|
"Exception while fetching headers: #{e.class}: #{e}"
|
|
@@ -856,15 +733,13 @@ module Appsignal
|
|
|
856
733
|
#
|
|
857
734
|
# @return [nil] if no environment is present.
|
|
858
735
|
# @return [Hash<String, Object>]
|
|
859
|
-
def
|
|
860
|
-
|
|
861
|
-
return unless
|
|
862
|
-
return unless env.respond_to?(:empty?)
|
|
863
|
-
return if env.empty?
|
|
736
|
+
def sanitized_request_headers
|
|
737
|
+
headers = request_headers
|
|
738
|
+
return unless headers
|
|
864
739
|
|
|
865
740
|
{}.tap do |out|
|
|
866
741
|
Appsignal.config[:request_headers].each do |key|
|
|
867
|
-
out[key] =
|
|
742
|
+
out[key] = headers[key] if headers[key]
|
|
868
743
|
end
|
|
869
744
|
end
|
|
870
745
|
end
|
|
@@ -890,6 +765,13 @@ module Appsignal
|
|
|
890
765
|
end
|
|
891
766
|
end
|
|
892
767
|
|
|
768
|
+
def custom_data
|
|
769
|
+
@custom_data.value
|
|
770
|
+
rescue => e
|
|
771
|
+
Appsignal.internal_logger.error("Exception while fetching custom data: #{e.class}: #{e}")
|
|
772
|
+
nil
|
|
773
|
+
end
|
|
774
|
+
|
|
893
775
|
# Clean error messages that are known to potentially contain user data.
|
|
894
776
|
# Returns an unchanged message otherwise.
|
|
895
777
|
def cleaned_error_message(error)
|