appsignal 3.10.0-java → 3.12.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +197 -0
  4. data/Gemfile +1 -0
  5. data/Rakefile +1 -1
  6. data/benchmark.rake +99 -42
  7. data/lib/appsignal/cli/demo.rb +0 -1
  8. data/lib/appsignal/cli/diagnose.rb +1 -1
  9. data/lib/appsignal/config.rb +204 -130
  10. data/lib/appsignal/demo.rb +16 -26
  11. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  12. data/lib/appsignal/event_formatter.rb +3 -2
  13. data/lib/appsignal/helpers/instrumentation.rb +331 -19
  14. data/lib/appsignal/hooks/action_cable.rb +21 -16
  15. data/lib/appsignal/hooks/active_job.rb +14 -8
  16. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  17. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  18. data/lib/appsignal/integrations/action_cable.rb +5 -7
  19. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  20. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  21. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  22. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  23. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  24. data/lib/appsignal/integrations/excon.rb +1 -0
  25. data/lib/appsignal/integrations/grape.rb +7 -0
  26. data/lib/appsignal/integrations/hanami.rb +8 -43
  27. data/lib/appsignal/integrations/http.rb +1 -0
  28. data/lib/appsignal/integrations/net_http.rb +1 -0
  29. data/lib/appsignal/integrations/object.rb +6 -0
  30. data/lib/appsignal/integrations/padrino.rb +8 -73
  31. data/lib/appsignal/integrations/que.rb +13 -20
  32. data/lib/appsignal/integrations/railtie.rb +36 -14
  33. data/lib/appsignal/integrations/rake.rb +1 -5
  34. data/lib/appsignal/integrations/redis.rb +1 -0
  35. data/lib/appsignal/integrations/redis_client.rb +1 -0
  36. data/lib/appsignal/integrations/resque.rb +2 -5
  37. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  38. data/lib/appsignal/integrations/sidekiq.rb +7 -15
  39. data/lib/appsignal/integrations/sinatra.rb +8 -19
  40. data/lib/appsignal/integrations/unicorn.rb +1 -0
  41. data/lib/appsignal/integrations/webmachine.rb +2 -5
  42. data/lib/appsignal/loaders/grape.rb +13 -0
  43. data/lib/appsignal/loaders/hanami.rb +40 -0
  44. data/lib/appsignal/loaders/padrino.rb +68 -0
  45. data/lib/appsignal/loaders/sinatra.rb +24 -0
  46. data/lib/appsignal/loaders.rb +92 -0
  47. data/lib/appsignal/logger.rb +7 -3
  48. data/lib/appsignal/probes/helpers.rb +1 -0
  49. data/lib/appsignal/probes/mri.rb +1 -0
  50. data/lib/appsignal/probes/sidekiq.rb +1 -0
  51. data/lib/appsignal/probes.rb +3 -0
  52. data/lib/appsignal/rack/abstract_middleware.rb +20 -13
  53. data/lib/appsignal/rack/event_handler.rb +44 -13
  54. data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
  55. data/lib/appsignal/rack/grape_middleware.rb +2 -1
  56. data/lib/appsignal/rack/streaming_listener.rb +1 -0
  57. data/lib/appsignal/rack.rb +35 -0
  58. data/lib/appsignal/span.rb +1 -0
  59. data/lib/appsignal/transaction.rb +308 -101
  60. data/lib/appsignal/utils/data.rb +0 -1
  61. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  62. data/lib/appsignal/utils/integration_logger.rb +0 -13
  63. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  64. data/lib/appsignal/utils/json.rb +0 -1
  65. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  66. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  67. data/lib/appsignal/utils.rb +6 -0
  68. data/lib/appsignal/version.rb +1 -1
  69. data/lib/appsignal.rb +169 -14
  70. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  71. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  72. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  73. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  74. data/spec/lib/appsignal/config_spec.rb +291 -44
  75. data/spec/lib/appsignal/demo_spec.rb +1 -2
  76. data/spec/lib/appsignal/environment_spec.rb +4 -2
  77. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  78. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  79. data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
  80. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  81. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  82. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  83. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  84. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  85. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  86. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  87. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  88. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  89. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  90. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  91. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  92. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  93. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  94. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  95. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  96. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  97. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  98. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  99. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  100. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  101. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  102. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  103. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  104. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
  105. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  106. data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
  107. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  108. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  109. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  110. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  111. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  112. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  113. data/spec/lib/appsignal/probes_spec.rb +6 -5
  114. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
  115. data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
  116. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  117. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  118. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  119. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  120. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  121. data/spec/lib/appsignal/rack_spec.rb +63 -0
  122. data/spec/lib/appsignal/span_spec.rb +1 -3
  123. data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
  124. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  125. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  126. data/spec/lib/appsignal_spec.rb +601 -36
  127. data/spec/lib/puma/appsignal_spec.rb +0 -3
  128. data/spec/spec_helper.rb +5 -4
  129. data/spec/support/helpers/config_helpers.rb +2 -1
  130. data/spec/support/helpers/loader_helper.rb +21 -0
  131. data/spec/support/helpers/transaction_helpers.rb +44 -20
  132. data/spec/support/matchers/transaction.rb +15 -1
  133. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  134. data/spec/support/testing.rb +47 -1
  135. metadata +19 -2
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Integrations
5
+ # @api private
6
+ class ShoryukenMiddleware
7
+ def call(worker_instance, queue, sqs_msg, body, &block)
8
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
9
+
10
+ Appsignal.instrument("perform_job.shoryuken", &block)
11
+ rescue Exception => error # rubocop:disable Lint/RescueException
12
+ transaction.set_error(error)
13
+ raise
14
+ ensure
15
+ batch = sqs_msg.is_a?(Array)
16
+ attributes = fetch_attributes(batch, sqs_msg)
17
+ transaction.set_action_if_nil("#{worker_instance.class.name}#perform")
18
+ transaction.set_params_if_nil { fetch_args(batch, sqs_msg, body) }
19
+ transaction.set_tags(attributes)
20
+ transaction.set_tags("queue" => queue)
21
+ transaction.set_tags("batch" => true) if batch
22
+
23
+ if attributes.key?("SentTimestamp")
24
+ transaction.set_queue_start(Time.at(attributes["SentTimestamp"].to_i).to_i)
25
+ end
26
+
27
+ Appsignal::Transaction.complete_current!
28
+ end
29
+
30
+ private
31
+
32
+ def fetch_attributes(batch, sqs_msg)
33
+ if batch
34
+ # We can't instrument batched message separately, the `yield` will
35
+ # perform all the batched messages.
36
+ # To provide somewhat useful metadata, Get first message based on
37
+ # SentTimestamp, and use its attributes as metadata for the
38
+ # transaction. We can't combine them all because then they would
39
+ # overwrite each other and the last message (in an sorted order)
40
+ # would be used as the source of the metadata. With the
41
+ # oldest/first message at least some useful information is stored
42
+ # such as the first received time and the number of retries for the
43
+ # first message. The newer message should have lower values and
44
+ # timestamps in their metadata.
45
+ first_msg =
46
+ sqs_msg.min do |a, b|
47
+ a.attributes["SentTimestamp"].to_i <=> b.attributes["SentTimestamp"].to_i
48
+ end
49
+ first_msg.attributes
50
+ else
51
+ sqs_msg.attributes.merge(:message_id => sqs_msg.message_id)
52
+ end
53
+ end
54
+
55
+ def fetch_args(batch, sqs_msg, body)
56
+ if batch
57
+ bodies = {}
58
+ sqs_msg.each_with_index do |msg, index|
59
+ # Store all separate bodies on a hash with the key being the
60
+ # message_id
61
+ bodies[msg.message_id] = body[index]
62
+ end
63
+ bodies
64
+ else
65
+ case body
66
+ when Hash
67
+ body
68
+ else
69
+ { :params => body }
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -11,6 +11,7 @@ module Appsignal
11
11
  # about completing the transaction.
12
12
  #
13
13
  # Introduced in Sidekiq 5.1.
14
+ # @api private
14
15
  class SidekiqDeathHandler
15
16
  def call(_job_context, exception)
16
17
  return unless Appsignal.config[:sidekiq_report_errors] == "discard"
@@ -37,12 +38,7 @@ module Appsignal
37
38
  # Sidekiq error outside of the middleware scope.
38
39
  # Can be a job JSON parse error or some other error happening in
39
40
  # Sidekiq.
40
- transaction =
41
- Appsignal::Transaction.create(
42
- SecureRandom.uuid, # Newly generated job id
43
- Appsignal::Transaction::BACKGROUND_JOB,
44
- Appsignal::Transaction::GenericRequest.new({})
45
- )
41
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
46
42
  transaction.set_action_if_nil("SidekiqInternal")
47
43
  transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
48
44
  transaction.set_params_if_nil(:jobstr => sidekiq_context[:jobstr])
@@ -64,13 +60,7 @@ module Appsignal
64
60
 
65
61
  def call(_worker, item, _queue, &block)
66
62
  job_status = nil
67
- transaction = Appsignal::Transaction.create(
68
- item["jid"],
69
- Appsignal::Transaction::BACKGROUND_JOB,
70
- Appsignal::Transaction::GenericRequest.new(
71
- :queue_start => item["enqueued_at"]
72
- )
73
- )
63
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
74
64
  transaction.set_action_if_nil(formatted_action_name(item))
75
65
 
76
66
  formatted_metadata(item).each do |key, value|
@@ -83,8 +73,10 @@ module Appsignal
83
73
  raise exception
84
74
  ensure
85
75
  if transaction
86
- transaction.set_params_if_nil(parse_arguments(item))
87
- transaction.set_http_or_background_queue_start
76
+ transaction.set_params_if_nil { parse_arguments(item) }
77
+ queue_start = (item["enqueued_at"].to_f * 1000.0).to_i # Convert seconds to milliseconds
78
+ transaction.set_queue_start(queue_start)
79
+ transaction.set_tags(:request_id => item["jid"])
88
80
  Appsignal::Transaction.complete_current! unless exception
89
81
 
90
82
  queue = item["queue"] || "unknown"
@@ -1,24 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
- require "appsignal/rack/sinatra_instrumentation"
5
4
 
6
- Appsignal.internal_logger.debug("Loading Sinatra (#{Sinatra::VERSION}) integration")
5
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
6
+ "The 'require \"appsignal/integrations/sinatra\"' file require integration " \
7
+ "method is deprecated. " \
8
+ "Please follow the Sinatra setup guide in our docs for the new method: " \
9
+ "https://docs.appsignal.com/ruby/integrations/sinatra.html"
10
+ )
7
11
 
8
- unless Appsignal.active?
9
- app_settings = ::Sinatra::Application.settings
10
- Appsignal.config = Appsignal::Config.new(
11
- app_settings.root || Dir.pwd,
12
- app_settings.environment
13
- )
14
-
15
- Appsignal.start
16
- end
17
-
18
- if Appsignal.active?
19
- ::Sinatra::Base.use(
20
- ::Rack::Events,
21
- [Appsignal::Rack::EventHandler.new]
22
- )
23
- ::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation)
24
- end
12
+ Appsignal.load(:sinatra)
13
+ Appsignal.start
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module UnicornIntegration
6
7
  # Make sure that appsignal is started and the last transaction
7
8
  # in a worker gets flushed.
@@ -10,11 +10,7 @@ module Appsignal
10
10
  if has_parent_transaction
11
11
  Appsignal::Transaction.current
12
12
  else
13
- Appsignal::Transaction.create(
14
- SecureRandom.uuid,
15
- Appsignal::Transaction::HTTP_REQUEST,
16
- request
17
- )
13
+ Appsignal::Transaction.create(Appsignal::Transaction::HTTP_REQUEST)
18
14
  end
19
15
 
20
16
  Appsignal.instrument("process_action.webmachine") do
@@ -23,6 +19,7 @@ module Appsignal
23
19
  ensure
24
20
  transaction.set_action_if_nil("#{resource.class.name}##{request.method}")
25
21
  transaction.set_params_if_nil(request.query)
22
+ transaction.set_headers_if_nil { request.headers if request.respond_to?(:headers) }
26
23
 
27
24
  Appsignal::Transaction.complete_current! unless has_parent_transaction
28
25
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Loaders
5
+ class GrapeLoader < Loader
6
+ register :grape
7
+
8
+ def on_load
9
+ require "appsignal/rack/grape_middleware"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Loaders
5
+ class HanamiLoader < Loader
6
+ register :hanami
7
+
8
+ def on_load
9
+ hanami_app_config = ::Hanami.app.config
10
+ register_config_defaults(
11
+ :root_path => hanami_app_config.root.to_s,
12
+ :env => hanami_app_config.env
13
+ )
14
+ end
15
+
16
+ def on_start
17
+ require "appsignal/rack/hanami_middleware"
18
+
19
+ hanami_app_config = ::Hanami.app.config
20
+ hanami_app_config.middleware.use(
21
+ ::Rack::Events,
22
+ [Appsignal::Rack::EventHandler.new]
23
+ )
24
+ hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
25
+
26
+ ::Hanami::Action.prepend Appsignal::Loaders::HanamiLoader::HanamiIntegration
27
+ end
28
+
29
+ module HanamiIntegration
30
+ def call(env)
31
+ super
32
+ ensure
33
+ transaction = env[::Appsignal::Rack::APPSIGNAL_TRANSACTION]
34
+
35
+ transaction&.set_action_if_nil(self.class.name)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Loaders
5
+ class PadrinoLoader < Loader
6
+ register :padrino
7
+
8
+ def on_load
9
+ register_config_defaults(
10
+ :root_path => Padrino.mounted_root,
11
+ :env => Padrino.env
12
+ )
13
+ end
14
+
15
+ def on_start
16
+ require "appsignal/rack/sinatra_instrumentation"
17
+
18
+ Padrino::Application.prepend(Appsignal::Loaders::PadrinoLoader::PadrinoIntegration)
19
+
20
+ Padrino.before_load do
21
+ Padrino.use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
22
+ Padrino.use Appsignal::Rack::SinatraBaseInstrumentation,
23
+ :instrument_event_name => "process_action.padrino"
24
+ end
25
+ end
26
+
27
+ module PadrinoIntegration
28
+ def route!(base = settings, pass_block = nil)
29
+ return super if !Appsignal.active? || env["sinatra.static_file"]
30
+
31
+ begin
32
+ super
33
+ ensure
34
+ transaction = Appsignal::Transaction.current
35
+ transaction.set_action_if_nil(get_payload_action(request))
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def get_payload_action(request)
42
+ # Short-circuit is there's no request object to obtain information from
43
+ return settings.name.to_s unless request
44
+
45
+ # Newer versions expose the action / controller on the request class.
46
+ # Newer versions also still expose a route_obj so we must prioritize the
47
+ # action/fullpath methods.
48
+ # The `request.action` and `request.controller` values are `nil` when a
49
+ # endpoint is not found, `""` if not specified by the user.
50
+ controller_name = request.controller if request.respond_to?(:controller)
51
+ action_name = request.action if request.respond_to?(:action)
52
+ action_name ||= ""
53
+
54
+ return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
55
+
56
+ # Older versions of Padrino work with a route object
57
+ if request.respond_to?(:route_obj) && request.route_obj
58
+ return "#{settings.name}:#{request.route_obj.original_path}"
59
+ end
60
+
61
+ # Fall back to the application name if we haven't found an action name in
62
+ # any previous methods.
63
+ "#{settings.name}#unknown"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Loaders
5
+ class SinatraLoader < Loader
6
+ register :sinatra
7
+
8
+ def on_load
9
+ app_settings = ::Sinatra::Application.settings
10
+ register_config_defaults(
11
+ :root_path => app_settings.root,
12
+ :env => app_settings.environment
13
+ )
14
+ end
15
+
16
+ def on_start
17
+ require "appsignal/rack/sinatra_instrumentation"
18
+
19
+ ::Sinatra::Base.use(::Rack::Events, [Appsignal::Rack::EventHandler.new])
20
+ ::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ # @api private
5
+ module Loaders
6
+ class << self
7
+ def loaders
8
+ @loaders ||= {}
9
+ end
10
+
11
+ def instances
12
+ @instances ||= {}
13
+ end
14
+
15
+ def register(name, klass)
16
+ loaders[name.to_sym] = klass
17
+ end
18
+
19
+ def registered?(name)
20
+ loaders.key?(name)
21
+ end
22
+
23
+ def unregister(name)
24
+ loaders.delete(name)
25
+ end
26
+
27
+ def load(name_str)
28
+ name = name_str.to_sym
29
+
30
+ unless registered?(name)
31
+ require_loader(name)
32
+ unless registered?(name)
33
+ Appsignal.internal_logger
34
+ .warn("No loader found with the name '#{name}'.")
35
+ return
36
+ end
37
+ end
38
+
39
+ Appsignal.internal_logger.debug("Loading '#{name}' loader")
40
+
41
+ begin
42
+ loader_klass = loaders[name]
43
+ loader = loader_klass.new
44
+ instances[name] = loader
45
+ loader.on_load if loader.respond_to?(:on_load)
46
+ rescue => e
47
+ Appsignal.internal_logger.error(
48
+ "An error occurred while loading the '#{name}' loader: " \
49
+ "#{e.class}: #{e.message}\n#{e.backtrace}"
50
+ )
51
+ end
52
+ end
53
+
54
+ def start
55
+ instances.each do |name, instance|
56
+ Appsignal.internal_logger.debug("Starting '#{name}' loader")
57
+ begin
58
+ instance.on_start if instance.respond_to?(:on_start)
59
+ rescue => e
60
+ Appsignal.internal_logger.error(
61
+ "An error occurred while starting the '#{name}' loader: " \
62
+ "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
63
+ )
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def require_loader(name)
71
+ require "appsignal/loaders/#{name}"
72
+ rescue LoadError
73
+ nil
74
+ end
75
+ end
76
+
77
+ class Loader
78
+ class << self
79
+ attr_reader :loader_name
80
+
81
+ def register(name)
82
+ @loader_name = name
83
+ Loaders.register(name, self)
84
+ end
85
+ end
86
+
87
+ def register_config_defaults(options)
88
+ Appsignal::Config.add_loader_defaults(self.class.loader_name, options)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -4,7 +4,10 @@ require "logger"
4
4
  require "set"
5
5
 
6
6
  module Appsignal
7
- # Logger that flushes logs to the AppSignal logging service
7
+ # Logger that flushes logs to the AppSignal logging service.
8
+ #
9
+ # @see https://docs.appsignal.com/logging/platforms/integrations/ruby.html
10
+ # AppSignal Ruby logging documentation.
8
11
  class Logger < ::Logger
9
12
  PLAINTEXT = 0
10
13
  LOGFMT = 1
@@ -144,8 +147,9 @@ module Appsignal
144
147
  # as our logger directly inherits from Ruby base logger.
145
148
  #
146
149
  # Links:
147
- # https://github.com/rails/rails/blob/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/activesupport/lib/active_support/logger.rb#L60-L76
148
- # https://github.com/rails/rails/blob/main/activesupport/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/active_support/logger_silence.rb
150
+ #
151
+ # - https://github.com/rails/rails/blob/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/activesupport/lib/active_support/logger.rb#L60-L76
152
+ # - https://github.com/rails/rails/blob/main/activesupport/e11ebc04cfbe41c06cdfb70ee5a9fdbbd98bb263/active_support/logger_silence.rb
149
153
  def silence(_severity = ERROR, &block)
150
154
  block.call
151
155
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Probes
5
+ # @api private
5
6
  module Helpers
6
7
  private
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Probes
5
+ # @api private
5
6
  class MriProbe
6
7
  include Helpers
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Probes
5
+ # @api private
5
6
  class SidekiqProbe
6
7
  include Helpers
7
8
 
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Appsignal
4
4
  module Probes
5
+ # @api private
5
6
  ITERATION_IN_SECONDS = 60
6
7
 
8
+ # @api private
7
9
  class ProbeCollection
8
10
  def initialize
9
11
  @probes = {}
@@ -72,6 +74,7 @@ module Appsignal
72
74
 
73
75
  # @see ProbeCollection
74
76
  # @return [ProbeCollection] Returns list of probes.
77
+ # @api private
75
78
  def probes
76
79
  @probes ||= ProbeCollection.new
77
80
  end
@@ -9,6 +9,7 @@ module Appsignal
9
9
  # Do not use this middleware directly. Instead use
10
10
  # {InstrumentationMiddleware}.
11
11
  #
12
+ # @abstract
12
13
  # @api private
13
14
  class AbstractMiddleware
14
15
  DEFAULT_ERROR_REPORTING = :default
@@ -33,11 +34,7 @@ module Appsignal
33
34
  if wrapped_instrumentation
34
35
  env[Appsignal::Rack::APPSIGNAL_TRANSACTION]
35
36
  else
36
- Appsignal::Transaction.create(
37
- SecureRandom.uuid,
38
- Appsignal::Transaction::HTTP_REQUEST,
39
- request
40
- )
37
+ Appsignal::Transaction.create(Appsignal::Transaction::HTTP_REQUEST)
41
38
  end
42
39
 
43
40
  unless wrapped_instrumentation
@@ -80,7 +77,7 @@ module Appsignal
80
77
  # Either another {AbstractMiddleware} or {EventHandler} is higher in the
81
78
  # stack and will report the exception and complete the transaction.
82
79
  #
83
- # @see {#instrument_app_call_with_exception_handling}
80
+ # @see #instrument_app_call_with_exception_handling
84
81
  def instrument_app_call(env, transaction)
85
82
  if @instrument_event_name
86
83
  Appsignal.instrument(@instrument_event_name) do
@@ -94,9 +91,10 @@ module Appsignal
94
91
  def call_app(env, transaction)
95
92
  status, headers, obody = @app.call(env)
96
93
  body =
97
- if obody.is_a? Appsignal::Rack::BodyWrapper
94
+ if env[Appsignal::Rack::APPSIGNAL_RESPONSE_INSTRUMENTED]
98
95
  obody
99
96
  else
97
+ env[Appsignal::Rack::APPSIGNAL_RESPONSE_INSTRUMENTED] = true
100
98
  # Instrument response body and closing of the response body
101
99
  Appsignal::Rack::BodyWrapper.wrap(obody, transaction)
102
100
  end
@@ -108,7 +106,7 @@ module Appsignal
108
106
  # {#instrument_app_call} this will report any exceptions being
109
107
  # raised.
110
108
  #
111
- # @see {#instrument_app_call}
109
+ # @see #instrument_app_call
112
110
  def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
113
111
  instrument_app_call(env, transaction)
114
112
  rescue Exception => error # rubocop:disable Lint/RescueException
@@ -147,7 +145,14 @@ module Appsignal
147
145
  transaction.set_metadata("method", request_method) if request_method
148
146
 
149
147
  transaction.set_params_if_nil { params_for(request) }
150
- transaction.set_http_or_background_queue_start
148
+ transaction.set_session_data_if_nil do
149
+ request.session if request.respond_to?(:session)
150
+ end
151
+ transaction.set_headers_if_nil do
152
+ request.env if request.respond_to?(:env)
153
+ end
154
+ queue_start = Appsignal::Rack::Utils.queue_start_from(request.env)
155
+ transaction.set_queue_start(queue_start) if queue_start
151
156
  end
152
157
 
153
158
  def params_for(request)
@@ -155,9 +160,9 @@ module Appsignal
155
160
 
156
161
  request.send(@params_method)
157
162
  rescue => error
158
- # Getting params from the request has been know to fail.
159
- Appsignal.internal_logger.debug(
160
- "Exception while getting params in #{self.class} from '#{@params_method}': #{error}"
163
+ Appsignal.internal_logger.error(
164
+ "Exception while fetching params from '#{@request_class}##{@params_method}': " \
165
+ "#{error.class} #{error}"
161
166
  )
162
167
  nil
163
168
  end
@@ -165,7 +170,9 @@ module Appsignal
165
170
  def request_method_for(request)
166
171
  request.request_method
167
172
  rescue => error
168
- Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
173
+ Appsignal.internal_logger.error(
174
+ "Exception while fetching the HTTP request method: #{error.class}: #{error}"
175
+ )
169
176
  nil
170
177
  end
171
178