appsignal 3.9.2-java → 3.10.0-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.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3138 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +130 -0
  6. data/README.md +0 -1
  7. data/Rakefile +80 -65
  8. data/appsignal.gemspec +1 -1
  9. data/build_matrix.yml +112 -184
  10. data/ext/base.rb +1 -1
  11. data/gemfiles/hanami-2.1.gemfile +7 -0
  12. data/gemfiles/webmachine1.gemfile +5 -4
  13. data/lib/appsignal/cli/diagnose.rb +1 -1
  14. data/lib/appsignal/config.rb +5 -1
  15. data/lib/appsignal/demo.rb +0 -1
  16. data/lib/appsignal/environment.rb +11 -2
  17. data/lib/appsignal/extension/jruby.rb +1 -1
  18. data/lib/appsignal/helpers/instrumentation.rb +164 -2
  19. data/lib/appsignal/hooks/active_job.rb +1 -6
  20. data/lib/appsignal/integrations/grape.rb +19 -47
  21. data/lib/appsignal/integrations/hanami.rb +8 -7
  22. data/lib/appsignal/integrations/padrino.rb +51 -52
  23. data/lib/appsignal/integrations/railtie.rb +0 -3
  24. data/lib/appsignal/integrations/rake.rb +46 -12
  25. data/lib/appsignal/integrations/sidekiq.rb +1 -11
  26. data/lib/appsignal/integrations/sinatra.rb +0 -1
  27. data/lib/appsignal/integrations/webmachine.rb +15 -9
  28. data/lib/appsignal/probes/gvl.rb +24 -2
  29. data/lib/appsignal/probes/sidekiq.rb +1 -1
  30. data/lib/appsignal/probes.rb +1 -1
  31. data/lib/appsignal/rack/abstract_middleware.rb +104 -33
  32. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  33. data/lib/appsignal/rack/event_handler.rb +12 -3
  34. data/lib/appsignal/rack/generic_instrumentation.rb +5 -4
  35. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  36. data/lib/appsignal/rack/hanami_middleware.rb +2 -12
  37. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  38. data/lib/appsignal/rack/rails_instrumentation.rb +14 -57
  39. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  40. data/lib/appsignal/rack/streaming_listener.rb +13 -59
  41. data/lib/appsignal/rack.rb +31 -0
  42. data/lib/appsignal/transaction.rb +50 -8
  43. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  44. data/lib/appsignal/utils.rb +1 -0
  45. data/lib/appsignal/version.rb +1 -1
  46. data/lib/appsignal.rb +36 -33
  47. data/spec/.rubocop.yml +1 -1
  48. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  49. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  50. data/spec/lib/appsignal/config_spec.rb +8 -5
  51. data/spec/lib/appsignal/demo_spec.rb +38 -41
  52. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  53. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  54. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  55. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  56. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  57. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  58. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  59. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  60. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  61. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  62. data/spec/lib/appsignal/hooks/rake_spec.rb +107 -34
  63. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  64. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  65. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  66. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  67. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  68. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  69. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  70. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  71. data/spec/lib/appsignal/integrations/padrino_spec.rb +190 -163
  72. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  73. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  74. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  75. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -3
  76. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -40
  77. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  78. data/spec/lib/appsignal/probes_spec.rb +7 -4
  79. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +302 -105
  80. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  81. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  82. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -27
  83. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  84. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  85. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  86. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  87. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  88. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +44 -139
  89. data/spec/lib/appsignal/transaction_spec.rb +239 -94
  90. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  91. data/spec/lib/appsignal_spec.rb +556 -344
  92. data/spec/support/helpers/dependency_helper.rb +6 -1
  93. data/spec/support/helpers/std_streams_helper.rb +1 -1
  94. data/spec/support/helpers/transaction_helpers.rb +8 -0
  95. data/spec/support/matchers/transaction.rb +185 -0
  96. data/spec/support/mocks/dummy_app.rb +20 -0
  97. data/spec/support/shared_examples/instrument.rb +17 -12
  98. data/spec/support/testing.rb +18 -9
  99. metadata +20 -11
  100. data/.semaphore/semaphore.yml +0 -2347
  101. data/script/lint_git +0 -22
  102. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  103. data/spec/support/matchers/be_completed.rb +0 -5
  104. data/support/check_versions +0 -22
  105. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -1,5 +1,6 @@
1
1
  describe Appsignal do
2
2
  include EnvironmentMetadataHelper
3
+ around { |example| keep_transactions { example.run } }
3
4
 
4
5
  before do
5
6
  # Make sure we have a clean state because we want to test
@@ -21,21 +22,30 @@ describe Appsignal do
21
22
 
22
23
  describe ".start" do
23
24
  context "with no config set beforehand" do
24
- it "should do nothing when config is not set and there is no valid config in the env" do
25
- expect(Appsignal.internal_logger).to receive(:error)
26
- .with("Push API key not set after loading config").once
27
- expect(Appsignal.internal_logger).to receive(:error)
28
- .with("Not starting, no valid config for this environment").once
25
+ let(:stdout_stream) { std_stream }
26
+ let(:stdout) { stdout_stream.read }
27
+ let(:stderr_stream) { std_stream }
28
+ let(:stderr) { stderr_stream.read }
29
+ before { ENV["APPSIGNAL_LOG"] = "stdout" }
30
+
31
+ it "does nothing when config is not set and there is no valid config in the env" do
29
32
  expect(Appsignal::Extension).to_not receive(:start)
30
- Appsignal.start
33
+ capture_std_streams(stdout_stream, stderr_stream) { Appsignal.start }
34
+
35
+ expect(stdout).to contains_log(
36
+ :error,
37
+ "appsignal: Not starting, no valid config for this environment"
38
+ )
31
39
  end
32
40
 
33
41
  it "should create a config from the env" do
34
42
  ENV["APPSIGNAL_PUSH_API_KEY"] = "something"
35
43
  expect(Appsignal::Extension).to receive(:start)
36
- expect(Appsignal.internal_logger).not_to receive(:error)
37
- silence { Appsignal.start }
44
+ capture_std_streams(stdout_stream, stderr_stream) { Appsignal.start }
45
+
38
46
  expect(Appsignal.config[:push_api_key]).to eq("something")
47
+ expect(stderr).to_not include("[ERROR]")
48
+ expect(stdout).to_not include("[ERROR]")
39
49
  end
40
50
  end
41
51
 
@@ -129,7 +139,7 @@ describe Appsignal do
129
139
 
130
140
  describe ".forked" do
131
141
  context "when not active" do
132
- it "should should do nothing" do
142
+ it "does nothing" do
133
143
  expect(Appsignal::Extension).to_not receive(:start)
134
144
 
135
145
  Appsignal.forked
@@ -141,8 +151,8 @@ describe Appsignal do
141
151
  Appsignal.config = project_fixture_config
142
152
  end
143
153
 
144
- it "should resubscribe and start the extension" do
145
- expect(Appsignal).to receive(:start_logger)
154
+ it "starts the logger and extension" do
155
+ expect(Appsignal).to receive(:_start_logger)
146
156
  expect(Appsignal::Extension).to receive(:start)
147
157
 
148
158
  Appsignal.forked
@@ -222,28 +232,26 @@ describe Appsignal do
222
232
  end
223
233
 
224
234
  context "not active" do
225
- describe ".monitor_transaction" do
226
- let(:log_stream) { StringIO.new }
227
- let(:log) { log_contents(log_stream) }
228
- before do
229
- Appsignal.config = project_fixture_config("not_active")
230
- Appsignal.start
231
- Appsignal.start_logger
232
- Appsignal.internal_logger = test_logger(log_stream)
233
- end
234
- after { Appsignal.internal_logger = nil }
235
+ before { Appsignal.config = project_fixture_config("not_active") }
235
236
 
236
- it "should do nothing but still yield the block" do
237
- expect(Appsignal::Transaction).to_not receive(:create)
238
- expect(Appsignal).to_not receive(:instrument)
239
- object = double
240
- expect(object).to receive(:some_method).and_return(1)
237
+ describe ".monitor_transaction" do
238
+ it "does not create a transaction" do
239
+ object = double(:some_method => 1)
241
240
 
242
241
  expect do
243
- expect(Appsignal.monitor_transaction("perform_job.nothing") do
242
+ Appsignal.monitor_transaction("perform_job.nothing") do
244
243
  object.some_method
245
- end).to eq 1
246
- end.to_not raise_error
244
+ end
245
+ end.to_not(change { created_transactions.count })
246
+ end
247
+
248
+ it "returns the block's return value" do
249
+ object = double(:some_method => 1)
250
+
251
+ return_value = Appsignal.monitor_transaction("perform_job.nothing") do
252
+ object.some_method
253
+ end
254
+ expect(return_value).to eq 1
247
255
  end
248
256
 
249
257
  context "with an unknown event type" do
@@ -254,8 +262,11 @@ describe Appsignal do
254
262
  end
255
263
 
256
264
  it "logs an error" do
257
- Appsignal.monitor_transaction("unknown.sidekiq") {} # rubocop:disable Lint/EmptyBlock
258
- expect(log).to contains_log(
265
+ logs =
266
+ capture_logs do
267
+ Appsignal.monitor_transaction("unknown.sidekiq") {} # rubocop:disable Lint/EmptyBlock
268
+ end
269
+ expect(logs).to contains_log(
259
270
  :error,
260
271
  "Unrecognized name 'unknown.sidekiq': names must start with either 'perform_job' " \
261
272
  "(for jobs and tasks) or 'process_action' (for HTTP requests)"
@@ -265,111 +276,149 @@ describe Appsignal do
265
276
  end
266
277
 
267
278
  describe ".listen_for_error" do
268
- it "does not record anything" do
269
- error = RuntimeError.new("specific error")
279
+ let(:error) { ExampleException.new("specific error") }
280
+
281
+ it "reraises the error" do
270
282
  expect do
271
- Appsignal.listen_for_error do
272
- raise error
273
- end
283
+ Appsignal.listen_for_error { raise error }
274
284
  end.to raise_error(error)
275
285
  end
286
+
287
+ it "does not create a transaction" do
288
+ expect do
289
+ expect do
290
+ Appsignal.listen_for_error { raise error }
291
+ end.to raise_error(error)
292
+ end.to_not(change { created_transactions.count })
293
+ end
276
294
  end
277
295
 
278
296
  describe ".send_error" do
279
- it "should do nothing" do
297
+ let(:error) { ExampleException.new("specific error") }
298
+
299
+ it "does not raise an error" do
300
+ Appsignal.send_error(error)
301
+ end
302
+
303
+ it "does not create a transaction" do
280
304
  expect do
281
- Appsignal.send_error(RuntimeError.new)
282
- end.to_not raise_error
305
+ Appsignal.send_error(error)
306
+ end.to_not(change { created_transactions.count })
283
307
  end
284
308
  end
285
309
 
286
310
  describe ".set_error" do
287
- it "should do nothing" do
311
+ let(:error) { ExampleException.new("specific error") }
312
+
313
+ it "does not raise an error" do
314
+ Appsignal.set_error(error)
315
+ end
316
+
317
+ it "does not create a transaction" do
288
318
  expect do
289
- Appsignal.set_error(RuntimeError.new)
290
- end.to_not raise_error
319
+ Appsignal.set_error(error)
320
+ end.to_not(change { created_transactions.count })
291
321
  end
292
322
  end
293
323
 
294
- describe ".set_namespace" do
295
- it "should do nothing" do
324
+ describe ".report_error" do
325
+ let(:error) { ExampleException.new("specific error") }
326
+
327
+ it "does not raise an error" do
328
+ Appsignal.report_error(error)
329
+ end
330
+
331
+ it "does not create a transaction" do
296
332
  expect do
297
- Appsignal.set_namespace("custom")
298
- end.to_not raise_error
333
+ Appsignal.report_error(error)
334
+ end.to_not(change { created_transactions.count })
335
+ end
336
+ end
337
+
338
+ describe ".set_namespace" do
339
+ it "does not raise an error" do
340
+ Appsignal.set_namespace("custom")
299
341
  end
300
342
  end
301
343
 
302
344
  describe ".tag_request" do
303
- it "should do nothing" do
304
- expect do
305
- Appsignal.tag_request(:tag => "tag")
306
- end.to_not raise_error
345
+ it "does not raise an error" do
346
+ Appsignal.tag_request(:tag => "tag")
347
+ end
348
+ end
349
+
350
+ describe ".set_custom_data" do
351
+ it "does not raise an error" do
352
+ Appsignal.set_custom_data(:data => "value")
307
353
  end
308
354
  end
309
355
  end
310
356
 
311
357
  context "with config and started" do
312
- let(:log_stream) { StringIO.new }
313
- let(:log) { log_contents(log_stream) }
314
- before do
315
- Appsignal.config = project_fixture_config
316
- Appsignal.start
317
- Appsignal.start_logger
318
- Appsignal.internal_logger = test_logger(log_stream)
319
- end
320
- after { Appsignal.internal_logger = nil }
358
+ before { start_agent }
359
+ around { |example| keep_transactions { example.run } }
321
360
 
322
361
  describe ".monitor_transaction" do
323
362
  context "with a successful call" do
324
- it "should instrument and complete for a background job" do
325
- expect(Appsignal).to receive(:instrument)
326
- .with("perform_job.something").and_yield
327
- expect(Appsignal::Transaction).to receive(:complete_current!)
328
- object = double
329
- expect(object).to receive(:some_method).and_return(1)
330
-
331
- expect(Appsignal.monitor_transaction(
332
- "perform_job.something",
333
- background_env_with_data
334
- ) do
335
- current = Appsignal::Transaction.current
336
- expect(current.namespace).to eq Appsignal::Transaction::BACKGROUND_JOB
337
- expect(current.request).to be_a(Appsignal::Transaction::GenericRequest)
338
- object.some_method
339
- end).to eq 1
363
+ it "instruments and completes for a background job" do
364
+ return_value = nil
365
+ expect do
366
+ return_value =
367
+ Appsignal.monitor_transaction(
368
+ "perform_job.something",
369
+ {
370
+ :class => "BackgroundJob",
371
+ :method => "perform"
372
+ }
373
+ ) do
374
+ :return_value
375
+ end
376
+ end.to(change { created_transactions.count }.by(1))
377
+ expect(return_value).to eq(:return_value)
378
+
379
+ transaction = last_transaction
380
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
381
+ expect(transaction).to have_action("BackgroundJob#perform")
382
+ expect(transaction).to include_event("name" => "perform_job.something")
383
+ expect(transaction).to be_completed
340
384
  end
341
385
 
342
- it "should instrument and complete for a http request" do
343
- expect(Appsignal).to receive(:instrument)
344
- .with("process_action.something").and_yield
345
- expect(Appsignal::Transaction).to receive(:complete_current!)
346
- object = double
347
- expect(object).to receive(:some_method)
386
+ it "instruments and completes for a http request" do
387
+ return_value = nil
388
+ expect do
389
+ return_value =
390
+ Appsignal.monitor_transaction(
391
+ "process_action.something",
392
+ {
393
+ :controller => "BlogPostsController",
394
+ :action => "show"
395
+ }
396
+ ) do
397
+ :return_value
398
+ end
399
+ end.to(change { created_transactions.count }.by(1))
400
+ expect(return_value).to eq(:return_value)
348
401
 
349
- Appsignal.monitor_transaction(
350
- "process_action.something",
351
- http_request_env_with_data
352
- ) do
353
- current = Appsignal::Transaction.current
354
- expect(current.namespace).to eq Appsignal::Transaction::HTTP_REQUEST
355
- expect(current.request).to be_a(::Rack::Request)
356
- object.some_method
357
- end
402
+ transaction = last_transaction
403
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
404
+ expect(transaction).to have_action("BlogPostsController#show")
405
+ expect(transaction).to include_event("name" => "process_action.something")
406
+ expect(transaction).to be_completed
358
407
  end
359
408
  end
360
409
 
361
410
  context "with an erroring call" do
362
- let(:error) { ExampleException.new }
363
-
364
- it "should add the error to the current transaction and complete" do
365
- expect_any_instance_of(Appsignal::Transaction).to receive(:set_error).with(error)
366
- expect(Appsignal::Transaction).to receive(:complete_current!)
411
+ let(:error) { ExampleException.new("error message") }
367
412
 
413
+ it "adds the error to the current transaction and complete" do
368
414
  expect do
369
415
  Appsignal.monitor_transaction("perform_job.something") do
370
416
  raise error
371
417
  end
372
418
  end.to raise_error(error)
419
+
420
+ expect(last_transaction).to have_error("ExampleException", "error message")
421
+ expect(last_transaction).to be_completed
373
422
  end
374
423
  end
375
424
 
@@ -381,8 +430,11 @@ describe Appsignal do
381
430
  end
382
431
 
383
432
  it "logs an error" do
384
- Appsignal.monitor_transaction("unknown.sidekiq") {} # rubocop:disable Lint/EmptyBlock
385
- expect(log).to contains_log(
433
+ logs =
434
+ capture_logs do
435
+ Appsignal.monitor_transaction("unknown.sidekiq") {} # rubocop:disable Lint/EmptyBlock
436
+ end
437
+ expect(logs).to contains_log(
386
438
  :error,
387
439
  "Unrecognized name 'unknown.sidekiq': names must start with either 'perform_job' " \
388
440
  "(for jobs and tasks) or 'process_action' (for HTTP requests)"
@@ -392,8 +444,6 @@ describe Appsignal do
392
444
  end
393
445
 
394
446
  describe ".monitor_single_transaction" do
395
- around { |example| keep_transactions { example.run } }
396
-
397
447
  context "with a successful call" do
398
448
  it "calls monitor_transaction and Appsignal.stop" do
399
449
  expect(Appsignal).to receive(:stop)
@@ -407,18 +457,8 @@ describe Appsignal do
407
457
  end
408
458
 
409
459
  transaction = last_transaction
410
- transaction_hash = transaction.to_h
411
- expect(transaction_hash).to include(
412
- "action" => "my_controller#my_action"
413
- )
414
- expect(transaction_hash["events"]).to match([
415
- hash_including(
416
- "name" => "perform_job.something",
417
- "title" => "",
418
- "body" => "",
419
- "body_format" => Appsignal::EventFormatter::DEFAULT
420
- )
421
- ])
460
+ expect(transaction).to have_action("my_controller#my_action")
461
+ expect(transaction).to include_event("name" => "perform_job.something")
422
462
  end
423
463
  end
424
464
 
@@ -439,75 +479,131 @@ describe Appsignal do
439
479
  end.to raise_error(error)
440
480
 
441
481
  transaction = last_transaction
442
- transaction_hash = transaction.to_h
443
- expect(transaction_hash).to include(
444
- "action" => "my_controller#my_action"
445
- )
446
- expect(transaction_hash["events"]).to match([
447
- hash_including(
448
- "name" => "perform_job.something",
449
- "title" => "",
450
- "body" => "",
451
- "body_format" => Appsignal::EventFormatter::DEFAULT
452
- )
453
- ])
482
+ expect(transaction).to have_action("my_controller#my_action")
483
+ expect(transaction).to include_event("name" => "perform_job.something")
454
484
  end
455
485
  end
456
486
  end
457
487
 
458
488
  describe ".tag_request" do
459
- let(:transaction) { http_request_transaction }
460
- around do |example|
461
- start_agent
462
- with_current_transaction transaction do
463
- keep_transactions { example.run }
464
- end
465
- end
489
+ before { start_agent }
466
490
 
467
491
  context "with transaction" do
468
- it "calls set_tags on the current transaction" do
492
+ let(:transaction) { http_request_transaction }
493
+ before { set_current_transaction(transaction) }
494
+
495
+ it "sets tags on the current transaction" do
469
496
  Appsignal.tag_request("a" => "b")
470
- transaction.complete # Manually trigger transaction sampling
471
497
 
472
- expect(transaction.to_h).to include(
473
- "sample_data" => hash_including(
474
- "tags" => { "a" => "b" }
475
- )
476
- )
498
+ transaction._sample
499
+ expect(transaction).to include_tags("a" => "b")
477
500
  end
478
501
  end
479
502
 
480
503
  context "without transaction" do
481
504
  let(:transaction) { nil }
482
505
 
483
- it "should call set_tags on transaction" do
506
+ it "does not set tags on the transaction" do
484
507
  expect(Appsignal.tag_request).to be_falsy
508
+ Appsignal.tag_request("a" => "b")
509
+
510
+ expect_any_instance_of(Appsignal::Transaction).to_not receive(:set_tags)
485
511
  end
486
512
  end
487
513
 
488
- it "should also listen to tag_job" do
489
- expect(Appsignal).to respond_to(:tag_job)
514
+ it "also listens to tag_job" do
515
+ expect(Appsignal.method(:tag_job)).to eq(Appsignal.method(:tag_request))
516
+ end
517
+
518
+ it "also listens to set_tags" do
519
+ expect(Appsignal.method(:set_tags)).to eq(Appsignal.method(:tag_request))
490
520
  end
491
521
  end
492
522
 
493
- describe ".add_breadcrumb" do
494
- before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
523
+ describe ".set_params" do
524
+ before do
525
+ start_agent
526
+ end
495
527
 
496
528
  context "with transaction" do
497
529
  let(:transaction) { http_request_transaction }
498
- around do |example|
499
- Appsignal.config = project_fixture_config
500
- set_current_transaction transaction do
501
- example.run
502
- end
530
+ before { set_current_transaction(transaction) }
531
+
532
+ it "sets parameters on the transaction" do
533
+ Appsignal.set_params("param1" => "value1")
534
+
535
+ transaction._sample
536
+ expect(transaction).to include_params("param1" => "value1")
537
+ end
538
+
539
+ it "overwrites the params if called multiple times" do
540
+ Appsignal.set_params("param1" => "value1")
541
+ Appsignal.set_params("param2" => "value2")
542
+
543
+ transaction._sample
544
+ expect(transaction).to include_params("param2" => "value2")
545
+ end
546
+
547
+ it "sets parameters with a block on the transaction" do
548
+ Appsignal.set_params { { "param1" => "value1" } }
549
+
550
+ transaction._sample
551
+ expect(transaction).to include_params("param1" => "value1")
552
+ end
553
+ end
554
+
555
+ context "without transaction" do
556
+ it "does not set tags on the transaction" do
557
+ Appsignal.set_params("a" => "b")
558
+
559
+ expect_any_instance_of(Appsignal::Transaction).to_not receive(:set_params)
560
+ end
561
+ end
562
+ end
563
+
564
+ describe ".set_custom_data" do
565
+ before { start_agent }
566
+
567
+ context "with transaction" do
568
+ let(:transaction) { http_request_transaction }
569
+ before { set_current_transaction transaction }
570
+
571
+ it "sets custom data on the current transaction" do
572
+ Appsignal.set_custom_data(
573
+ :user => { :id => 123 },
574
+ :organization => { :slug => "appsignal" }
575
+ )
576
+
577
+ transaction._sample
578
+ expect(transaction).to include_custom_data(
579
+ "user" => { "id" => 123 },
580
+ "organization" => { "slug" => "appsignal" }
581
+ )
503
582
  end
583
+ end
584
+
585
+ context "without transaction" do
586
+ it "does not set tags on the transaction" do
587
+ Appsignal.set_custom_data(
588
+ :user => { :id => 123 },
589
+ :organization => { :slug => "appsignal" }
590
+ )
504
591
 
505
- it "should call add_breadcrumb on transaction" do
506
- expect(transaction).to receive(:add_breadcrumb)
507
- .with("Network", "http", "User made network request", { :response => 200 }, fixed_time)
592
+ expect_any_instance_of(Appsignal::Transaction).to_not receive(:set_custom_data)
508
593
  end
594
+ end
595
+ end
596
+
597
+ describe ".add_breadcrumb" do
598
+ around do |example|
599
+ start_agent
600
+ with_current_transaction(transaction) { example.run }
601
+ end
509
602
 
510
- after do
603
+ context "with transaction" do
604
+ let(:transaction) { http_request_transaction }
605
+
606
+ it "adds the breadcrumb to the transaction" do
511
607
  Appsignal.add_breadcrumb(
512
608
  "Network",
513
609
  "http",
@@ -515,13 +611,22 @@ describe Appsignal do
515
611
  { :response => 200 },
516
612
  fixed_time
517
613
  )
614
+
615
+ transaction._sample
616
+ expect(transaction).to include_breadcrumb(
617
+ "http",
618
+ "Network",
619
+ "User made network request",
620
+ { "response" => 200 },
621
+ fixed_time
622
+ )
518
623
  end
519
624
  end
520
625
 
521
626
  context "without transaction" do
522
627
  let(:transaction) { nil }
523
628
 
524
- it "should not call add_breadcrumb on transaction" do
629
+ it "does not add a breadcrumb to any transaction" do
525
630
  expect(Appsignal.add_breadcrumb("Network", "http")).to be_falsy
526
631
  end
527
632
  end
@@ -550,13 +655,15 @@ describe Appsignal do
550
655
  end
551
656
 
552
657
  it "should not raise an exception when out of range" do
553
- expect(Appsignal::Extension).to receive(:set_gauge).with("key", 10,
554
- Appsignal::Extension.data_map_new).and_raise(RangeError)
658
+ expect(Appsignal::Extension).to receive(:set_gauge).with(
659
+ "key",
660
+ 10,
661
+ Appsignal::Extension.data_map_new
662
+ ).and_raise(RangeError)
555
663
  expect(Appsignal.internal_logger).to receive(:warn)
556
664
  .with("Gauge value 10 for key 'key' is too big")
557
- expect do
558
- Appsignal.set_gauge("key", 10)
559
- end.to_not raise_error
665
+
666
+ Appsignal.set_gauge("key", 10)
560
667
  end
561
668
  end
562
669
 
@@ -634,9 +741,8 @@ describe Appsignal do
634
741
  .with("key", 10, Appsignal::Extension.data_map_new).and_raise(RangeError)
635
742
  expect(Appsignal.internal_logger).to receive(:warn)
636
743
  .with("Counter value 10 for key 'key' is too big")
637
- expect do
638
- Appsignal.increment_counter("key", 10)
639
- end.to_not raise_error
744
+
745
+ Appsignal.increment_counter("key", 10)
640
746
  end
641
747
  end
642
748
 
@@ -664,9 +770,8 @@ describe Appsignal do
664
770
  .with("key", 10, Appsignal::Extension.data_map_new).and_raise(RangeError)
665
771
  expect(Appsignal.internal_logger).to receive(:warn)
666
772
  .with("Distribution value 10 for key 'key' is too big")
667
- expect do
668
- Appsignal.add_distribution_value("key", 10)
669
- end.to_not raise_error
773
+
774
+ Appsignal.add_distribution_value("key", 10)
670
775
  end
671
776
  end
672
777
  end
@@ -706,46 +811,39 @@ describe Appsignal do
706
811
  end
707
812
 
708
813
  describe ".send_error" do
709
- let(:transaction) do
710
- Appsignal::Transaction.new(
711
- SecureRandom.uuid,
712
- Appsignal::Transaction::HTTP_REQUEST,
713
- Appsignal::Transaction::GenericRequest.new({})
714
- )
715
- end
716
- let(:error) { ExampleException.new }
814
+ let(:error) { ExampleException.new("error message") }
717
815
  let(:err_stream) { std_stream }
718
816
  let(:stderr) { err_stream.read }
719
- around { |example| keep_transactions { example.run } }
817
+ around do |example|
818
+ keep_transactions { example.run }
819
+ end
720
820
 
721
821
  it "sends the error to AppSignal" do
722
- expect(Appsignal::Transaction).to receive(:new).with(
723
- kind_of(String),
724
- Appsignal::Transaction::HTTP_REQUEST,
725
- kind_of(Appsignal::Transaction::GenericRequest)
726
- ).and_return(transaction)
727
- expect(transaction).to receive(:set_error).with(error)
728
- expect(transaction).to_not receive(:set_tags)
729
- expect(transaction).to receive(:complete)
822
+ expect { Appsignal.send_error(error) }.to(change { created_transactions.count }.by(1))
730
823
 
731
- Appsignal.send_error(error)
824
+ transaction = last_transaction
825
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
826
+ expect(transaction).to_not have_action
827
+ expect(transaction).to have_error("ExampleException", "error message")
828
+ expect(transaction).to_not include_tags
829
+ expect(transaction).to be_completed
732
830
  end
733
831
 
734
832
  context "when given error is not an Exception" do
735
- let(:error) { double }
833
+ let(:error) { "string value" }
736
834
 
737
835
  it "logs an error message" do
738
- expect(Appsignal.internal_logger).to receive(:error).with(
836
+ logs = capture_logs { Appsignal.send_error(error) }
837
+ expect(logs).to contains_log(
838
+ :error,
739
839
  "Appsignal.send_error: Cannot send error. " \
740
840
  "The given value is not an exception: #{error.inspect}"
741
841
  )
742
842
  end
743
843
 
744
844
  it "does not send the error" do
745
- expect(Appsignal::Transaction).to_not receive(:create)
845
+ expect { Appsignal.send_error(error) }.to_not(change { created_transactions.count })
746
846
  end
747
-
748
- after { Appsignal.send_error(error) }
749
847
  end
750
848
 
751
849
  context "with tags" do
@@ -760,13 +858,7 @@ describe Appsignal do
760
858
  end.to change { created_transactions.count }.by(1)
761
859
  end
762
860
 
763
- transaction = last_transaction
764
- transaction_hash = transaction.to_h
765
- expect(transaction_hash).to include(
766
- "sample_data" => hash_including(
767
- "tags" => { "a" => "a", "b" => "b" }
768
- )
769
- )
861
+ expect(last_transaction).to include_tags("a" => "a", "b" => "b")
770
862
 
771
863
  message = "The tags argument for `Appsignal.send_error` is deprecated. " \
772
864
  "Please use the block method to set tags instead.\n\n" \
@@ -791,9 +883,7 @@ describe Appsignal do
791
883
  end.to change { created_transactions.count }.by(1)
792
884
  end
793
885
 
794
- transaction = last_transaction
795
- transaction_hash = transaction.to_h
796
- expect(transaction_hash).to include("namespace" => namespace)
886
+ expect(last_transaction).to have_namespace(namespace)
797
887
 
798
888
  message = "The namespace argument for `Appsignal.send_error` is deprecated. " \
799
889
  "Please use the block method to set the namespace instead.\n\n" \
@@ -808,23 +898,15 @@ describe Appsignal do
808
898
 
809
899
  context "when given a block" do
810
900
  it "yields the transaction and allows additional metadata to be set" do
811
- captured_transaction = nil
812
901
  keep_transactions do
813
902
  Appsignal.send_error(StandardError.new("my_error")) do |transaction|
814
- captured_transaction = transaction
815
903
  transaction.set_action("my_action")
816
904
  transaction.set_namespace("my_namespace")
817
905
  end
818
906
  end
819
- expect(captured_transaction.to_h).to include(
820
- "namespace" => "my_namespace",
821
- "action" => "my_action",
822
- "error" => {
823
- "name" => "StandardError",
824
- "message" => "my_error",
825
- "backtrace" => kind_of(String) # TODO: should be Array
826
- }
827
- )
907
+ expect(last_transaction).to have_namespace("my_namespace")
908
+ expect(last_transaction).to have_action("my_action")
909
+ expect(last_transaction).to have_error("StandardError", "my_error")
828
910
  end
829
911
  end
830
912
  end
@@ -841,17 +923,10 @@ describe Appsignal do
841
923
  end.to raise_error(ExampleException, "I am an exception")
842
924
  end.to change { created_transactions.count }.by(1)
843
925
 
844
- expect(last_transaction.to_h).to include(
845
- "error" => {
846
- "name" => "ExampleException",
847
- "message" => "I am an exception",
848
- "backtrace" => kind_of(String)
849
- },
850
- "namespace" => Appsignal::Transaction::HTTP_REQUEST, # Default namespace
851
- "sample_data" => hash_including(
852
- "tags" => {}
853
- )
854
- )
926
+ # Default namespace
927
+ expect(last_transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
928
+ expect(last_transaction).to have_error("ExampleException", "I am an exception")
929
+ expect(last_transaction).to_not include_tags
855
930
  end
856
931
 
857
932
  context "with tags" do
@@ -864,17 +939,10 @@ describe Appsignal do
864
939
  end.to raise_error(ExampleException, "I am an exception")
865
940
  end.to change { created_transactions.count }.by(1)
866
941
 
867
- expect(last_transaction.to_h).to include(
868
- "error" => {
869
- "name" => "ExampleException",
870
- "message" => "I am an exception",
871
- "backtrace" => kind_of(String)
872
- },
873
- "namespace" => Appsignal::Transaction::HTTP_REQUEST, # Default namespace
874
- "sample_data" => hash_including(
875
- "tags" => { "foo" => "bar" }
876
- )
877
- )
942
+ # Default namespace
943
+ expect(last_transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
944
+ expect(last_transaction).to have_error("ExampleException", "I am an exception")
945
+ expect(last_transaction).to include_tags("foo" => "bar")
878
946
  end
879
947
  end
880
948
 
@@ -888,17 +956,10 @@ describe Appsignal do
888
956
  end.to raise_error(ExampleException, "I am an exception")
889
957
  end.to change { created_transactions.count }.by(1)
890
958
 
891
- expect(last_transaction.to_h).to include(
892
- "error" => {
893
- "name" => "ExampleException",
894
- "message" => "I am an exception",
895
- "backtrace" => kind_of(String)
896
- },
897
- "namespace" => "custom_namespace",
898
- "sample_data" => hash_including(
899
- "tags" => {}
900
- )
901
- )
959
+ # Default namespace
960
+ expect(last_transaction).to have_namespace("custom_namespace")
961
+ expect(last_transaction).to have_error("ExampleException", "I am an exception")
962
+ expect(last_transaction).to_not include_tags
902
963
  end
903
964
  end
904
965
  end
@@ -907,42 +968,56 @@ describe Appsignal do
907
968
  let(:err_stream) { std_stream }
908
969
  let(:stderr) { err_stream.read }
909
970
  let(:error) { ExampleException.new("I am an exception") }
910
- before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
971
+ let(:transaction) { http_request_transaction }
911
972
  around { |example| keep_transactions { example.run } }
912
973
 
913
974
  context "when there is an active transaction" do
914
- it "adds the error to the active transaction" do
915
- expect(transaction).to receive(:set_error).with(error)
916
- expect(transaction).to_not receive(:set_tags)
917
- expect(transaction).to_not receive(:set_namespace)
975
+ before { set_current_transaction(transaction) }
918
976
 
977
+ it "adds the error to the active transaction" do
919
978
  Appsignal.set_error(error)
979
+
980
+ transaction._sample
981
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
982
+ expect(transaction).to have_error("ExampleException", "I am an exception")
983
+ expect(transaction).to_not include_tags
920
984
  end
921
985
 
922
986
  context "when the error is not an Exception" do
923
987
  let(:error) { Object.new }
924
988
 
989
+ it "does not set an error" do
990
+ silence { Appsignal.set_error(error) }
991
+
992
+ transaction._sample
993
+ expect(transaction).to_not have_error
994
+ expect(transaction).to_not include_tags
995
+ end
996
+
925
997
  it "logs an error" do
926
- expect(Appsignal.internal_logger).to receive(:error).with(
998
+ logs = capture_logs { Appsignal.set_error(error) }
999
+ expect(logs).to contains_log(
1000
+ :error,
927
1001
  "Appsignal.set_error: Cannot set error. " \
928
1002
  "The given value is not an exception: #{error.inspect}"
929
1003
  )
930
- expect(transaction).to_not receive(:set_error)
931
- expect(transaction).to_not receive(:set_tags)
932
- expect(transaction).to_not receive(:set_namespace)
933
-
934
- Appsignal.set_error(error)
935
1004
  end
936
1005
  end
937
1006
 
938
1007
  context "with tags" do
939
1008
  let(:tags) { { "foo" => "bar" } }
940
1009
 
941
- it "prints a deprecation warning and tags the transaction" do
942
- expect(transaction).to receive(:set_error).with(error)
943
- expect(transaction).to receive(:set_tags).with(tags)
944
- expect(transaction).to_not receive(:set_namespace)
1010
+ it "tags the transaction" do
1011
+ silence(:allowed => ["set_error", "The tags argument for"]) do
1012
+ Appsignal.set_error(error, tags)
1013
+ end
1014
+
1015
+ transaction._sample
1016
+ expect(transaction).to have_error(error)
1017
+ expect(transaction).to include_tags(tags)
1018
+ end
945
1019
 
1020
+ it "prints a deprecation warning and tags the transaction" do
946
1021
  logs = capture_logs do
947
1022
  capture_std_streams(std_stream, err_stream) do
948
1023
  Appsignal.set_error(error, tags)
@@ -963,11 +1038,17 @@ describe Appsignal do
963
1038
  context "with namespace" do
964
1039
  let(:namespace) { "admin" }
965
1040
 
966
- it "prints a deprecation warning andsets the namespace on the transaction" do
967
- expect(transaction).to receive(:set_error).with(error)
968
- expect(transaction).to_not receive(:set_tags)
969
- expect(transaction).to receive(:set_namespace).with(namespace)
1041
+ it "sets the namespace on the transaction" do
1042
+ silence(:allowed => ["set_error", "The namespace argument for"]) do
1043
+ Appsignal.set_error(error, nil, namespace)
1044
+ end
970
1045
 
1046
+ expect(transaction).to have_error("ExampleException", "I am an exception")
1047
+ expect(transaction).to have_namespace(namespace)
1048
+ expect(transaction).to_not include_tags
1049
+ end
1050
+
1051
+ it "prints a deprecation warning andsets the namespace on the transaction" do
971
1052
  logs = capture_logs do
972
1053
  capture_std_streams(std_stream, err_stream) do
973
1054
  Appsignal.set_error(error, nil, namespace)
@@ -987,135 +1068,232 @@ describe Appsignal do
987
1068
 
988
1069
  context "when given a block" do
989
1070
  it "yields the transaction and allows additional metadata to be set" do
990
- captured_transaction = nil
991
- keep_transactions do
992
- Appsignal.set_error(StandardError.new("my_error")) do |transaction|
993
- captured_transaction = transaction
994
- transaction.set_action("my_action")
995
- transaction.set_namespace("my_namespace")
996
- end
1071
+ Appsignal.set_error(StandardError.new("my_error")) do |t|
1072
+ t.set_action("my_action")
1073
+ t.set_namespace("my_namespace")
997
1074
  end
998
1075
 
999
- expect(transaction).to eql(captured_transaction)
1000
- expect(captured_transaction.to_h).to include(
1001
- "namespace" => "my_namespace",
1002
- "action" => "my_action",
1003
- "error" => {
1004
- "name" => "StandardError",
1005
- "message" => "my_error",
1006
- "backtrace" => kind_of(String)
1007
- }
1008
- )
1076
+ expect(transaction).to have_namespace("my_namespace")
1077
+ expect(transaction).to have_action("my_action")
1078
+ expect(transaction).to have_error("StandardError", "my_error")
1009
1079
  end
1010
1080
  end
1011
1081
  end
1012
1082
 
1013
1083
  context "when there is no active transaction" do
1014
1084
  it "does nothing" do
1015
- allow(Appsignal::Transaction).to receive(:current).and_return(nil)
1085
+ Appsignal.set_error(error)
1016
1086
 
1017
- expect(transaction).to_not receive(:set_error)
1087
+ expect(transaction).to_not have_error
1088
+ end
1089
+ end
1090
+ end
1018
1091
 
1019
- Appsignal.set_error(error)
1092
+ describe ".report_error" do
1093
+ let(:err_stream) { std_stream }
1094
+ let(:stderr) { err_stream.read }
1095
+ let(:error) { ExampleException.new("error message") }
1096
+ before { start_agent }
1097
+ around { |example| keep_transactions { example.run } }
1098
+
1099
+ context "when the error is not an Exception" do
1100
+ let(:error) { Object.new }
1101
+
1102
+ it "does not set an error" do
1103
+ silence { Appsignal.report_error(error) }
1104
+
1105
+ expect(last_transaction).to_not have_error
1106
+ end
1107
+
1108
+ it "logs an error" do
1109
+ logs = capture_logs { Appsignal.report_error(error) }
1110
+ expect(logs).to contains_log(
1111
+ :error,
1112
+ "Appsignal.report_error: Cannot set error. " \
1113
+ "The given value is not an exception: #{error.inspect}"
1114
+ )
1115
+ end
1116
+ end
1117
+
1118
+ context "when there is no active transaction" do
1119
+ it "creates a new transaction" do
1120
+ expect do
1121
+ Appsignal.report_error(error)
1122
+ end.to(change { created_transactions.count }.by(1))
1123
+ end
1124
+
1125
+ it "completes the transaction" do
1126
+ Appsignal.report_error(error)
1127
+
1128
+ expect(last_transaction).to be_completed
1129
+ end
1130
+
1131
+ context "when given a block" do
1132
+ it "yields the transaction and allows additional metadata to be set" do
1133
+ Appsignal.report_error(error) do |t|
1134
+ t.set_action("my_action")
1135
+ t.set_namespace("my_namespace")
1136
+ t.set_tags(:tag1 => "value1")
1137
+ end
1138
+
1139
+ transaction = last_transaction
1140
+ expect(transaction).to have_namespace("my_namespace")
1141
+ expect(transaction).to have_action("my_action")
1142
+ expect(transaction).to have_error("ExampleException", "error message")
1143
+ expect(transaction).to include_tags("tag1" => "value1")
1144
+ expect(transaction).to be_completed
1145
+ end
1146
+ end
1147
+ end
1148
+
1149
+ context "when there is an active transaction" do
1150
+ let(:transaction) { http_request_transaction }
1151
+ before { set_current_transaction(transaction) }
1152
+
1153
+ it "adds the error to the active transaction" do
1154
+ Appsignal.report_error(error)
1155
+
1156
+ expect(last_transaction).to eq(transaction)
1157
+ transaction._sample
1158
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
1159
+ expect(transaction).to have_error("ExampleException", "error message")
1160
+ end
1161
+
1162
+ it "does not complete the transaction" do
1163
+ Appsignal.report_error(error)
1164
+
1165
+ expect(last_transaction).to_not be_completed
1166
+ end
1167
+
1168
+ context "when given a block" do
1169
+ it "yields the transaction and allows additional metadata to be set" do
1170
+ Appsignal.report_error(error) do |t|
1171
+ t.set_action("my_action")
1172
+ t.set_namespace("my_namespace")
1173
+ t.set_tags(:tag1 => "value1")
1174
+ end
1175
+
1176
+ transaction._sample
1177
+ expect(transaction).to have_namespace("my_namespace")
1178
+ expect(transaction).to have_action("my_action")
1179
+ expect(transaction).to have_error("ExampleException", "error message")
1180
+ expect(transaction).to include_tags("tag1" => "value1")
1181
+ expect(transaction).to_not be_completed
1182
+ end
1020
1183
  end
1021
1184
  end
1022
1185
  end
1023
1186
 
1024
1187
  describe ".set_action" do
1025
- before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
1188
+ around { |example| keep_transactions { example.run } }
1026
1189
 
1027
- it "should set the namespace to the current transaction" do
1028
- expect(transaction).to receive(:set_action).with("custom")
1190
+ context "with current transaction" do
1191
+ before { set_current_transaction(transaction) }
1029
1192
 
1030
- Appsignal.set_action("custom")
1031
- end
1193
+ it "sets the namespace on the current transaction" do
1194
+ Appsignal.set_action("custom")
1032
1195
 
1033
- it "should do nothing if there is no current transaction" do
1034
- allow(Appsignal::Transaction).to receive(:current).and_return(nil)
1196
+ expect(transaction).to have_action("custom")
1197
+ end
1035
1198
 
1036
- expect(transaction).to_not receive(:set_action)
1199
+ it "does not set the action if the action is nil" do
1200
+ Appsignal.set_action(nil)
1037
1201
 
1038
- Appsignal.set_action("custom")
1202
+ expect(transaction).to_not have_action
1203
+ end
1039
1204
  end
1040
1205
 
1041
- it "should do nothing if the error is nil" do
1042
- expect(transaction).to_not receive(:set_action)
1206
+ context "without current transaction" do
1207
+ it "does not set ther action" do
1208
+ Appsignal.set_action("custom")
1043
1209
 
1044
- Appsignal.set_action(nil)
1210
+ expect(transaction).to_not have_action
1211
+ end
1045
1212
  end
1046
1213
  end
1047
1214
 
1048
1215
  describe ".set_namespace" do
1049
- before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
1216
+ around { |example| keep_transactions { example.run } }
1050
1217
 
1051
- it "should set the namespace to the current transaction" do
1052
- expect(transaction).to receive(:set_namespace).with("custom")
1218
+ context "with current transaction" do
1219
+ before { set_current_transaction(transaction) }
1053
1220
 
1054
- Appsignal.set_namespace("custom")
1055
- end
1221
+ it "should set the namespace to the current transaction" do
1222
+ Appsignal.set_namespace("custom")
1056
1223
 
1057
- it "should do nothing if there is no current transaction" do
1058
- allow(Appsignal::Transaction).to receive(:current).and_return(nil)
1224
+ expect(transaction).to have_namespace("custom")
1225
+ end
1059
1226
 
1060
- expect(transaction).to_not receive(:set_namespace)
1227
+ it "does not update the namespace if the namespace is nil" do
1228
+ Appsignal.set_namespace(nil)
1061
1229
 
1062
- Appsignal.set_namespace("custom")
1230
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
1231
+ end
1063
1232
  end
1064
1233
 
1065
- it "should do nothing if the error is nil" do
1066
- expect(transaction).to_not receive(:set_namespace)
1234
+ context "without current transaction" do
1235
+ it "does not update the namespace" do
1236
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
1237
+
1238
+ Appsignal.set_namespace("custom")
1067
1239
 
1068
- Appsignal.set_namespace(nil)
1240
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
1241
+ end
1069
1242
  end
1070
1243
  end
1071
1244
 
1072
1245
  describe ".instrument" do
1073
1246
  it_behaves_like "instrument helper" do
1074
1247
  let(:instrumenter) { Appsignal }
1075
- before do
1076
- expect(Appsignal::Transaction).to receive(:current).at_least(:once)
1077
- .and_return(transaction)
1078
- end
1248
+ before { set_current_transaction(transaction) }
1079
1249
  end
1080
1250
  end
1081
1251
 
1082
1252
  describe ".instrument_sql" do
1083
- before do
1084
- expect(Appsignal::Transaction).to receive(:current).at_least(:once)
1085
- .and_return(transaction)
1086
- end
1253
+ around { |example| keep_transactions { example.run } }
1254
+ before { set_current_transaction(transaction) }
1087
1255
 
1088
1256
  it "creates an SQL event on the transaction" do
1089
- expect(transaction).to receive(:start_event)
1090
- expect(transaction).to receive(:finish_event)
1091
- .with("name", "title", "body", Appsignal::EventFormatter::SQL_BODY_FORMAT)
1257
+ result =
1258
+ Appsignal.instrument_sql "name", "title", "body" do
1259
+ "return value"
1260
+ end
1092
1261
 
1093
- result = Appsignal.instrument_sql "name", "title", "body" do
1094
- "return value"
1095
- end
1096
1262
  expect(result).to eq "return value"
1263
+ expect(transaction).to include_event(
1264
+ "name" => "name",
1265
+ "title" => "title",
1266
+ "body" => "body",
1267
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT
1268
+ )
1097
1269
  end
1098
1270
  end
1099
1271
 
1100
1272
  describe ".without_instrumentation" do
1273
+ around { |example| keep_transactions { example.run } }
1101
1274
  let(:transaction) { http_request_transaction }
1102
- before { allow(Appsignal::Transaction).to receive(:current).and_return(transaction) }
1103
1275
 
1104
- it "does not record events on the transaction" do
1105
- expect(transaction).to receive(:pause!).and_call_original
1106
- expect(transaction).to receive(:resume!).and_call_original
1107
- Appsignal.instrument("register.this.event") { :do_nothing }
1108
- Appsignal.without_instrumentation do
1109
- Appsignal.instrument("dont.register.this.event") { :do_nothing }
1276
+ context "with current transaction" do
1277
+ before { set_current_transaction(transaction) }
1278
+
1279
+ it "does not record events on the transaction" do
1280
+ expect(transaction).to receive(:pause!).and_call_original
1281
+ expect(transaction).to receive(:resume!).and_call_original
1282
+
1283
+ Appsignal.instrument("register.this.event") { :do_nothing }
1284
+ Appsignal.without_instrumentation do
1285
+ Appsignal.instrument("dont.register.this.event") { :do_nothing }
1286
+ end
1287
+
1288
+ expect(transaction).to include_event("name" => "register.this.event")
1289
+ expect(transaction).to_not include_event("name" => "dont.register.this.event")
1110
1290
  end
1111
- expect(transaction.to_h["events"].map { |e| e["name"] })
1112
- .to match_array("register.this.event")
1113
1291
  end
1114
1292
 
1115
- context "without transaction" do
1293
+ context "without current transaction" do
1116
1294
  let(:transaction) { nil }
1117
1295
 
1118
- it "should not crash" do
1296
+ it "does not crash" do
1119
1297
  Appsignal.without_instrumentation { :do_nothing }
1120
1298
  end
1121
1299
  end
@@ -1123,17 +1301,35 @@ describe Appsignal do
1123
1301
  end
1124
1302
 
1125
1303
  describe ".start_logger" do
1304
+ let(:stderr_stream) { std_stream }
1305
+ let(:stderr) { stderr_stream.read }
1306
+ let(:log_stream) { std_stream }
1307
+ let(:log) { log_contents(log_stream) }
1308
+
1309
+ it "prints and logs a deprecation warning" do
1310
+ use_logger_with(log_stream) do
1311
+ capture_std_streams(std_stream, stderr_stream) do
1312
+ Appsignal.start_logger
1313
+ end
1314
+ end
1315
+ expect(stderr).to include("appsignal WARNING: Callng 'Appsignal.start_logger' is deprecated.")
1316
+ expect(log).to contains_log(:warn, "Callng 'Appsignal.start_logger' is deprecated.")
1317
+ end
1318
+ end
1319
+
1320
+ describe "._start_logger" do
1126
1321
  let(:out_stream) { std_stream }
1127
1322
  let(:output) { out_stream.read }
1128
1323
  let(:log_path) { File.join(tmp_dir, "log") }
1129
1324
  let(:log_file) { File.join(log_path, "appsignal.log") }
1325
+ let(:log_level) { "debug" }
1130
1326
 
1131
1327
  before do
1132
1328
  FileUtils.mkdir_p(log_path)
1133
1329
  # Clear state from previous test
1134
1330
  Appsignal.internal_logger = nil
1135
- if Appsignal.instance_variable_defined?(:@in_memory_log)
1136
- Appsignal.remove_instance_variable(:@in_memory_log)
1331
+ if Appsignal.instance_variable_defined?(:@in_memory_logger)
1332
+ Appsignal.remove_instance_variable(:@in_memory_logger)
1137
1333
  end
1138
1334
  end
1139
1335
  after { FileUtils.rm_rf(log_path) }
@@ -1141,10 +1337,12 @@ describe Appsignal do
1141
1337
  def initialize_config
1142
1338
  Appsignal.config = project_fixture_config(
1143
1339
  "production",
1144
- :log_path => log_path
1340
+ :log_path => log_path,
1341
+ :log_level => log_level
1145
1342
  )
1146
- Appsignal.internal_logger.error("Log in memory")
1147
- expect(Appsignal.in_memory_log.string).to_not be_empty
1343
+ Appsignal.internal_logger.error("Log in memory line 1")
1344
+ Appsignal.internal_logger.debug("Log in memory line 2")
1345
+ expect(Appsignal.in_memory_logger.messages).to_not be_empty
1148
1346
  end
1149
1347
 
1150
1348
  context "when the log path is writable" do
@@ -1154,7 +1352,7 @@ describe Appsignal do
1154
1352
  before do
1155
1353
  capture_stdout(out_stream) do
1156
1354
  initialize_config
1157
- Appsignal.start_logger
1355
+ Appsignal._start_logger
1158
1356
  Appsignal.internal_logger.error("Log to file")
1159
1357
  end
1160
1358
  expect(Appsignal.internal_logger).to be_a(Appsignal::Utils::IntegrationLogger)
@@ -1166,12 +1364,26 @@ describe Appsignal do
1166
1364
  expect(output).to be_empty
1167
1365
  end
1168
1366
 
1169
- it "amends in memory log to log file" do
1170
- expect(log_file_contents).to include "[ERROR] appsignal: Log in memory"
1367
+ context "with log level info" do
1368
+ let(:log_level) { "info" }
1369
+
1370
+ it "amends info log level and higher memory log messages to log file" do
1371
+ expect(log_file_contents).to include "[ERROR] appsignal: Log in memory line 1"
1372
+ expect(log_file_contents).to_not include "[DEBUG]"
1373
+ end
1374
+ end
1375
+
1376
+ context "with log level debug" do
1377
+ let(:log_level) { "debug" }
1378
+
1379
+ it "amends debug log level and higher memory log messages to log file" do
1380
+ expect(log_file_contents).to include "[ERROR] appsignal: Log in memory line 1"
1381
+ expect(log_file_contents).to include "[DEBUG] appsignal: Log in memory line 2"
1382
+ end
1171
1383
  end
1172
1384
 
1173
1385
  it "clears the in memory log after writing to the new logger" do
1174
- expect(Appsignal.in_memory_log.string).to be_empty
1386
+ expect(Appsignal.instance_variable_get(:@in_memory_logger)).to be_nil
1175
1387
  end
1176
1388
  end
1177
1389
 
@@ -1182,7 +1394,7 @@ describe Appsignal do
1182
1394
 
1183
1395
  capture_stdout(out_stream) do
1184
1396
  initialize_config
1185
- Appsignal.start_logger
1397
+ Appsignal._start_logger
1186
1398
  Appsignal.internal_logger.error("Log to not writable log file")
1187
1399
  expect(Appsignal.internal_logger).to be_a(Appsignal::Utils::IntegrationLogger)
1188
1400
  end
@@ -1198,7 +1410,7 @@ describe Appsignal do
1198
1410
  end
1199
1411
 
1200
1412
  it "clears the in memory log after writing to the new logger" do
1201
- expect(Appsignal.in_memory_log.string).to be_empty
1413
+ expect(Appsignal.instance_variable_get(:@in_memory_logger)).to be_nil
1202
1414
  end
1203
1415
 
1204
1416
  it "outputs a warning" do
@@ -1216,7 +1428,7 @@ describe Appsignal do
1216
1428
 
1217
1429
  capture_stdout(out_stream) do
1218
1430
  initialize_config
1219
- Appsignal.start_logger
1431
+ Appsignal._start_logger
1220
1432
  Appsignal.internal_logger.error("Log to not writable log path")
1221
1433
  end
1222
1434
  expect(Appsignal.internal_logger).to be_a(Appsignal::Utils::IntegrationLogger)
@@ -1245,7 +1457,7 @@ describe Appsignal do
1245
1457
  before do
1246
1458
  capture_stdout(out_stream) do
1247
1459
  initialize_config
1248
- Appsignal.start_logger
1460
+ Appsignal._start_logger
1249
1461
  Appsignal.internal_logger.error("Log to stdout")
1250
1462
  end
1251
1463
  expect(Appsignal.internal_logger).to be_a(Appsignal::Utils::IntegrationLogger)
@@ -1261,7 +1473,7 @@ describe Appsignal do
1261
1473
  end
1262
1474
 
1263
1475
  it "clears the in memory log after writing to the new logger" do
1264
- expect(Appsignal.in_memory_log.string).to be_empty
1476
+ expect(Appsignal.instance_variable_get(:@in_memory_logger)).to be_nil
1265
1477
  end
1266
1478
  end
1267
1479
 
@@ -1272,7 +1484,7 @@ describe Appsignal do
1272
1484
  before do
1273
1485
  Appsignal.config = nil
1274
1486
  capture_stdout(out_stream) do
1275
- Appsignal.start_logger
1487
+ Appsignal._start_logger
1276
1488
  end
1277
1489
  end
1278
1490
 
@@ -1287,7 +1499,7 @@ describe Appsignal do
1287
1499
  capture_stdout(out_stream) do
1288
1500
  initialize_config
1289
1501
  Appsignal.config[:log_level] = "debug"
1290
- Appsignal.start_logger
1502
+ Appsignal._start_logger
1291
1503
  end
1292
1504
  end
1293
1505