appsignal 3.10.0-java → 3.11.0-java

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