appsignal 3.9.3-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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +22 -19
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +180 -0
  5. data/Gemfile +1 -0
  6. data/README.md +0 -1
  7. data/Rakefile +1 -1
  8. data/benchmark.rake +99 -42
  9. data/build_matrix.yml +10 -12
  10. data/gemfiles/webmachine1.gemfile +5 -4
  11. data/lib/appsignal/cli/demo.rb +0 -1
  12. data/lib/appsignal/config.rb +57 -97
  13. data/lib/appsignal/demo.rb +15 -20
  14. data/lib/appsignal/environment.rb +6 -1
  15. data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
  16. data/lib/appsignal/event_formatter.rb +3 -2
  17. data/lib/appsignal/helpers/instrumentation.rb +490 -16
  18. data/lib/appsignal/hooks/action_cable.rb +21 -16
  19. data/lib/appsignal/hooks/active_job.rb +15 -14
  20. data/lib/appsignal/hooks/delayed_job.rb +1 -1
  21. data/lib/appsignal/hooks/shoryuken.rb +3 -63
  22. data/lib/appsignal/integrations/action_cable.rb +5 -7
  23. data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
  24. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
  25. data/lib/appsignal/integrations/data_mapper.rb +1 -0
  26. data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
  27. data/lib/appsignal/integrations/dry_monitor.rb +1 -0
  28. data/lib/appsignal/integrations/excon.rb +1 -0
  29. data/lib/appsignal/integrations/http.rb +1 -0
  30. data/lib/appsignal/integrations/net_http.rb +1 -0
  31. data/lib/appsignal/integrations/object.rb +6 -0
  32. data/lib/appsignal/integrations/padrino.rb +21 -25
  33. data/lib/appsignal/integrations/que.rb +13 -20
  34. data/lib/appsignal/integrations/railtie.rb +1 -1
  35. data/lib/appsignal/integrations/rake.rb +45 -15
  36. data/lib/appsignal/integrations/redis.rb +1 -0
  37. data/lib/appsignal/integrations/redis_client.rb +1 -0
  38. data/lib/appsignal/integrations/resque.rb +2 -5
  39. data/lib/appsignal/integrations/shoryuken.rb +75 -0
  40. data/lib/appsignal/integrations/sidekiq.rb +7 -25
  41. data/lib/appsignal/integrations/unicorn.rb +1 -0
  42. data/lib/appsignal/integrations/webmachine.rb +12 -9
  43. data/lib/appsignal/logger.rb +7 -3
  44. data/lib/appsignal/probes/helpers.rb +1 -0
  45. data/lib/appsignal/probes/mri.rb +1 -0
  46. data/lib/appsignal/probes/sidekiq.rb +1 -0
  47. data/lib/appsignal/probes.rb +3 -0
  48. data/lib/appsignal/rack/abstract_middleware.rb +67 -24
  49. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  50. data/lib/appsignal/rack/event_handler.rb +39 -8
  51. data/lib/appsignal/rack/generic_instrumentation.rb +6 -4
  52. data/lib/appsignal/rack/grape_middleware.rb +3 -2
  53. data/lib/appsignal/rack/hanami_middleware.rb +1 -1
  54. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  55. data/lib/appsignal/rack/rails_instrumentation.rb +1 -3
  56. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  57. data/lib/appsignal/rack/streaming_listener.rb +14 -59
  58. data/lib/appsignal/rack.rb +60 -0
  59. data/lib/appsignal/span.rb +1 -0
  60. data/lib/appsignal/transaction.rb +353 -104
  61. data/lib/appsignal/utils/data.rb +0 -1
  62. data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
  63. data/lib/appsignal/utils/integration_logger.rb +0 -13
  64. data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
  65. data/lib/appsignal/utils/json.rb +0 -1
  66. data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
  67. data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
  68. data/lib/appsignal/utils.rb +6 -0
  69. data/lib/appsignal/version.rb +1 -1
  70. data/lib/appsignal.rb +9 -6
  71. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  72. data/spec/lib/appsignal/config_spec.rb +139 -43
  73. data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
  74. data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
  75. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
  76. data/spec/lib/appsignal/hooks/rake_spec.rb +100 -17
  77. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
  78. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
  79. data/spec/lib/appsignal/integrations/padrino_spec.rb +181 -131
  80. data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
  81. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
  82. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
  83. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -2
  84. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -17
  85. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +144 -11
  86. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  87. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
  88. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -17
  89. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +1 -1
  90. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  91. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
  92. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +43 -120
  93. data/spec/lib/appsignal/rack_spec.rb +63 -0
  94. data/spec/lib/appsignal/transaction_spec.rb +1675 -953
  95. data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
  96. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
  97. data/spec/lib/appsignal_spec.rb +517 -13
  98. data/spec/support/helpers/transaction_helpers.rb +44 -20
  99. data/spec/support/matchers/transaction.rb +15 -1
  100. data/spec/support/mocks/dummy_app.rb +1 -1
  101. data/spec/support/testing.rb +1 -1
  102. metadata +12 -4
  103. data/support/check_versions +0 -22
@@ -54,25 +54,13 @@ module Appsignal
54
54
  # we do for Sidekiq.
55
55
  #
56
56
  # Prefer job_id from provider, instead of ActiveJob's internal ID.
57
- Appsignal::Transaction.create(
58
- job["provider_job_id"] || job["job_id"],
59
- Appsignal::Transaction::BACKGROUND_JOB,
60
- Appsignal::Transaction::GenericRequest.new({})
61
- )
57
+ Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
62
58
  end
63
59
 
64
60
  if transaction
65
- transaction.set_params_if_nil(
66
- Appsignal::Utils::HashSanitizer.sanitize(
67
- job["arguments"],
68
- Appsignal.config[:filter_parameters]
69
- )
70
- )
61
+ transaction.set_params_if_nil(job["arguments"])
71
62
 
72
63
  transaction_tags = ActiveJobHelpers.transaction_tags_for(job)
73
- transaction_tags["active_job_id"] = job["job_id"]
74
- provider_job_id = job["provider_job_id"]
75
- transaction_tags[:provider_job_id] = provider_job_id if provider_job_id
76
64
  transaction.set_tags(transaction_tags)
77
65
 
78
66
  transaction.set_action(ActiveJobHelpers.action_name(job))
@@ -159,12 +147,25 @@ module Appsignal
159
147
 
160
148
  def self.transaction_tags_for(job)
161
149
  tags = {}
150
+
162
151
  queue = job["queue_name"]
163
152
  tags[:queue] = queue if queue
153
+
164
154
  priority = job["priority"]
165
155
  tags[:priority] = priority if priority
156
+
166
157
  executions = job["executions"]
167
158
  tags[:executions] = executions.to_i + 1 if executions
159
+
160
+ job_id = job["job_id"]
161
+ tags[:active_job_id] = job_id
162
+
163
+ provider_job_id = job["provider_job_id"]
164
+ tags[:provider_job_id] = provider_job_id if provider_job_id
165
+
166
+ request_id = provider_job_id || job_id
167
+ tags[:request_id] = request_id if request_id
168
+
168
169
  tags
169
170
  end
170
171
 
@@ -14,7 +14,7 @@ module Appsignal
14
14
  # The DJ plugin is a subclass of Delayed::Plugin, so we can only
15
15
  # require this code if we're actually installing.
16
16
  require "appsignal/integrations/delayed_job_plugin"
17
- ::Delayed::Worker.plugins << Appsignal::Hooks::DelayedJobPlugin
17
+ ::Delayed::Worker.plugins << Appsignal::Integrations::DelayedJobPlugin
18
18
  end
19
19
  end
20
20
  end
@@ -3,68 +3,6 @@
3
3
  module Appsignal
4
4
  class Hooks
5
5
  # @api private
6
- class ShoryukenMiddleware
7
- def call(worker_instance, queue, sqs_msg, body, &block)
8
- batch = sqs_msg.is_a?(Array)
9
- attributes =
10
- if batch
11
- # We can't instrument batched message separately, the `yield` will
12
- # perform all the batched messages.
13
- # To provide somewhat useful metadata, Get first message based on
14
- # SentTimestamp, and use its attributes as metadata for the
15
- # transaction. We can't combine them all because then they would
16
- # overwrite each other and the last message (in an sorted order)
17
- # would be used as the source of the metadata. With the
18
- # oldest/first message at least some useful information is stored
19
- # such as the first received time and the number of retries for the
20
- # first message. The newer message should have lower values and
21
- # timestamps in their metadata.
22
- first_msg = sqs_msg.min do |a, b|
23
- a.attributes["SentTimestamp"].to_i <=> b.attributes["SentTimestamp"].to_i
24
- end
25
- # Add batch => true metadata so people can recognize when a
26
- # transaction is about a batch of messages.
27
- first_msg.attributes.merge(:batch => true)
28
- else
29
- sqs_msg.attributes.merge(:message_id => sqs_msg.message_id)
30
- end
31
- metadata = { :queue => queue }.merge(attributes)
32
- options = {
33
- :class => worker_instance.class.name,
34
- :method => "perform",
35
- :metadata => metadata
36
- }
37
-
38
- args =
39
- if batch
40
- bodies = {}
41
- sqs_msg.each_with_index do |msg, index|
42
- # Store all separate bodies on a hash with the key being the
43
- # message_id
44
- bodies[msg.message_id] = body[index]
45
- end
46
- bodies
47
- else
48
- case body
49
- when Hash
50
- body
51
- else
52
- { :params => body }
53
- end
54
- end
55
- options[:params] = Appsignal::Utils::HashSanitizer.sanitize(
56
- args,
57
- Appsignal.config[:filter_parameters]
58
- )
59
-
60
- if attributes.key?("SentTimestamp")
61
- options[:queue_start] = Time.at(attributes["SentTimestamp"].to_i / 1000)
62
- end
63
-
64
- Appsignal.monitor_transaction("perform_job.shoryuken", options, &block)
65
- end
66
- end
67
-
68
6
  class ShoryukenHook < Appsignal::Hooks::Hook
69
7
  register :shoryuken
70
8
 
@@ -73,9 +11,11 @@ module Appsignal
73
11
  end
74
12
 
75
13
  def install
14
+ require "appsignal/integrations/shoryuken"
15
+
76
16
  ::Shoryuken.configure_server do |config|
77
17
  config.server_middleware do |chain|
78
- chain.add Appsignal::Hooks::ShoryukenMiddleware
18
+ chain.add Appsignal::Integrations::ShoryukenMiddleware
79
19
  end
80
20
  end
81
21
  end
@@ -2,19 +2,16 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module ActionCableIntegration
6
7
  def perform_action(*args, &block)
7
8
  # The request is only the original websocket request
8
9
  env = connection.env
9
10
  request = ActionDispatch::Request.new(env)
10
- env[Appsignal::Hooks::ActionCableHook::REQUEST_ID] ||=
11
- request.request_id || SecureRandom.uuid
11
+ request_id = request.request_id || SecureRandom.uuid
12
+ env[Appsignal::Hooks::ActionCableHook::REQUEST_ID] ||= request_id
12
13
 
13
- transaction = Appsignal::Transaction.create(
14
- env[Appsignal::Hooks::ActionCableHook::REQUEST_ID],
15
- Appsignal::Transaction::ACTION_CABLE,
16
- request
17
- )
14
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::ACTION_CABLE)
18
15
 
19
16
  begin
20
17
  super
@@ -26,6 +23,7 @@ module Appsignal
26
23
  transaction.set_action_if_nil("#{self.class}##{args.first["action"]}")
27
24
  transaction.set_metadata("path", request.path)
28
25
  transaction.set_metadata("method", "websocket")
26
+ transaction.set_tags(:request_id => request_id) if request_id
29
27
  Appsignal::Transaction.complete_current!
30
28
  end
31
29
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module ActiveSupportNotificationsIntegration
6
7
  BANG = "!"
7
8
 
@@ -1,47 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- # @todo Move to sub-namespace
5
- # @api private
6
- class Capistrano
7
- def self.tasks(config)
8
- config.load do # rubocop:disable Metrics/BlockLength
9
- after "deploy", "appsignal:deploy"
10
- after "deploy:migrations", "appsignal:deploy"
4
+ module Integrations
5
+ # @api private
6
+ class Capistrano
7
+ def self.tasks(config)
8
+ config.load do # rubocop:disable Metrics/BlockLength
9
+ after "deploy", "appsignal:deploy"
10
+ after "deploy:migrations", "appsignal:deploy"
11
11
 
12
- namespace :appsignal do
13
- task :deploy do
14
- env = fetch(:appsignal_env,
15
- fetch(:stage, fetch(:rails_env, fetch(:rack_env, "production"))))
16
- user = fetch(:appsignal_user, ENV["USER"] || ENV.fetch("USERNAME", nil))
17
- revision = fetch(:appsignal_revision, fetch(:current_revision))
12
+ namespace :appsignal do
13
+ task :deploy do
14
+ env = fetch(:appsignal_env,
15
+ fetch(:stage, fetch(:rails_env, fetch(:rack_env, "production"))))
16
+ user = fetch(:appsignal_user, ENV["USER"] || ENV.fetch("USERNAME", nil))
17
+ revision = fetch(:appsignal_revision, fetch(:current_revision))
18
18
 
19
- appsignal_config = Appsignal::Config.new(
20
- ENV.fetch("PWD", nil),
21
- env,
22
- {},
23
- Appsignal::Utils::IntegrationLogger.new(StringIO.new)
24
- ).tap do |c|
25
- fetch(:appsignal_config, {}).each do |key, value|
26
- c[key] = value
19
+ appsignal_config = Appsignal::Config.new(
20
+ ENV.fetch("PWD", nil),
21
+ env,
22
+ {},
23
+ Appsignal::Utils::IntegrationLogger.new(StringIO.new)
24
+ ).tap do |c|
25
+ fetch(:appsignal_config, {}).each do |key, value|
26
+ c[key] = value
27
+ end
28
+ c.validate
27
29
  end
28
- c.validate
29
- end
30
30
 
31
- if appsignal_config&.active?
32
- marker_data = {
33
- :revision => revision,
34
- :user => user
35
- }
31
+ if appsignal_config&.active?
32
+ marker_data = {
33
+ :revision => revision,
34
+ :user => user
35
+ }
36
36
 
37
- marker = Marker.new(marker_data, appsignal_config)
38
- if config.dry_run
39
- puts "Dry run: AppSignal deploy marker not actually sent."
37
+ marker = Marker.new(marker_data, appsignal_config)
38
+ if config.dry_run
39
+ puts "Dry run: AppSignal deploy marker not actually sent."
40
+ else
41
+ marker.transmit
42
+ end
40
43
  else
41
- marker.transmit
44
+ puts "Not notifying of deploy, config is not active for environment: #{env}"
42
45
  end
43
- else
44
- puts "Not notifying of deploy, config is not active for environment: #{env}"
45
46
  end
46
47
  end
47
48
  end
@@ -51,5 +52,5 @@ module Appsignal
51
52
  end
52
53
 
53
54
  if ::Capistrano::Configuration.instance
54
- Appsignal::Capistrano.tasks(::Capistrano::Configuration.instance)
55
+ Appsignal::Integrations::Capistrano.tasks(::Capistrano::Configuration.instance)
55
56
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  class Hooks
5
+ # @api private
5
6
  module DataMapperLogListener
6
7
  SQL_CLASSES = [
7
8
  "DataObjects::SqlServer::Connection",
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- class Hooks
4
+ module Integrations
5
5
  # @api private
6
6
  class DelayedJobPlugin < ::Delayed::Plugin
7
7
  extend Appsignal::Hooks::Helpers
@@ -17,52 +17,46 @@ module Appsignal
17
17
  end
18
18
 
19
19
  def self.invoke_with_instrumentation(job, block)
20
- payload = job.payload_object
20
+ transaction =
21
+ Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
21
22
 
23
+ Appsignal.instrument("perform_job.delayed_job") do
24
+ block.call(job)
25
+ end
26
+ rescue Exception => error # rubocop:disable Lint/RescueException
27
+ transaction.set_error(error)
28
+ raise
29
+ ensure
30
+ payload = job.payload_object
22
31
  if payload.respond_to? :job_data
23
32
  # ActiveJob
24
33
  job_data = payload.job_data
25
- args = job_data.fetch("arguments", {})
26
- class_name = job_data["job_class"]
27
- method_name = "perform"
34
+ transaction.set_action_if_nil("#{job_data["job_class"]}#perform")
35
+ transaction.set_params_if_nil(job_data.fetch("arguments", {}))
28
36
  else
29
37
  # Delayed Job
30
- args = extract_value(payload, :args, {})
31
- class_name, method_name = class_and_method_name_from_object_or_hash(payload, job.name)
38
+ transaction.set_action_if_nil(action_name_from_payload(payload, job.name))
39
+ transaction.set_params_if_nil(extract_value(payload, :args, {}))
32
40
  end
33
41
 
34
- params = Appsignal::Utils::HashSanitizer.sanitize(
35
- args,
36
- Appsignal.config[:filter_parameters]
42
+ transaction.set_tags(
43
+ :id => extract_value(job, :id, nil, true),
44
+ :queue => extract_value(job, :queue),
45
+ :priority => extract_value(job, :priority, 0),
46
+ :attempts => extract_value(job, :attempts, 0)
37
47
  )
38
48
 
39
- Appsignal.monitor_transaction(
40
- "perform_job.delayed_job",
41
- :class => class_name,
42
- :method => method_name,
43
- :metadata => {
44
- :id => extract_value(job, :id, nil, true),
45
- :queue => extract_value(job, :queue),
46
- :priority => extract_value(job, :priority, 0),
47
- :attempts => extract_value(job, :attempts, 0)
48
- },
49
- :params => params,
50
- :queue_start => extract_value(job, :run_at)
51
- ) do
52
- block.call(job)
53
- end
49
+ transaction.set_queue_start(extract_value(job, :run_at)&.to_i&.* 1_000)
50
+
51
+ Appsignal::Transaction.complete_current!
54
52
  end
55
53
 
56
- def self.class_and_method_name_from_object_or_hash(payload, default_name)
54
+ def self.action_name_from_payload(payload, default_name)
57
55
  # Attempt to find appsignal_name override
58
56
  class_and_method_name = extract_value(payload, :appsignal_name, nil)
59
- return class_and_method_name.split("#") if class_and_method_name.is_a?(String)
60
-
61
- pound_split = default_name.split("#")
62
- return pound_split if pound_split.length == 2
63
-
64
- dot_split = default_name.split(".")
65
- return default_name if dot_split.length == 2
57
+ return class_and_method_name if class_and_method_name.is_a?(String)
58
+ return default_name if default_name.split("#").length == 2
59
+ return default_name if default_name.split(".").length == 2
66
60
 
67
61
  "#{default_name}#perform"
68
62
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module DryMonitorIntegration
6
7
  def instrument(event_id, payload = {}, &block)
7
8
  Appsignal::Transaction.current.start_event
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module ExconIntegration
6
7
  def self.instrument(name, data, &block)
7
8
  namespace, *event = name.split(".")
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module HttpIntegration
6
7
  def request(verb, uri, opts = {})
7
8
  parsed_request_uri = uri.is_a?(URI) ? uri : URI.parse(uri.to_s)
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module NetHttpIntegration
6
7
  def request(request, body = nil, &block)
7
8
  Appsignal.instrument(
@@ -3,6 +3,8 @@
3
3
  Appsignal::Environment.report_enabled("object_instrumentation") if defined?(Appsignal)
4
4
 
5
5
  class Object
6
+ # @see https://docs.appsignal.com/ruby/instrumentation/method-instrumentation.html
7
+ # Method instrumentation documentation.
6
8
  def self.appsignal_instrument_class_method(method_name, options = {})
7
9
  singleton_class.send \
8
10
  :alias_method, "appsignal_uninstrumented_#{method_name}", method_name
@@ -20,6 +22,8 @@ class Object
20
22
  end
21
23
  end
22
24
 
25
+ # @see https://docs.appsignal.com/ruby/instrumentation/method-instrumentation.html
26
+ # Method instrumentation documentation.
23
27
  def self.appsignal_instrument_method(method_name, options = {})
24
28
  alias_method "appsignal_uninstrumented_#{method_name}", method_name
25
29
  define_method method_name do |*args, &block|
@@ -33,12 +37,14 @@ class Object
33
37
  ruby2_keywords method_name if respond_to?(:ruby2_keywords, true)
34
38
  end
35
39
 
40
+ # @api private
36
41
  def self.appsignal_reverse_class_name
37
42
  return "AnonymousClass" unless name
38
43
 
39
44
  name.split("::").reverse.join(".")
40
45
  end
41
46
 
47
+ # @api private
42
48
  def appsignal_reverse_class_name
43
49
  self.class.appsignal_reverse_class_name
44
50
  end
@@ -1,18 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
+ require "appsignal/rack/sinatra_instrumentation"
4
5
 
5
6
  module Appsignal
6
7
  module Integrations
7
8
  # @api private
8
9
  module PadrinoPlugin
9
10
  def self.init
10
- Appsignal.internal_logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
11
+ Padrino::Application.prepend Appsignal::Integrations::PadrinoIntegration
11
12
 
12
- root = Padrino.mounted_root
13
- Appsignal.config = Appsignal::Config.new(root, Padrino.env)
13
+ Padrino.before_load do
14
+ Appsignal.internal_logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
14
15
 
15
- Appsignal.start
16
+ unless Appsignal.active?
17
+ root = Padrino.mounted_root
18
+ Appsignal.config = Appsignal::Config.new(root, Padrino.env)
19
+ Appsignal.start
20
+ end
21
+
22
+ next unless Appsignal.active?
23
+
24
+ Padrino.use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
25
+ Padrino.use Appsignal::Rack::SinatraBaseInstrumentation,
26
+ :instrument_event_name => "process_action.padrino"
27
+ end
16
28
  end
17
29
  end
18
30
  end
@@ -20,35 +32,23 @@ end
20
32
 
21
33
  module Appsignal
22
34
  module Integrations
35
+ # @api private
23
36
  module PadrinoIntegration
24
37
  def route!(base = settings, pass_block = nil)
25
38
  return super if !Appsignal.active? || env["sinatra.static_file"]
26
39
 
27
- transaction = Appsignal::Transaction.create(
28
- SecureRandom.uuid,
29
- Appsignal::Transaction::HTTP_REQUEST,
30
- request
31
- )
32
40
  begin
33
- Appsignal.instrument("process_action.padrino") do
34
- super
35
- end
36
- rescue Exception => error # rubocop:disable Lint/RescueException
37
- transaction.set_error(error)
38
- raise error
41
+ super
39
42
  ensure
43
+ transaction = Appsignal::Transaction.current
40
44
  transaction.set_action_if_nil(get_payload_action(request))
41
- transaction.set_metadata("path", request.path)
42
- transaction.set_metadata("method", request.request_method)
43
- transaction.set_http_or_background_queue_start
44
- Appsignal::Transaction.complete_current!
45
45
  end
46
46
  end
47
47
 
48
48
  private
49
49
 
50
50
  def get_payload_action(request)
51
- # Short-circut is there's no request object to obtain information from
51
+ # Short-circuit is there's no request object to obtain information from
52
52
  return settings.name.to_s unless request
53
53
 
54
54
  # Newer versions expose the action / controller on the request class.
@@ -75,8 +75,4 @@ module Appsignal
75
75
  end
76
76
  end
77
77
 
78
- Padrino::Application.prepend Appsignal::Integrations::PadrinoIntegration
79
-
80
- Padrino.after_load do
81
- Appsignal::Integrations::PadrinoPlugin.init
82
- end
78
+ Appsignal::Integrations::PadrinoPlugin.init
@@ -2,27 +2,11 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module QuePlugin
6
7
  def _run(*)
7
- local_attrs = respond_to?(:que_attrs) ? que_attrs : attrs
8
- env = {
9
- :metadata => {
10
- :id => local_attrs[:job_id] || local_attrs[:id],
11
- :queue => local_attrs[:queue],
12
- :run_at => local_attrs[:run_at].to_s,
13
- :priority => local_attrs[:priority],
14
- :attempts => local_attrs[:error_count].to_i
15
- },
16
- :params => local_attrs[:args]
17
- }
18
-
19
- request = Appsignal::Transaction::GenericRequest.new(env)
20
-
21
- transaction = Appsignal::Transaction.create(
22
- SecureRandom.uuid,
23
- Appsignal::Transaction::BACKGROUND_JOB,
24
- request
25
- )
8
+ transaction =
9
+ Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
26
10
 
27
11
  begin
28
12
  Appsignal.instrument("perform_job.que") { super }
@@ -30,7 +14,16 @@ module Appsignal
30
14
  transaction.set_error(error)
31
15
  raise error
32
16
  ensure
33
- transaction.set_action_if_nil "#{local_attrs[:job_class]}#run"
17
+ local_attrs = respond_to?(:que_attrs) ? que_attrs : attrs
18
+ transaction.set_action_if_nil("#{local_attrs[:job_class]}#run")
19
+ transaction.set_params_if_nil(local_attrs[:args])
20
+ transaction.set_tags(
21
+ "id" => local_attrs[:job_id] || local_attrs[:id],
22
+ "queue" => local_attrs[:queue],
23
+ "run_at" => local_attrs[:run_at].to_s,
24
+ "priority" => local_attrs[:priority],
25
+ "attempts" => local_attrs[:error_count].to_i
26
+ )
34
27
  Appsignal::Transaction.complete_current!
35
28
  end
36
29
  end
@@ -69,7 +69,7 @@ module Appsignal
69
69
  transaction.set_metadata("path", path)
70
70
  transaction.set_metadata("method", method)
71
71
  transaction.set_params_if_nil(params)
72
- transaction.set_sample_data("custom_data", custom_data) if custom_data
72
+ transaction.set_custom_data(custom_data) if custom_data
73
73
 
74
74
  tags[:severity] = severity
75
75
  tags[:source] = source.to_s if source
@@ -2,26 +2,56 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module RakeIntegration
6
7
  def execute(*args)
7
- super
8
+ transaction =
9
+ if Appsignal.config[:enable_rake_performance_instrumentation]
10
+ Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
11
+ _appsignal_create_transaction
12
+ end
13
+
14
+ Appsignal.instrument "task.rake" do
15
+ super
16
+ end
8
17
  rescue Exception => error # rubocop:disable Lint/RescueException
9
- # Format given arguments and cast to hash if possible
10
- params, _ = args
11
- params = params.to_hash if params.respond_to?(:to_hash)
12
-
13
- transaction = Appsignal::Transaction.create(
14
- SecureRandom.uuid,
15
- Appsignal::Transaction::BACKGROUND_JOB,
16
- Appsignal::Transaction::GenericRequest.new(
17
- :params => params
18
- )
19
- )
20
- transaction.set_action(name)
18
+ Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
19
+ transaction ||= _appsignal_create_transaction
21
20
  transaction.set_error(error)
22
- transaction.complete
23
- Appsignal.stop("rake")
24
21
  raise error
22
+ ensure
23
+ if transaction
24
+ # Format given arguments and cast to hash if possible
25
+ params, _ = args
26
+ params = params.to_hash if params.respond_to?(:to_hash)
27
+ transaction.set_params_if_nil(params)
28
+ transaction.set_action(name)
29
+ transaction.complete
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def _appsignal_create_transaction
36
+ Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
37
+ end
38
+ end
39
+
40
+ # @api private
41
+ module RakeIntegrationHelper
42
+ # Register an `at_exit` hook when a task is executed. This will stop
43
+ # AppSignal when _all_ tasks are executed and Rake exits.
44
+ def self.register_at_exit_hook
45
+ return if @register_at_exit_hook
46
+
47
+ Kernel.at_exit(&method(:at_exit_hook))
48
+
49
+ @register_at_exit_hook = true
50
+ end
51
+
52
+ # The at_exit hook itself
53
+ def self.at_exit_hook
54
+ Appsignal.stop("rake")
25
55
  end
26
56
  end
27
57
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module RedisIntegration
6
7
  def write(command)
7
8
  sanitized_command =