appsignal 3.10.0-java → 3.11.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +88 -0
  4. data/Gemfile +1 -0
  5. data/benchmark.rake +99 -42
  6. data/lib/appsignal/cli/demo.rb +0 -1
  7. data/lib/appsignal/config.rb +54 -98
  8. data/lib/appsignal/demo.rb +15 -20
  9. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  10. data/lib/appsignal/event_formatter.rb +3 -2
  11. data/lib/appsignal/helpers/instrumentation.rb +331 -19
  12. data/lib/appsignal/hooks/action_cable.rb +21 -16
  13. data/lib/appsignal/hooks/active_job.rb +14 -8
  14. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  15. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  16. data/lib/appsignal/integrations/action_cable.rb +5 -7
  17. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  18. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  19. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  20. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  21. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  22. data/lib/appsignal/integrations/excon.rb +1 -0
  23. data/lib/appsignal/integrations/http.rb +1 -0
  24. data/lib/appsignal/integrations/net_http.rb +1 -0
  25. data/lib/appsignal/integrations/object.rb +6 -0
  26. data/lib/appsignal/integrations/que.rb +13 -20
  27. data/lib/appsignal/integrations/railtie.rb +1 -1
  28. data/lib/appsignal/integrations/rake.rb +1 -5
  29. data/lib/appsignal/integrations/redis.rb +1 -0
  30. data/lib/appsignal/integrations/redis_client.rb +1 -0
  31. data/lib/appsignal/integrations/resque.rb +2 -5
  32. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  33. data/lib/appsignal/integrations/sidekiq.rb +7 -15
  34. data/lib/appsignal/integrations/unicorn.rb +1 -0
  35. data/lib/appsignal/integrations/webmachine.rb +2 -5
  36. data/lib/appsignal/logger.rb +7 -3
  37. data/lib/appsignal/probes/helpers.rb +1 -0
  38. data/lib/appsignal/probes/mri.rb +1 -0
  39. data/lib/appsignal/probes/sidekiq.rb +1 -0
  40. data/lib/appsignal/probes.rb +3 -0
  41. data/lib/appsignal/rack/abstract_middleware.rb +18 -12
  42. data/lib/appsignal/rack/event_handler.rb +39 -8
  43. data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
  44. data/lib/appsignal/rack/grape_middleware.rb +2 -1
  45. data/lib/appsignal/rack/streaming_listener.rb +1 -0
  46. data/lib/appsignal/rack.rb +29 -0
  47. data/lib/appsignal/span.rb +1 -0
  48. data/lib/appsignal/transaction.rb +308 -101
  49. data/lib/appsignal/utils/data.rb +0 -1
  50. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  51. data/lib/appsignal/utils/integration_logger.rb +0 -13
  52. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  53. data/lib/appsignal/utils/json.rb +0 -1
  54. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  55. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  56. data/lib/appsignal/utils.rb +6 -0
  57. data/lib/appsignal/version.rb +1 -1
  58. data/lib/appsignal.rb +6 -5
  59. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  60. data/spec/lib/appsignal/config_spec.rb +138 -43
  61. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  62. data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
  63. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  64. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  65. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  66. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  67. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  68. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
  69. data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
  70. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +48 -3
  71. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
  72. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  73. data/spec/lib/appsignal/rack_spec.rb +63 -0
  74. data/spec/lib/appsignal/transaction_spec.rb +1634 -1071
  75. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  76. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  77. data/spec/lib/appsignal_spec.rb +323 -10
  78. data/spec/support/helpers/transaction_helpers.rb +44 -20
  79. data/spec/support/matchers/transaction.rb +15 -1
  80. data/spec/support/testing.rb +1 -1
  81. metadata +6 -2
@@ -4,7 +4,6 @@ require "logger"
4
4
 
5
5
  module Appsignal
6
6
  module Utils
7
- # @api private
8
7
  class IntegrationMemoryLogger
9
8
  LEVELS = {
10
9
  Logger::DEBUG => :DEBUG,
@@ -35,18 +34,6 @@ module Appsignal
35
34
  add(:WARN, message)
36
35
  end
37
36
 
38
- def seen_keys
39
- @seen_keys ||= Set.new
40
- end
41
-
42
- def warn_once_then_debug(key, message)
43
- if seen_keys.add?(key).nil?
44
- debug message
45
- else
46
- warn message
47
- end
48
- end
49
-
50
37
  def error(message)
51
38
  add(:ERROR, message)
52
39
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Appsignal
4
4
  module Utils
5
- # @api private
6
5
  class JSON
7
6
  class << self
8
7
  def generate(body)
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Appsignal
4
4
  module Utils
5
- # @api private
6
5
  class QueryParamsSanitizer
7
6
  REPLACEMENT_KEY = "?"
8
7
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Appsignal
4
4
  module Utils
5
- # @api private
6
5
  module StdoutAndLoggerMessage
7
6
  def self.warning(message, logger = Appsignal.internal_logger)
8
7
  Kernel.warn "appsignal WARNING: #{message}"
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ module Appsignal
4
+ # @api private
5
+ module Utils
6
+ end
7
+ end
8
+
3
9
  require "appsignal/utils/integration_memory_logger"
4
10
  require "appsignal/utils/stdout_and_logger_message"
5
11
  require "appsignal/utils/data"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.10.0"
4
+ VERSION = "3.11.0"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -47,7 +47,7 @@ module Appsignal
47
47
  # @see Extension
48
48
  # @see extension_loaded?
49
49
  attr_accessor :extension_loaded
50
- # @!attribute [rw] logger
50
+ # @!attribute [rw] internal_logger
51
51
  # Accessor for the internal AppSignal logger.
52
52
  #
53
53
  # Not to be confused with our logging feature.
@@ -59,10 +59,8 @@ module Appsignal
59
59
  # {.start}) the contents of the "in memory logger" is written to the new
60
60
  # logger.
61
61
  #
62
- # @note some classes may have options to set custom loggers. Their
63
- # defaults are pointed to this attribute.
64
62
  # @api private
65
- # @return [Logger]
63
+ # @return [Utils::IntegrationLogger or Utils::IntegrationMemoryLogger]
66
64
  # @see start
67
65
  attr_writer :internal_logger
68
66
 
@@ -165,10 +163,12 @@ module Appsignal
165
163
  Appsignal::Extension.start
166
164
  end
167
165
 
166
+ # @api private
168
167
  def get_server_state(key)
169
168
  Appsignal::Extension.get_server_state(key)
170
169
  end
171
170
 
171
+ # @api private
172
172
  def in_memory_logger
173
173
  @in_memory_logger ||=
174
174
  Appsignal::Utils::IntegrationMemoryLogger.new.tap do |l|
@@ -176,6 +176,7 @@ module Appsignal
176
176
  end
177
177
  end
178
178
 
179
+ # @api private
179
180
  def internal_logger
180
181
  @internal_logger ||= in_memory_logger
181
182
  end
@@ -195,7 +196,7 @@ module Appsignal
195
196
  def start_logger
196
197
  callers = caller
197
198
  Appsignal::Utils::StdoutAndLoggerMessage.warning \
198
- "Callng 'Appsignal.start_logger' is deprecated. " \
199
+ "Calling 'Appsignal.start_logger' is deprecated. " \
199
200
  "The logger will be started when calling 'Appsignal.start'. " \
200
201
  "Remove the 'Appsignal.start_logger' call in the following file to " \
201
202
  "remove this message.\n#{callers.first}"
@@ -17,7 +17,7 @@ if DependencyHelper.capistrano2_present?
17
17
  c.dry_run = false
18
18
  end
19
19
  end
20
- before { Appsignal::Capistrano.tasks(capistrano_config) }
20
+ before { Appsignal::Integrations::Capistrano.tasks(capistrano_config) }
21
21
 
22
22
  def run
23
23
  capture_stdout(out_stream) do
@@ -1,19 +1,4 @@
1
1
  describe Appsignal::Config do
2
- describe "config keys" do
3
- it "all config keys have an environment variable version registered" do
4
- config = Appsignal::Config
5
- mapped_env_keys = config::ENV_TO_KEY_MAPPING.keys.sort
6
- configured_env_keys = (
7
- config::ENV_STRING_KEYS +
8
- config::ENV_BOOLEAN_KEYS +
9
- config::ENV_ARRAY_KEYS +
10
- config::ENV_FLOAT_KEYS
11
- ).sort
12
-
13
- expect(mapped_env_keys).to eql(configured_env_keys)
14
- end
15
- end
16
-
17
2
  describe "#initialize" do
18
3
  describe "environment" do
19
4
  context "when environment is nil" do
@@ -416,49 +401,159 @@ describe Appsignal::Config do
416
401
  let(:working_directory_path) { File.join(tmp_dir, "test_working_directory_path") }
417
402
  let(:env_config) do
418
403
  {
419
- :running_in_container => true,
420
- :push_api_key => "aaa-bbb-ccc",
421
404
  :active => true,
405
+ :activejob_report_errors => "all",
422
406
  :bind_address => "0.0.0.0",
407
+ :ca_file_path => "/some/path",
423
408
  :cpu_count => 1.5,
424
- :name => "App name",
425
409
  :debug => true,
426
410
  :dns_servers => ["8.8.8.8", "8.8.4.4"],
427
- :ignore_actions => %w[action1 action2],
428
- :ignore_errors => %w[ExampleStandardError AnotherError],
411
+ :enable_allocation_tracking => false,
412
+ :enable_gvl_global_timer => false,
413
+ :enable_gvl_waiting_threads => false,
414
+ :enable_host_metrics => false,
415
+ :enable_minutely_probes => false,
416
+ :enable_nginx_metrics => false,
417
+ :enable_rails_error_reporter => false,
418
+ :enable_rake_performance_instrumentation => false,
419
+ :enable_statsd => false,
420
+ :endpoint => "https://test.appsignal.com",
421
+ :files_world_accessible => false,
422
+ :filter_metadata => ["key1", "key2"],
423
+ :filter_parameters => ["param1", "param2"],
424
+ :filter_session_data => ["session1", "session2"],
425
+ :host_role => "my host role",
426
+ :hostname => "my hostname",
427
+ :http_proxy => "some proxy",
428
+ :ignore_actions => ["action1", "action2"],
429
+ :ignore_errors => ["ExampleStandardError", "AnotherError"],
429
430
  :ignore_logs => ["^start$", "^Completed 2.* in .*ms (.*)"],
430
- :ignore_namespaces => %w[admin private_namespace],
431
+ :ignore_namespaces => ["admin", "private_namespace"],
432
+ :instrument_http_rb => false,
431
433
  :instrument_net_http => false,
432
434
  :instrument_redis => false,
433
435
  :instrument_sequel => false,
434
- :files_world_accessible => false,
435
- :request_headers => %w[accept accept-charset],
436
+ :log => "file",
437
+ :log_level => "debug",
438
+ :log_path => "/tmp/something",
439
+ :logging_endpoint => "https://appsignal-endpoint.net/test",
440
+ :name => "App name",
441
+ :push_api_key => "aaa-bbb-ccc",
442
+ :request_headers => ["accept", "accept-charset"],
436
443
  :revision => "v2.5.1",
444
+ :running_in_container => true,
437
445
  :send_environment_metadata => false,
446
+ :send_params => false,
447
+ :send_session_data => false,
448
+ :sidekiq_report_errors => "all",
449
+ :skip_session_data => false,
450
+ :statsd_port => "7890",
451
+ :transaction_debug_mode => false,
452
+ :working_dir_path => "/some/path",
438
453
  :working_directory_path => working_directory_path
439
454
  }
440
455
  end
456
+ let(:env_vars) do
457
+ {
458
+ # Strings
459
+ "APPSIGNAL_ACTIVEJOB_REPORT_ERRORS" => "all",
460
+ "APPSIGNAL_APP_NAME" => "App name",
461
+ "APPSIGNAL_BIND_ADDRESS" => "0.0.0.0",
462
+ "APPSIGNAL_CA_FILE_PATH" => "/some/path",
463
+ "APPSIGNAL_HOSTNAME" => "my hostname",
464
+ "APPSIGNAL_HOST_ROLE" => "my host role",
465
+ "APPSIGNAL_HTTP_PROXY" => "some proxy",
466
+ "APPSIGNAL_LOG" => "file",
467
+ "APPSIGNAL_LOGGING_ENDPOINT" => "https://appsignal-endpoint.net/test",
468
+ "APPSIGNAL_LOG_LEVEL" => "debug",
469
+ "APPSIGNAL_LOG_PATH" => "/tmp/something",
470
+ "APPSIGNAL_PUSH_API_ENDPOINT" => "https://test.appsignal.com",
471
+ "APPSIGNAL_PUSH_API_KEY" => "aaa-bbb-ccc",
472
+ "APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => "all",
473
+ "APPSIGNAL_STATSD_PORT" => "7890",
474
+ "APPSIGNAL_WORKING_DIRECTORY_PATH" => working_directory_path,
475
+ "APPSIGNAL_WORKING_DIR_PATH" => "/some/path",
476
+ "APP_REVISION" => "v2.5.1",
477
+
478
+ # Booleans
479
+ "APPSIGNAL_ACTIVE" => "true",
480
+ "APPSIGNAL_DEBUG" => "true",
481
+ "APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => "false",
482
+ "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER" => "false",
483
+ "APPSIGNAL_ENABLE_GVL_WAITING_THREADS" => "false",
484
+ "APPSIGNAL_ENABLE_HOST_METRICS" => "false",
485
+ "APPSIGNAL_ENABLE_MINUTELY_PROBES" => "false",
486
+ "APPSIGNAL_ENABLE_NGINX_METRICS" => "false",
487
+ "APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER" => "false",
488
+ "APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION" => "false",
489
+ "APPSIGNAL_ENABLE_STATSD" => "false",
490
+ "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => "false",
491
+ "APPSIGNAL_INSTRUMENT_HTTP_RB" => "false",
492
+ "APPSIGNAL_INSTRUMENT_NET_HTTP" => "false",
493
+ "APPSIGNAL_INSTRUMENT_REDIS" => "false",
494
+ "APPSIGNAL_INSTRUMENT_SEQUEL" => "false",
495
+ "APPSIGNAL_RUNNING_IN_CONTAINER" => "true",
496
+ "APPSIGNAL_SEND_ENVIRONMENT_METADATA" => "false",
497
+ "APPSIGNAL_SEND_PARAMS" => "false",
498
+ "APPSIGNAL_SEND_SESSION_DATA" => "false",
499
+ "APPSIGNAL_SKIP_SESSION_DATA" => "false",
500
+ "APPSIGNAL_TRANSACTION_DEBUG_MODE" => "false",
501
+
502
+ # Arrays
503
+ "APPSIGNAL_DNS_SERVERS" => "8.8.8.8,8.8.4.4",
504
+ "APPSIGNAL_FILTER_METADATA" => "key1,key2",
505
+ "APPSIGNAL_FILTER_PARAMETERS" => "param1,param2",
506
+ "APPSIGNAL_FILTER_SESSION_DATA" => "session1,session2",
507
+ "APPSIGNAL_IGNORE_ACTIONS" => "action1,action2",
508
+ "APPSIGNAL_IGNORE_ERRORS" => "ExampleStandardError,AnotherError",
509
+ "APPSIGNAL_IGNORE_LOGS" => "^start$,^Completed 2.* in .*ms (.*)",
510
+ "APPSIGNAL_IGNORE_NAMESPACES" => "admin,private_namespace",
511
+ "APPSIGNAL_REQUEST_HEADERS" => "accept,accept-charset",
512
+
513
+ # Floats
514
+ "APPSIGNAL_CPU_COUNT" => "1.5"
515
+ }
516
+ end
441
517
  before do
442
- ENV["APPSIGNAL_RUNNING_IN_CONTAINER"] = "true"
443
- ENV["APPSIGNAL_PUSH_API_KEY"] = "aaa-bbb-ccc"
444
- ENV["APPSIGNAL_ACTIVE"] = "true"
445
- ENV["APPSIGNAL_APP_NAME"] = "App name"
446
- ENV["APPSIGNAL_BIND_ADDRESS"] = "0.0.0.0"
447
- ENV["APPSIGNAL_CPU_COUNT"] = "1.5"
448
- ENV["APPSIGNAL_DEBUG"] = "true"
449
- ENV["APPSIGNAL_DNS_SERVERS"] = "8.8.8.8,8.8.4.4"
450
- ENV["APPSIGNAL_IGNORE_ACTIONS"] = "action1,action2"
451
- ENV["APPSIGNAL_IGNORE_ERRORS"] = "ExampleStandardError,AnotherError"
452
- ENV["APPSIGNAL_IGNORE_LOGS"] = "^start$,^Completed 2.* in .*ms (.*)"
453
- ENV["APPSIGNAL_IGNORE_NAMESPACES"] = "admin,private_namespace"
454
- ENV["APPSIGNAL_INSTRUMENT_NET_HTTP"] = "false"
455
- ENV["APPSIGNAL_INSTRUMENT_REDIS"] = "false"
456
- ENV["APPSIGNAL_INSTRUMENT_SEQUEL"] = "false"
457
- ENV["APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = "false"
458
- ENV["APPSIGNAL_REQUEST_HEADERS"] = "accept,accept-charset"
459
- ENV["APPSIGNAL_SEND_ENVIRONMENT_METADATA"] = "false"
460
- ENV["APPSIGNAL_WORKING_DIRECTORY_PATH"] = working_directory_path
461
- ENV["APP_REVISION"] = "v2.5.1"
518
+ env_vars.each do |key, value|
519
+ ENV[key] = value
520
+ end
521
+ end
522
+
523
+ it "reads all string env keys" do
524
+ config
525
+
526
+ Appsignal::Config::ENV_STRING_KEYS.each do |env_key, option|
527
+ ENV.fetch(env_key) { raise "Config env var '#{env_key}' is not set for this test" }
528
+ expect(config[option]).to eq(ENV.fetch(env_key, nil))
529
+ end
530
+ end
531
+
532
+ it "reads all boolean env keys" do
533
+ config
534
+
535
+ Appsignal::Config::ENV_BOOLEAN_KEYS.each do |env_key, option|
536
+ ENV.fetch(env_key) { raise "Config env var '#{env_key}' is not set for this test" }
537
+ expect(config[option]).to eq(ENV.fetch(env_key, nil) == "true")
538
+ end
539
+ end
540
+
541
+ it "reads all array env keys" do
542
+ config
543
+
544
+ Appsignal::Config::ENV_ARRAY_KEYS.each do |env_key, option|
545
+ ENV.fetch(env_key) { raise "Config env var '#{env_key}' is not set for this test" }
546
+ expect(config[option]).to eq(ENV.fetch(env_key, nil).split(","))
547
+ end
548
+ end
549
+
550
+ it "reads all float env keys" do
551
+ config
552
+
553
+ Appsignal::Config::ENV_FLOAT_KEYS.each do |env_key, option|
554
+ ENV.fetch(env_key) { raise "Config env var '#{env_key}' is not set for this test" }
555
+ expect(config[option]).to eq(ENV.fetch(env_key, nil).to_f)
556
+ end
462
557
  end
463
558
 
464
559
  it "overrides config with environment values" do
@@ -14,13 +14,6 @@ describe Appsignal::Hooks::ActionCableHook do
14
14
  end
15
15
 
16
16
  describe ActionCable::Channel::Base do
17
- let(:transaction) do
18
- Appsignal::Transaction.new(
19
- transaction_id,
20
- Appsignal::Transaction::ACTION_CABLE,
21
- ActionDispatch::Request.new(env)
22
- )
23
- end
24
17
  let(:channel) do
25
18
  Class.new(ActionCable::Channel::Base) do
26
19
  def speak(_data)
@@ -37,21 +30,20 @@ describe Appsignal::Hooks::ActionCableHook do
37
30
  s.config.logger = ActiveSupport::Logger.new(log)
38
31
  end
39
32
  end
33
+ let(:env) do
34
+ http_request_env_with_data(
35
+ "action_dispatch.request_id" => request_id,
36
+ :params => params,
37
+ :with_queue_start => true
38
+ )
39
+ end
40
40
  let(:connection) { ActionCable::Connection::Base.new(server, env) }
41
41
  let(:identifier) { { :channel => "MyChannel" }.to_json }
42
42
  let(:params) { {} }
43
43
  let(:request_id) { SecureRandom.uuid }
44
- let(:transaction_id) { request_id }
45
- let(:env) do
46
- http_request_env_with_data("action_dispatch.request_id" => request_id, :params => params)
47
- end
48
44
  let(:instance) { channel.new(connection, identifier, params) }
49
45
  before do
50
46
  start_agent
51
- expect(Appsignal.active?).to be_truthy
52
- transaction
53
-
54
- set_current_transaction(transaction)
55
47
 
56
48
  # Stub transmit call for subscribe/unsubscribe tests
57
49
  allow(connection).to receive(:websocket)
@@ -64,7 +56,7 @@ describe Appsignal::Hooks::ActionCableHook do
64
56
  instance.perform_action("message" => "foo", "action" => "speak")
65
57
 
66
58
  transaction = last_transaction
67
- expect(transaction).to have_id(transaction_id)
59
+ expect(transaction).to have_id
68
60
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
69
61
  expect(transaction).to have_action("MyChannel#speak")
70
62
  expect(transaction).to_not have_error
@@ -83,40 +75,20 @@ describe Appsignal::Hooks::ActionCableHook do
83
75
  "action" => "speak",
84
76
  "message" => "foo"
85
77
  )
78
+ expect(transaction).to include_tags("request_id" => request_id)
79
+ expect(transaction).to_not have_queue_start
80
+ expect(transaction).to be_completed
86
81
  end
87
82
 
88
83
  context "without request_id (standalone server)" do
89
84
  let(:request_id) { nil }
90
- let(:transaction_id) { SecureRandom.uuid }
91
- let(:action_transaction) do
92
- Appsignal::Transaction.new(
93
- transaction_id,
94
- Appsignal::Transaction::ACTION_CABLE,
95
- ActionDispatch::Request.new(env)
96
- )
97
- end
98
- before do
99
- # Stub future (private AppSignal) transaction id generated by the hook.
100
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
101
- end
102
85
 
103
- it "uses its own internal request_id set by the subscribed callback" do
86
+ it "sets a generated request ID" do
104
87
  # Subscribe action, sets the request_id
105
88
  instance.subscribe_to_channel
106
- expect(transaction).to have_id(transaction_id)
107
-
108
- # Expect another transaction for the action.
109
- # This transaction will use the same request_id as the
110
- # transaction id used to subscribe to the channel.
111
- expect(Appsignal::Transaction).to receive(:create).with(
112
- transaction_id,
113
- Appsignal::Transaction::ACTION_CABLE,
114
- kind_of(ActionDispatch::Request)
115
- ).and_return(action_transaction)
116
- allow(Appsignal::Transaction).to receive(:current).and_return(action_transaction)
117
89
 
118
90
  instance.perform_action("message" => "foo", "action" => "speak")
119
- expect(action_transaction).to have_id(transaction_id)
91
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
120
92
  end
121
93
  end
122
94
 
@@ -139,7 +111,7 @@ describe Appsignal::Hooks::ActionCableHook do
139
111
  end.to raise_error(ExampleException)
140
112
 
141
113
  transaction = last_transaction
142
- expect(transaction).to have_id(transaction_id)
114
+ expect(transaction).to have_id
143
115
  expect(transaction).to have_action("MyChannel#speak")
144
116
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
145
117
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -151,6 +123,8 @@ describe Appsignal::Hooks::ActionCableHook do
151
123
  "action" => "speak",
152
124
  "message" => "foo"
153
125
  )
126
+ expect(transaction).to_not have_queue_start
127
+ expect(transaction).to be_completed
154
128
  end
155
129
  end
156
130
  end
@@ -162,7 +136,7 @@ describe Appsignal::Hooks::ActionCableHook do
162
136
  instance.subscribe_to_channel
163
137
 
164
138
  transaction = last_transaction
165
- expect(transaction).to have_id(transaction_id)
139
+ expect(transaction).to have_id
166
140
  expect(transaction).to have_action("MyChannel#subscribed")
167
141
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
168
142
  expect(transaction).to_not have_error
@@ -178,18 +152,17 @@ describe Appsignal::Hooks::ActionCableHook do
178
152
  "name" => "subscribed.action_cable",
179
153
  "title" => ""
180
154
  )
155
+ expect(transaction).to include_tags("request_id" => request_id)
156
+ expect(transaction).to_not have_queue_start
157
+ expect(transaction).to be_completed
181
158
  end
182
159
 
183
160
  context "without request_id (standalone server)" do
184
161
  let(:request_id) { nil }
185
- let(:transaction_id) { SecureRandom.uuid }
186
- before do
187
- allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
188
- instance.subscribe_to_channel
189
- end
162
+ before { instance.subscribe_to_channel }
190
163
 
191
- it "uses its own internal request_id" do
192
- expect(last_transaction).to have_id(transaction_id)
164
+ it "sets a generated request ID" do
165
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
193
166
  end
194
167
  end
195
168
 
@@ -212,7 +185,7 @@ describe Appsignal::Hooks::ActionCableHook do
212
185
  end.to raise_error(ExampleException)
213
186
 
214
187
  transaction = last_transaction
215
- expect(transaction).to have_id(transaction_id)
188
+ expect(transaction).to have_id
216
189
  expect(transaction).to have_action("MyChannel#subscribed")
217
190
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
218
191
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -221,23 +194,20 @@ describe Appsignal::Hooks::ActionCableHook do
221
194
  "path" => "/blog"
222
195
  )
223
196
  expect(transaction).to include_params("internal" => "true")
197
+ expect(transaction).to_not have_queue_start
198
+ expect(transaction).to be_completed
224
199
  end
225
200
  end
226
201
 
227
202
  if DependencyHelper.rails6_present?
228
203
  context "with ConnectionStub" do
229
204
  let(:connection) { ActionCable::Channel::ConnectionStub.new }
230
- let(:transaction_id) { "Stubbed transaction id" }
231
- before do
232
- # Stub future (private AppSignal) transaction id generated by the hook.
233
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
234
- end
235
205
 
236
206
  it "does not fail on missing `#env` method on `ConnectionStub`" do
237
207
  instance.subscribe_to_channel
238
208
 
239
209
  transaction = last_transaction
240
- expect(transaction).to have_id(transaction_id)
210
+ expect(transaction).to have_id
241
211
  expect(transaction).to have_action("MyChannel#subscribed")
242
212
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
243
213
  expect(transaction).to_not have_error
@@ -245,7 +215,7 @@ describe Appsignal::Hooks::ActionCableHook do
245
215
  "method" => "websocket",
246
216
  "path" => "" # No path as the ConnectionStub doesn't have the real request env
247
217
  )
248
- expect(transaction).to include_params("internal" => "true")
218
+ expect(transaction).to_not include_params
249
219
  expect(transaction).to include_event(
250
220
  "body" => "",
251
221
  "body_format" => Appsignal::EventFormatter::DEFAULT,
@@ -253,6 +223,8 @@ describe Appsignal::Hooks::ActionCableHook do
253
223
  "name" => "subscribed.action_cable",
254
224
  "title" => ""
255
225
  )
226
+ expect(transaction).to_not have_queue_start
227
+ expect(transaction).to be_completed
256
228
  end
257
229
  end
258
230
  end
@@ -265,7 +237,7 @@ describe Appsignal::Hooks::ActionCableHook do
265
237
  instance.unsubscribe_from_channel
266
238
 
267
239
  transaction = last_transaction
268
- expect(transaction).to have_id(transaction_id)
240
+ expect(transaction).to have_id
269
241
  expect(transaction).to have_action("MyChannel#unsubscribed")
270
242
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
271
243
  expect(transaction).to_not have_error
@@ -281,18 +253,16 @@ describe Appsignal::Hooks::ActionCableHook do
281
253
  "name" => "unsubscribed.action_cable",
282
254
  "title" => ""
283
255
  )
256
+ expect(transaction).to_not have_queue_start
257
+ expect(transaction).to be_completed
284
258
  end
285
259
 
286
260
  context "without request_id (standalone server)" do
287
261
  let(:request_id) { nil }
288
- let(:transaction_id) { SecureRandom.uuid }
289
- before do
290
- allow(SecureRandom).to receive(:uuid).and_return(transaction_id)
291
- instance.unsubscribe_from_channel
292
- end
262
+ before { instance.unsubscribe_from_channel }
293
263
 
294
- it "uses its own internal request_id" do
295
- expect(transaction).to have_id(transaction_id)
264
+ it "sets a generated request ID" do
265
+ expect(last_transaction).to include_tags("request_id" => kind_of(String))
296
266
  end
297
267
  end
298
268
 
@@ -315,7 +285,7 @@ describe Appsignal::Hooks::ActionCableHook do
315
285
  end.to raise_error(ExampleException)
316
286
 
317
287
  transaction = last_transaction
318
- expect(transaction).to have_id(transaction_id)
288
+ expect(transaction).to have_id
319
289
  expect(transaction).to have_action("MyChannel#unsubscribed")
320
290
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
321
291
  expect(transaction).to have_error("ExampleException", "oh no!")
@@ -324,23 +294,20 @@ describe Appsignal::Hooks::ActionCableHook do
324
294
  "path" => "/blog"
325
295
  )
326
296
  expect(transaction).to include_params("internal" => "true")
297
+ expect(transaction).to_not have_queue_start
298
+ expect(transaction).to be_completed
327
299
  end
328
300
  end
329
301
 
330
302
  if DependencyHelper.rails6_present?
331
303
  context "with ConnectionStub" do
332
304
  let(:connection) { ActionCable::Channel::ConnectionStub.new }
333
- let(:transaction_id) { "Stubbed transaction id" }
334
- before do
335
- # Stub future (private AppSignal) transaction id generated by the hook.
336
- expect(SecureRandom).to receive(:uuid).and_return(transaction_id)
337
- end
338
305
 
339
306
  it "does not fail on missing `#env` method on `ConnectionStub`" do
340
307
  instance.unsubscribe_from_channel
341
308
 
342
309
  transaction = last_transaction
343
- expect(transaction).to have_id(transaction_id)
310
+ expect(transaction).to have_id
344
311
  expect(transaction).to have_action("MyChannel#unsubscribed")
345
312
  expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
346
313
  expect(transaction).to_not have_error
@@ -348,7 +315,7 @@ describe Appsignal::Hooks::ActionCableHook do
348
315
  "method" => "websocket",
349
316
  "path" => "" # No path as the ConnectionStub doesn't have the real request env
350
317
  )
351
- expect(transaction).to include_params("internal" => "true")
318
+ expect(transaction).to_not include_params
352
319
  expect(transaction).to include_event(
353
320
  "body" => "",
354
321
  "body_format" => Appsignal::EventFormatter::DEFAULT,
@@ -356,6 +323,8 @@ describe Appsignal::Hooks::ActionCableHook do
356
323
  "name" => "unsubscribed.action_cable",
357
324
  "title" => ""
358
325
  )
326
+ expect(transaction).to_not have_queue_start
327
+ expect(transaction).to be_completed
359
328
  end
360
329
  end
361
330
  end