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
@@ -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
@@ -108,7 +105,7 @@ module Appsignal
108
105
  # {#instrument_app_call} this will report any exceptions being
109
106
  # raised.
110
107
  #
111
- # @see {#instrument_app_call}
108
+ # @see #instrument_app_call
112
109
  def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
113
110
  instrument_app_call(env, transaction)
114
111
  rescue Exception => error # rubocop:disable Lint/RescueException
@@ -147,7 +144,14 @@ module Appsignal
147
144
  transaction.set_metadata("method", request_method) if request_method
148
145
 
149
146
  transaction.set_params_if_nil { params_for(request) }
150
- transaction.set_http_or_background_queue_start
147
+ transaction.set_session_data_if_nil do
148
+ request.session if request.respond_to?(:session)
149
+ end
150
+ transaction.set_headers_if_nil do
151
+ request.env if request.respond_to?(:env)
152
+ end
153
+ queue_start = Appsignal::Rack::Utils.queue_start_from(request.env)
154
+ transaction.set_queue_start(queue_start) if queue_start
151
155
  end
152
156
 
153
157
  def params_for(request)
@@ -155,9 +159,9 @@ module Appsignal
155
159
 
156
160
  request.send(@params_method)
157
161
  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}"
162
+ Appsignal.internal_logger.error(
163
+ "Exception while fetching params from '#{@request_class}##{@params_method}': " \
164
+ "#{error.class} #{error}"
161
165
  )
162
166
  nil
163
167
  end
@@ -165,7 +169,9 @@ module Appsignal
165
169
  def request_method_for(request)
166
170
  request.request_method
167
171
  rescue => error
168
- Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
172
+ Appsignal.internal_logger.error(
173
+ "Exception while fetching the HTTP request method: #{error.class}: #{error}"
174
+ )
169
175
  nil
170
176
  end
171
177
 
@@ -7,10 +7,32 @@ module Appsignal
7
7
  APPSIGNAL_EVENT_HANDLER_HAS_ERROR = "appsignal.event_handler.error"
8
8
  RACK_AFTER_REPLY = "rack.after_reply"
9
9
 
10
- # @api private
10
+ # Instrumentation middleware using Rack's Events module.
11
+ #
12
+ # We recommend using this in combination with the
13
+ # {InstrumentationMiddleware}.
14
+ #
15
+ # This middleware will report the response status code as the
16
+ # `response_status` tag on the sample. It will also report the response
17
+ # status as the `response_status` metric.
18
+ #
19
+ # This middleware will ensure the AppSignal transaction is always completed
20
+ # for every request.
21
+ #
22
+ # @example Add EventHandler to a Rack app
23
+ # # Add this middleware as the first middleware of an app
24
+ # use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
25
+ #
26
+ # # Then add the InstrumentationMiddleware
27
+ # use Appsignal::Rack::InstrumentationMiddleware
28
+ #
29
+ # @see https://docs.appsignal.com/ruby/integrations/rack.html
30
+ # Rack integration documentation.
31
+ # @api public
11
32
  class EventHandler
12
33
  include ::Rack::Events::Abstract
13
34
 
35
+ # @api private
14
36
  def self.safe_execution(name)
15
37
  yield
16
38
  rescue => e
@@ -19,27 +41,27 @@ module Appsignal
19
41
  )
20
42
  end
21
43
 
44
+ # @api private
22
45
  attr_reader :id
23
46
 
47
+ # @api private
24
48
  def initialize
25
49
  @id = SecureRandom.uuid
26
50
  end
27
51
 
52
+ # @api private
28
53
  def request_handler?(given_id)
29
54
  id == given_id
30
55
  end
31
56
 
57
+ # @api private
32
58
  def on_start(request, _response)
33
59
  event_handler = self
34
60
  self.class.safe_execution("Appsignal::Rack::EventHandler#on_start") do
35
61
  request.env[APPSIGNAL_EVENT_HANDLER_ID] ||= id
36
62
  return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
37
63
 
38
- transaction = Appsignal::Transaction.create(
39
- SecureRandom.uuid,
40
- Appsignal::Transaction::HTTP_REQUEST,
41
- request
42
- )
64
+ transaction = Appsignal::Transaction.create(Appsignal::Transaction::HTTP_REQUEST)
43
65
  request.env[APPSIGNAL_TRANSACTION] = transaction
44
66
 
45
67
  request.env[RACK_AFTER_REPLY] ||= []
@@ -49,7 +71,8 @@ module Appsignal
49
71
  Appsignal::Rack::EventHandler
50
72
  .safe_execution("Appsignal::Rack::EventHandler's after_reply") do
51
73
  transaction.finish_event("process_request.rack", "", "")
52
- transaction.set_http_or_background_queue_start
74
+ queue_start = Appsignal::Rack::Utils.queue_start_from(request.env)
75
+ transaction.set_queue_start(queue_start) if queue_start
53
76
  end
54
77
 
55
78
  # Make sure the current transaction is always closed when the request
@@ -65,6 +88,7 @@ module Appsignal
65
88
  end
66
89
  end
67
90
 
91
+ # @api private
68
92
  def on_error(request, _response, error)
69
93
  self.class.safe_execution("Appsignal::Rack::EventHandler#on_error") do
70
94
  return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
@@ -77,6 +101,7 @@ module Appsignal
77
101
  end
78
102
  end
79
103
 
104
+ # @api private
80
105
  def on_finish(request, response)
81
106
  return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
82
107
 
@@ -85,7 +110,13 @@ module Appsignal
85
110
 
86
111
  self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
87
112
  transaction.finish_event("process_request.rack", "", "")
88
- transaction.set_http_or_background_queue_start
113
+ transaction.set_params_if_nil { request.params }
114
+ transaction.set_headers_if_nil { request.env }
115
+ transaction.set_session_data_if_nil do
116
+ request.session if request.respond_to?(:session)
117
+ end
118
+ queue_start = Appsignal::Rack::Utils.queue_start_from(request.env)
119
+ transaction.set_queue_start(queue_start) if queue_start
89
120
  response_status =
90
121
  if response
91
122
  response.status
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Rack
5
+ # @deprecated Use {InstrumentationMiddleware} instead.
5
6
  # @api private
6
7
  class GenericInstrumentation < AbstractMiddleware
7
8
  def initialize(app, options = {})
@@ -2,8 +2,9 @@
2
2
 
3
3
  module Appsignal
4
4
  module Rack
5
- # @api private
5
+ # @api public
6
6
  class GrapeMiddleware < Appsignal::Rack::AbstractMiddleware
7
+ # @api private
7
8
  def initialize(app, options = {})
8
9
  options[:instrument_event_name] = "process_request.grape"
9
10
  options[:report_errors] = lambda { |env| !env["grape.skip_appsignal_error"] }
@@ -10,6 +10,7 @@ module Appsignal
10
10
  # Instrumentation middleware that tracks exceptions in streaming Rack
11
11
  # responses.
12
12
  #
13
+ # @deprecated Use {InstrumentationMiddleware} instead.
13
14
  # @api private
14
15
  class StreamingListener < AbstractMiddleware
15
16
  def initialize(app, options = {})
@@ -3,6 +3,35 @@
3
3
  module Appsignal
4
4
  # @api private
5
5
  module Rack
6
+ class Utils
7
+ # Fetch the queue start time from the request environment.
8
+ #
9
+ # @since 3.11.0
10
+ # @param env [Hash] Request environment hash.
11
+ # @return [Integer, NilClass]
12
+ def self.queue_start_from(env)
13
+ return unless env
14
+
15
+ env_var = env["HTTP_X_QUEUE_START"] || env["HTTP_X_REQUEST_START"]
16
+ return unless env_var
17
+
18
+ cleaned_value = env_var.tr("^0-9", "")
19
+ return if cleaned_value.empty?
20
+
21
+ value = cleaned_value.to_i
22
+ if value > 4_102_441_200_000
23
+ # Value is in microseconds. Transform to milliseconds.
24
+ value / 1_000
25
+ elsif value < 946_681_200_000
26
+ # Value is too low to be plausible
27
+ nil
28
+ else
29
+ # Value is in milliseconds
30
+ value
31
+ end
32
+ end
33
+ end
34
+
6
35
  # Alias constants that have moved with a warning message that points to the
7
36
  # place to update the reference.
8
37
  def self.const_missing(name)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
+ # @api private
4
5
  class Span
5
6
  def initialize(namespace = nil, ext = nil)
6
7
  @ext = ext || Appsignal::Extension::Span.root(namespace || "")