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
@@ -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
@@ -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
@@ -33,11 +33,7 @@ module Appsignal
33
33
  private
34
34
 
35
35
  def _appsignal_create_transaction
36
- Appsignal::Transaction.create(
37
- SecureRandom.uuid,
38
- Appsignal::Transaction::BACKGROUND_JOB,
39
- Appsignal::Transaction::GenericRequest.new({})
40
- )
36
+ Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
41
37
  end
42
38
  end
43
39
 
@@ -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 =
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module RedisClientIntegration
6
7
  def write(command)
7
8
  sanitized_command =
@@ -5,11 +5,7 @@ module Appsignal
5
5
  # @api private
6
6
  module ResqueIntegration
7
7
  def perform
8
- transaction = Appsignal::Transaction.create(
9
- SecureRandom.uuid,
10
- Appsignal::Transaction::BACKGROUND_JOB,
11
- Appsignal::Transaction::GenericRequest.new({})
12
- )
8
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
13
9
 
14
10
  Appsignal.instrument "perform.resque" do
15
11
  super
@@ -34,6 +30,7 @@ module Appsignal
34
30
  end
35
31
  end
36
32
 
33
+ # @api private
37
34
  class ResqueHelpers
38
35
  def self.arguments(payload)
39
36
  case payload["class"]
@@ -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"
@@ -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
@@ -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