appsignal 2.10.4-java → 2.10.8-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/.semaphore/semaphore.yml +154 -2
- data/CHANGELOG.md +19 -0
- data/Rakefile +7 -1
- data/appsignal.gemspec +5 -2
- data/build_matrix.yml +17 -2
- data/ext/agent.yml +19 -19
- data/ext/base.rb +4 -2
- data/lib/appsignal.rb +6 -3
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/cli/notify_of_deploy.rb +1 -1
- data/lib/appsignal/event_formatter.rb +1 -2
- data/lib/appsignal/integrations/delayed_job_plugin.rb +16 -3
- data/lib/appsignal/integrations/grape.rb +2 -1
- data/lib/appsignal/minutely.rb +1 -2
- data/lib/appsignal/rack/js_exception_catcher.rb +3 -4
- data/lib/appsignal/transaction.rb +6 -1
- data/lib/appsignal/utils/deprecation_message.rb +2 -2
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/auth_check_spec.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +4 -2
- data/spec/lib/appsignal/config_spec.rb +7 -7
- data/spec/lib/appsignal/event_formatter_spec.rb +5 -4
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +198 -166
- data/spec/lib/appsignal/integrations/grape_spec.rb +10 -0
- data/spec/lib/appsignal/minutely_spec.rb +4 -4
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +9 -5
- data/spec/lib/appsignal/transaction_spec.rb +14 -1
- data/spec/lib/appsignal/transmitter_spec.rb +3 -1
- data/spec/lib/appsignal_spec.rb +2 -2
- data/spec/spec_helper.rb +15 -1
- data/support/install_deps +4 -1
- metadata +21 -21
@@ -323,11 +323,11 @@ describe Appsignal::Config do
|
|
323
323
|
end
|
324
324
|
|
325
325
|
describe "support for old config keys" do
|
326
|
-
let(:
|
327
|
-
let(:
|
326
|
+
let(:err_stream) { std_stream }
|
327
|
+
let(:stderr) { err_stream.read }
|
328
328
|
let(:config) { project_fixture_config(env, {}, test_logger(log)) }
|
329
329
|
let(:log) { StringIO.new }
|
330
|
-
before {
|
330
|
+
before { capture_std_streams(std_stream, err_stream) { config } }
|
331
331
|
|
332
332
|
describe ":api_key" do
|
333
333
|
context "without :push_api_key" do
|
@@ -338,7 +338,7 @@ describe Appsignal::Config do
|
|
338
338
|
expect(config.config_hash).to_not have_key :api_key
|
339
339
|
|
340
340
|
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
341
|
-
expect(
|
341
|
+
expect(stderr).to include "appsignal WARNING: #{message}"
|
342
342
|
expect(log_contents(log)).to contains_log :warn, message
|
343
343
|
end
|
344
344
|
end
|
@@ -351,7 +351,7 @@ describe Appsignal::Config do
|
|
351
351
|
expect(config.config_hash).to_not have_key :api_key
|
352
352
|
|
353
353
|
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
354
|
-
expect(
|
354
|
+
expect(stderr).to include "appsignal WARNING: #{message}"
|
355
355
|
expect(log_contents(log)).to contains_log :warn, message
|
356
356
|
end
|
357
357
|
end
|
@@ -366,7 +366,7 @@ describe Appsignal::Config do
|
|
366
366
|
expect(config.config_hash).to_not have_key :ignore_exceptions
|
367
367
|
|
368
368
|
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
369
|
-
expect(
|
369
|
+
expect(stderr).to include "appsignal WARNING: #{message}"
|
370
370
|
expect(log_contents(log)).to contains_log :warn, message
|
371
371
|
end
|
372
372
|
end
|
@@ -379,7 +379,7 @@ describe Appsignal::Config do
|
|
379
379
|
expect(config.config_hash).to_not have_key :ignore_exceptions
|
380
380
|
|
381
381
|
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
382
|
-
expect(
|
382
|
+
expect(stderr).to include "appsignal WARNING: #{message}"
|
383
383
|
expect(log_contents(log)).to contains_log :warn, message
|
384
384
|
end
|
385
385
|
end
|
@@ -116,7 +116,8 @@ describe Appsignal::EventFormatter do
|
|
116
116
|
end
|
117
117
|
|
118
118
|
context "when registering deprecated formatters" do
|
119
|
-
let(:
|
119
|
+
let(:err_stream) { std_stream }
|
120
|
+
let(:stderr) { err_stream.read }
|
120
121
|
let(:deprecated_formatter) do
|
121
122
|
Class.new(Appsignal::EventFormatter) do
|
122
123
|
register "mock.deprecated"
|
@@ -133,16 +134,16 @@ describe Appsignal::EventFormatter do
|
|
133
134
|
"https://docs.appsignal.com/ruby/instrumentation/event-formatters.html"
|
134
135
|
|
135
136
|
logs = capture_logs do
|
136
|
-
|
137
|
+
capture_std_streams(std_stream, err_stream) { deprecated_formatter }
|
137
138
|
end
|
138
139
|
expect(logs).to contains_log :warn, message
|
139
|
-
expect(
|
140
|
+
expect(stderr).to include "appsignal WARNING: #{message}"
|
140
141
|
|
141
142
|
expect(klass.deprecated_formatter_classes.keys).to include("mock.deprecated")
|
142
143
|
end
|
143
144
|
|
144
145
|
it "initializes deprecated formatters" do
|
145
|
-
|
146
|
+
capture_std_streams(std_stream, err_stream) { deprecated_formatter }
|
146
147
|
klass.initialize_deprecated_formatters
|
147
148
|
|
148
149
|
expect(klass.registered?("mock.deprecated")).to be_truthy
|
@@ -36,6 +36,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
36
36
|
let(:time) { Time.parse("01-01-2001 10:01:00UTC") }
|
37
37
|
let(:created_at) { time - 3600 }
|
38
38
|
let(:run_at) { time - 3600 }
|
39
|
+
let(:payload_object) { double(:args => args) }
|
39
40
|
let(:job_data) do
|
40
41
|
{
|
41
42
|
:id => 123,
|
@@ -45,38 +46,40 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
45
46
|
:queue => "default",
|
46
47
|
:created_at => created_at,
|
47
48
|
:run_at => run_at,
|
48
|
-
:payload_object =>
|
49
|
+
:payload_object => payload_object
|
49
50
|
}
|
50
51
|
end
|
51
52
|
let(:args) { ["argument"] }
|
52
53
|
let(:job) { double(job_data) }
|
53
54
|
let(:invoked_block) { proc {} }
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
:class => "TestClass",
|
59
|
-
:method => "perform",
|
60
|
-
:metadata => {
|
61
|
-
:priority => 1,
|
62
|
-
:attempts => 1,
|
63
|
-
:queue => "default",
|
64
|
-
:id => "123"
|
65
|
-
},
|
66
|
-
:params => args,
|
67
|
-
:queue_start => run_at
|
68
|
-
}
|
69
|
-
end
|
70
|
-
after do
|
71
|
-
Timecop.freeze(time) do
|
56
|
+
def perform
|
57
|
+
Timecop.freeze(time) do
|
58
|
+
keep_transactions do
|
72
59
|
plugin.invoke_with_instrumentation(job, invoked_block)
|
73
60
|
end
|
74
61
|
end
|
62
|
+
end
|
75
63
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
64
|
+
context "with a normal call" do
|
65
|
+
it "wraps it in a transaction" do
|
66
|
+
perform
|
67
|
+
transaction_data = last_transaction.to_h
|
68
|
+
expect(transaction_data).to include(
|
69
|
+
"action" => "TestClass#perform",
|
70
|
+
"namespace" => "background_job",
|
71
|
+
"error" => nil
|
72
|
+
)
|
73
|
+
expect(transaction_data["events"].map { |e| e["name"] })
|
74
|
+
.to eql(["perform_job.delayed_job"])
|
75
|
+
expect(transaction_data["sample_data"]).to include(
|
76
|
+
"metadata" => {
|
77
|
+
"priority" => 1,
|
78
|
+
"attempts" => 1,
|
79
|
+
"queue" => "default",
|
80
|
+
"id" => "123"
|
81
|
+
},
|
82
|
+
"params" => ["argument"]
|
80
83
|
)
|
81
84
|
end
|
82
85
|
|
@@ -89,14 +92,13 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
89
92
|
end
|
90
93
|
|
91
94
|
it "adds the more complex arguments" do
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
)
|
95
|
+
perform
|
96
|
+
transaction_data = last_transaction.to_h
|
97
|
+
expect(transaction_data["sample_data"]).to include(
|
98
|
+
"params" => {
|
99
|
+
"foo" => "Foo",
|
100
|
+
"bar" => "Bar"
|
101
|
+
}
|
100
102
|
)
|
101
103
|
end
|
102
104
|
|
@@ -107,14 +109,13 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
107
109
|
end
|
108
110
|
|
109
111
|
it "filters selected arguments" do
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
)
|
112
|
+
perform
|
113
|
+
transaction_data = last_transaction.to_h
|
114
|
+
expect(transaction_data["sample_data"]).to include(
|
115
|
+
"params" => {
|
116
|
+
"foo" => "[FILTERED]",
|
117
|
+
"bar" => "Bar"
|
118
|
+
}
|
118
119
|
)
|
119
120
|
end
|
120
121
|
end
|
@@ -124,98 +125,135 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
124
125
|
let(:run_at) { Time.parse("2017-01-01 10:01:00UTC") }
|
125
126
|
|
126
127
|
it "reports queue_start with run_at time" do
|
128
|
+
# TODO: Not available in transaction.to_h yet.
|
129
|
+
# https://github.com/appsignal/appsignal-agent/issues/293
|
127
130
|
expect(Appsignal).to receive(:monitor_transaction).with(
|
128
131
|
"perform_job.delayed_job",
|
129
|
-
|
130
|
-
)
|
132
|
+
a_hash_including(:queue_start => run_at)
|
133
|
+
).and_call_original
|
134
|
+
perform
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
134
|
-
context "with
|
138
|
+
context "with class method job" do
|
135
139
|
let(:job_data) do
|
136
|
-
{
|
137
|
-
:payload_object => double(
|
138
|
-
:appsignal_name => "CustomClass#perform",
|
139
|
-
:args => args
|
140
|
-
),
|
141
|
-
:id => "123",
|
142
|
-
:name => "TestClass#perform",
|
143
|
-
:priority => 1,
|
144
|
-
:attempts => 1,
|
145
|
-
:queue => "default",
|
146
|
-
:created_at => created_at,
|
147
|
-
:run_at => run_at
|
148
|
-
}
|
149
|
-
end
|
150
|
-
let(:default_params) do
|
151
|
-
{
|
152
|
-
:class => "CustomClass",
|
153
|
-
:method => "perform",
|
154
|
-
:metadata => {
|
155
|
-
:priority => 1,
|
156
|
-
:attempts => 1,
|
157
|
-
:queue => "default",
|
158
|
-
:id => "123"
|
159
|
-
},
|
160
|
-
:queue_start => run_at
|
161
|
-
}
|
140
|
+
{ :name => "CustomClassMethod.perform", :payload_object => payload_object }
|
162
141
|
end
|
163
142
|
|
164
|
-
it "wraps it in a transaction
|
165
|
-
|
166
|
-
|
167
|
-
default_params.merge(
|
168
|
-
:params => ["argument"]
|
169
|
-
)
|
170
|
-
)
|
143
|
+
it "wraps it in a transaction using the class method job name" do
|
144
|
+
perform
|
145
|
+
expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
|
171
146
|
end
|
147
|
+
end
|
172
148
|
|
173
|
-
|
174
|
-
|
175
|
-
{
|
176
|
-
:foo => "Foo",
|
177
|
-
:bar => "Bar"
|
178
|
-
}
|
179
|
-
end
|
149
|
+
context "with custom name call" do
|
150
|
+
before { perform }
|
180
151
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
152
|
+
context "with appsignal_name defined" do
|
153
|
+
context "with payload_object being an object" do
|
154
|
+
context "with value" do
|
155
|
+
let(:payload_object) { double(:appsignal_name => "CustomClass#perform") }
|
156
|
+
|
157
|
+
it "wraps it in a transaction using the custom name" do
|
158
|
+
expect(last_transaction.to_h["action"]).to eql("CustomClass#perform")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "with non-String value" do
|
163
|
+
let(:payload_object) { double(:appsignal_name => Object.new) }
|
164
|
+
|
165
|
+
it "wraps it in a transaction using the original job name" do
|
166
|
+
expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "with class method name as job" do
|
171
|
+
let(:payload_object) { double(:appsignal_name => "CustomClassMethod.perform") }
|
172
|
+
|
173
|
+
it "wraps it in a transaction using the custom name" do
|
174
|
+
perform
|
175
|
+
expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
|
176
|
+
end
|
177
|
+
end
|
191
178
|
end
|
192
179
|
|
193
|
-
context "with
|
194
|
-
|
195
|
-
|
196
|
-
|
180
|
+
context "with payload_object being a Hash" do
|
181
|
+
context "with value" do
|
182
|
+
let(:payload_object) { double(:appsignal_name => "CustomClassHash#perform") }
|
183
|
+
|
184
|
+
it "wraps it in a transaction using the custom name" do
|
185
|
+
expect(last_transaction.to_h["action"]).to eql("CustomClassHash#perform")
|
186
|
+
end
|
197
187
|
end
|
198
188
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
)
|
189
|
+
context "with non-String value" do
|
190
|
+
let(:payload_object) { double(:appsignal_name => Object.new) }
|
191
|
+
|
192
|
+
it "wraps it in a transaction using the original job name" do
|
193
|
+
expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "with class method name as job" do
|
198
|
+
let(:payload_object) { { :appsignal_name => "CustomClassMethod.perform" } }
|
199
|
+
|
200
|
+
it "wraps it in a transaction using the custom name" do
|
201
|
+
perform
|
202
|
+
expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "with payload_object being acting like a Hash and returning a non-String value" do
|
208
|
+
class ClassActingAsHash
|
209
|
+
def self.[](_key)
|
210
|
+
Object.new
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.appsignal_name
|
214
|
+
"ClassActingAsHash#perform"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
let(:payload_object) { ClassActingAsHash }
|
218
|
+
|
219
|
+
# We check for hash values before object values
|
220
|
+
# this means ClassActingAsHash returns `Object.new` instead
|
221
|
+
# of `self.appsignal_name`. Since this isn't a valid `String`
|
222
|
+
# we return the default job name as action name.
|
223
|
+
it "wraps it in a transaction using the original job name" do
|
224
|
+
expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
|
209
225
|
end
|
210
226
|
end
|
211
227
|
end
|
212
228
|
end
|
213
229
|
|
230
|
+
context "without job name" do
|
231
|
+
let(:job_data) do
|
232
|
+
{ :name => "", :payload_object => payload_object }
|
233
|
+
end
|
234
|
+
|
235
|
+
it "wraps it in a transaction using the class method job name" do
|
236
|
+
perform
|
237
|
+
expect(last_transaction.to_h["action"]).to eql("unknown")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context "with invalid job name" do
|
242
|
+
let(:job_data) do
|
243
|
+
{ :name => "Banana", :payload_object => payload_object }
|
244
|
+
end
|
245
|
+
|
246
|
+
it "wraps it in a transaction using the class method job name" do
|
247
|
+
perform
|
248
|
+
expect(last_transaction.to_h["action"]).to eql("unknown")
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
214
252
|
if active_job_present?
|
215
253
|
require "active_job"
|
216
254
|
|
217
255
|
context "when wrapped by ActiveJob" do
|
218
|
-
let(:
|
256
|
+
let(:payload_object) do
|
219
257
|
ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper.new(
|
220
258
|
"arguments" => args,
|
221
259
|
"job_class" => "TestClass",
|
@@ -233,32 +271,30 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
233
271
|
:queue => "default",
|
234
272
|
:created_at => created_at,
|
235
273
|
:run_at => run_at,
|
236
|
-
:payload_object =>
|
274
|
+
:payload_object => payload_object
|
237
275
|
)
|
238
276
|
end
|
239
|
-
let(:default_params) do
|
240
|
-
{
|
241
|
-
:class => "TestClass",
|
242
|
-
:method => "perform",
|
243
|
-
:metadata => {
|
244
|
-
:priority => 1,
|
245
|
-
:attempts => 1,
|
246
|
-
:queue => "default",
|
247
|
-
:id => "123"
|
248
|
-
},
|
249
|
-
:queue_start => run_at,
|
250
|
-
:params => args
|
251
|
-
}
|
252
|
-
end
|
253
277
|
let(:args) { ["activejob_argument"] }
|
254
278
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
279
|
+
it "wraps it in a transaction with the correct params" do
|
280
|
+
perform
|
281
|
+
transaction_data = last_transaction.to_h
|
282
|
+
expect(transaction_data).to include(
|
283
|
+
"action" => "TestClass#perform",
|
284
|
+
"namespace" => "background_job",
|
285
|
+
"error" => nil
|
286
|
+
)
|
287
|
+
expect(transaction_data["events"].map { |e| e["name"] })
|
288
|
+
.to eql(["perform_job.delayed_job"])
|
289
|
+
expect(transaction_data["sample_data"]).to include(
|
290
|
+
"metadata" => {
|
291
|
+
"priority" => 1,
|
292
|
+
"attempts" => 1,
|
293
|
+
"queue" => "default",
|
294
|
+
"id" => "123"
|
295
|
+
},
|
296
|
+
"params" => ["activejob_argument"]
|
297
|
+
)
|
262
298
|
end
|
263
299
|
|
264
300
|
context "with more complex params" do
|
@@ -270,14 +306,14 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
270
306
|
end
|
271
307
|
|
272
308
|
it "adds the more complex arguments" do
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
309
|
+
perform
|
310
|
+
transaction_data = last_transaction.to_h
|
311
|
+
expect(transaction_data).to include("action" => "TestClass#perform")
|
312
|
+
expect(transaction_data["sample_data"]).to include(
|
313
|
+
"params" => {
|
314
|
+
"foo" => "Foo",
|
315
|
+
"bar" => "Bar"
|
316
|
+
}
|
281
317
|
)
|
282
318
|
end
|
283
319
|
|
@@ -288,14 +324,14 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
288
324
|
end
|
289
325
|
|
290
326
|
it "filters selected arguments" do
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
327
|
+
perform
|
328
|
+
transaction_data = last_transaction.to_h
|
329
|
+
expect(transaction_data).to include("action" => "TestClass#perform")
|
330
|
+
expect(transaction_data["sample_data"]).to include(
|
331
|
+
"params" => {
|
332
|
+
"foo" => "[FILTERED]",
|
333
|
+
"bar" => "Bar"
|
334
|
+
}
|
299
335
|
)
|
300
336
|
end
|
301
337
|
end
|
@@ -307,8 +343,9 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
307
343
|
it "reports queue_start with run_at time" do
|
308
344
|
expect(Appsignal).to receive(:monitor_transaction).with(
|
309
345
|
"perform_job.delayed_job",
|
310
|
-
|
311
|
-
)
|
346
|
+
a_hash_including(:queue_start => run_at)
|
347
|
+
).and_call_original
|
348
|
+
perform
|
312
349
|
end
|
313
350
|
end
|
314
351
|
end
|
@@ -316,33 +353,28 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
316
353
|
end
|
317
354
|
|
318
355
|
context "with an erroring call" do
|
319
|
-
let(:error) { ExampleException }
|
320
|
-
let(:transaction) do
|
321
|
-
Appsignal::Transaction.new(
|
322
|
-
SecureRandom.uuid,
|
323
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
324
|
-
Appsignal::Transaction::GenericRequest.new({})
|
325
|
-
)
|
326
|
-
end
|
356
|
+
let(:error) { ExampleException.new("uh oh") }
|
327
357
|
before do
|
328
358
|
expect(invoked_block).to receive(:call).and_raise(error)
|
329
|
-
|
330
|
-
allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
|
331
|
-
expect(Appsignal::Transaction).to receive(:create)
|
332
|
-
.with(
|
333
|
-
kind_of(String),
|
334
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
335
|
-
kind_of(Appsignal::Transaction::GenericRequest)
|
336
|
-
).and_return(transaction)
|
337
359
|
end
|
338
360
|
|
339
361
|
it "adds the error to the transaction" do
|
340
|
-
expect(transaction).to receive(:set_error).with(error)
|
341
|
-
expect(transaction).to receive(:complete)
|
342
|
-
|
343
362
|
expect do
|
344
|
-
|
363
|
+
perform
|
345
364
|
end.to raise_error(error)
|
365
|
+
|
366
|
+
transaction_data = last_transaction.to_h
|
367
|
+
expect(transaction_data).to include(
|
368
|
+
"action" => "TestClass#perform",
|
369
|
+
"namespace" => "background_job",
|
370
|
+
"error" => {
|
371
|
+
"name" => "ExampleException",
|
372
|
+
"message" => "uh oh",
|
373
|
+
# TODO: backtrace should be an Array of Strings
|
374
|
+
# https://github.com/appsignal/appsignal-agent/issues/294
|
375
|
+
"backtrace" => kind_of(String)
|
376
|
+
}
|
377
|
+
)
|
346
378
|
end
|
347
379
|
end
|
348
380
|
end
|