appsignal 3.9.2-java → 3.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
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