appsignal 3.8.0-java → 3.9.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/lib/appsignal/config.rb +10 -2
- data/lib/appsignal/hooks/sidekiq.rb +18 -1
- data/lib/appsignal/integrations/sidekiq.rb +37 -18
- data/lib/appsignal/integrations/sinatra.rb +9 -7
- data/lib/appsignal/rack/abstract_middleware.rb +127 -0
- data/lib/appsignal/rack/event_handler.rb +29 -1
- data/lib/appsignal/rack/generic_instrumentation.rb +6 -33
- data/lib/appsignal/rack/sinatra_instrumentation.rb +16 -42
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/spec/lib/appsignal/config_spec.rb +28 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +175 -17
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +57 -33
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +250 -0
- data/spec/lib/appsignal/rack/event_handler_spec.rb +56 -3
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +26 -79
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +80 -164
- data/support/install_deps +6 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87ae30cedc24d783bcd6f28bb01bb19384e0f7a280fe2c8b89585a5161aaaf77
|
4
|
+
data.tar.gz: 36c1760ff247804c579bb0b7bf3db2aee1d4ed53ede1a1920d5a8a1fa762f032
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed40403d826734ba4725b087b4d52d75be79d9bfd7172d12ceba70da3393de9bf55ca02964a81104082e9058eb44d1c3795623a21b244b13905a0310f2961d16
|
7
|
+
data.tar.gz: 66832484c634de15a474774f49e8c38838faf4b71889c68c4ad7ef897d1ad64c119b926152a228117409103b657f8523599597394b989bbf87553d1c072bf5a1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
2
2
|
|
3
|
+
## 3.9.0
|
4
|
+
|
5
|
+
_Published on 2024-06-21._
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [500b2b4b](https://github.com/appsignal/appsignal-ruby/commit/500b2b4bb57a29663a197ff063c672e6b0c44769) minor - Report Sidekiq errors when a job is dead/discarded. Configure the new `sidekiq_report_errors` config option to "discard" to only report errors when the job is not retried further.
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- [c76952ff](https://github.com/appsignal/appsignal-ruby/commit/c76952ff5c8bd6e9d1d841a3aeb600b27494bb43) patch - Improve instrumentation for mounted Sinatra apps in Rails apps. The sample reported for the Sinatra request will now include the time spent in Rails and its middleware.
|
14
|
+
- [661b8e08](https://github.com/appsignal/appsignal-ruby/commit/661b8e08de962e8f95326f0bbc9c0061b8cc0a62) patch - Support apps that have multiple Appsignal::Rack::EventHandler-s in the middleware stack.
|
15
|
+
- [7382afa3](https://github.com/appsignal/appsignal-ruby/commit/7382afa3e9c89ce0c9f3430fb71825736e484e82) patch - Improve support for instrumentation of nested pure Rack and Sinatra apps. It will now report more of the request's duration and events. This also improves support for apps that have multiple Rack GenericInstrumentation or SinatraInstrumentation middlewares.
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- [2478eb19](https://github.com/appsignal/appsignal-ruby/commit/2478eb19f51c18433785347d02af18f405eeeabd) patch - Fix issue with AppSignal getting stuck in a boot loop when loading the Sinatra integration with: `require "appsignal/integrations/sinatra"`
|
20
|
+
This could happen in nested applications, like a Sinatra app in a Rails app. It will now use the first config AppSignal starts with.
|
21
|
+
|
22
|
+
## 3.8.1
|
23
|
+
|
24
|
+
_Published on 2024-06-17._
|
25
|
+
|
26
|
+
### Added
|
27
|
+
|
28
|
+
- [5459a021](https://github.com/appsignal/appsignal-ruby/commit/5459a021d7d4bbbd09a0dcbdf5f3af7bf861b6f5) patch - Report the response status for Rails requests as the `response_status` tag on samples, e.g. 200, 301, 500. This tag is visible on the sample detail page.
|
29
|
+
|
30
|
+
The response status is also reported as the `response_status` metric.
|
31
|
+
|
3
32
|
## 3.8.0
|
4
33
|
|
5
34
|
_Published on 2024-06-17._
|
data/lib/appsignal/config.rb
CHANGED
@@ -47,6 +47,7 @@ module Appsignal
|
|
47
47
|
],
|
48
48
|
:send_environment_metadata => true,
|
49
49
|
:send_params => true,
|
50
|
+
:sidekiq_report_errors => "all",
|
50
51
|
:transaction_debug_mode => false
|
51
52
|
}.freeze
|
52
53
|
|
@@ -67,7 +68,7 @@ module Appsignal
|
|
67
68
|
|
68
69
|
ENV_TO_KEY_MAPPING = {
|
69
70
|
"APPSIGNAL_ACTIVE" => :active,
|
70
|
-
"
|
71
|
+
"APPSIGNAL_ACTIVEJOB_REPORT_ERRORS" => :activejob_report_errors,
|
71
72
|
"APPSIGNAL_APP_NAME" => :name,
|
72
73
|
"APPSIGNAL_BIND_ADDRESS" => :bind_address,
|
73
74
|
"APPSIGNAL_CA_FILE_PATH" => :ca_file_path,
|
@@ -108,6 +109,7 @@ module Appsignal
|
|
108
109
|
"APPSIGNAL_SEND_ENVIRONMENT_METADATA" => :send_environment_metadata,
|
109
110
|
"APPSIGNAL_SEND_PARAMS" => :send_params,
|
110
111
|
"APPSIGNAL_SEND_SESSION_DATA" => :send_session_data,
|
112
|
+
"APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => :sidekiq_report_errors,
|
111
113
|
"APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data,
|
112
114
|
"APPSIGNAL_STATSD_PORT" => :statsd_port,
|
113
115
|
"APPSIGNAL_TRANSACTION_DEBUG_MODE" => :transaction_debug_mode,
|
@@ -117,7 +119,7 @@ module Appsignal
|
|
117
119
|
}.freeze
|
118
120
|
# @api private
|
119
121
|
ENV_STRING_KEYS = %w[
|
120
|
-
|
122
|
+
APPSIGNAL_ACTIVEJOB_REPORT_ERRORS
|
121
123
|
APPSIGNAL_APP_NAME
|
122
124
|
APPSIGNAL_BIND_ADDRESS
|
123
125
|
APPSIGNAL_CA_FILE_PATH
|
@@ -130,6 +132,7 @@ module Appsignal
|
|
130
132
|
APPSIGNAL_LOGGING_ENDPOINT
|
131
133
|
APPSIGNAL_PUSH_API_ENDPOINT
|
132
134
|
APPSIGNAL_PUSH_API_KEY
|
135
|
+
APPSIGNAL_SIDEKIQ_REPORT_ERRORS
|
133
136
|
APPSIGNAL_STATSD_PORT
|
134
137
|
APPSIGNAL_WORKING_DIRECTORY_PATH
|
135
138
|
APPSIGNAL_WORKING_DIR_PATH
|
@@ -563,6 +566,11 @@ module Appsignal
|
|
563
566
|
config[:activejob_report_errors] = "all"
|
564
567
|
end
|
565
568
|
|
569
|
+
if config_hash[:sidekiq_report_errors] == "discard" &&
|
570
|
+
!Appsignal::Hooks::SidekiqHook.version_5_1_or_higher?
|
571
|
+
config[:sidekiq_report_errors] = "all"
|
572
|
+
end
|
573
|
+
|
566
574
|
config
|
567
575
|
end
|
568
576
|
|
@@ -5,10 +5,23 @@ module Appsignal
|
|
5
5
|
class SidekiqHook < Appsignal::Hooks::Hook
|
6
6
|
register :sidekiq
|
7
7
|
|
8
|
-
def
|
8
|
+
def self.version_5_1_or_higher?
|
9
|
+
@version_5_1_or_higher ||=
|
10
|
+
if dependencies_present?
|
11
|
+
Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("5.1.0")
|
12
|
+
else
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.dependencies_present?
|
9
18
|
defined?(::Sidekiq)
|
10
19
|
end
|
11
20
|
|
21
|
+
def dependencies_present?
|
22
|
+
self.class.dependencies_present?
|
23
|
+
end
|
24
|
+
|
12
25
|
def install
|
13
26
|
require "appsignal/integrations/sidekiq"
|
14
27
|
Appsignal::Probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
|
@@ -16,6 +29,10 @@ module Appsignal
|
|
16
29
|
::Sidekiq.configure_server do |config|
|
17
30
|
config.error_handlers <<
|
18
31
|
Appsignal::Integrations::SidekiqErrorHandler.new
|
32
|
+
if config.respond_to? :death_handlers
|
33
|
+
config.death_handlers <<
|
34
|
+
Appsignal::Integrations::SidekiqDeathHandler.new
|
35
|
+
end
|
19
36
|
|
20
37
|
config.server_middleware do |chain|
|
21
38
|
if chain.respond_to? :prepend
|
@@ -4,32 +4,51 @@ require "yaml"
|
|
4
4
|
|
5
5
|
module Appsignal
|
6
6
|
module Integrations
|
7
|
+
# Handler for job death events. We get notified when a job has exhausted
|
8
|
+
# its retries.
|
9
|
+
#
|
10
|
+
# This is called before the SidekiqErrorHandler so it doesn't need to worry
|
11
|
+
# about completing the transaction.
|
12
|
+
#
|
13
|
+
# Introduced in Sidekiq 5.1.
|
14
|
+
class SidekiqDeathHandler
|
15
|
+
def call(_job_context, exception)
|
16
|
+
return unless Appsignal.config[:sidekiq_report_errors] == "discard"
|
17
|
+
|
18
|
+
transaction = Appsignal::Transaction.current
|
19
|
+
transaction.set_error(exception)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
7
23
|
# Error handler for Sidekiq to report errors from jobs and internal Sidekiq
|
8
24
|
# errors.
|
9
25
|
#
|
10
26
|
# @api private
|
11
27
|
class SidekiqErrorHandler
|
28
|
+
# Sidekiq 7.1.5 introduced the third sidekiq_config argument. It is not
|
29
|
+
# given on older Sidekiq versions.
|
12
30
|
def call(exception, sidekiq_context, _sidekiq_config = nil)
|
13
|
-
|
14
|
-
if Appsignal
|
15
|
-
Appsignal::Transaction.current
|
16
|
-
|
17
|
-
# Sidekiq error outside of the middleware scope.
|
18
|
-
# Can be a job JSON parse error or some other error happening in
|
19
|
-
# Sidekiq.
|
20
|
-
transaction =
|
21
|
-
Appsignal::Transaction.create(
|
22
|
-
SecureRandom.uuid, # Newly generated job id
|
23
|
-
Appsignal::Transaction::BACKGROUND_JOB,
|
24
|
-
Appsignal::Transaction::GenericRequest.new({})
|
25
|
-
)
|
26
|
-
transaction.set_action_if_nil("SidekiqInternal")
|
27
|
-
transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
|
28
|
-
transaction.params = { :jobstr => sidekiq_context[:jobstr] }
|
29
|
-
transaction
|
31
|
+
if Appsignal::Transaction.current?
|
32
|
+
if Appsignal.config[:sidekiq_report_errors] == "all"
|
33
|
+
transaction = Appsignal::Transaction.current
|
34
|
+
transaction.set_error(exception)
|
30
35
|
end
|
36
|
+
else
|
37
|
+
# Sidekiq error outside of the middleware scope.
|
38
|
+
# Can be a job JSON parse error or some other error happening in
|
39
|
+
# 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
|
+
)
|
46
|
+
transaction.set_action_if_nil("SidekiqInternal")
|
47
|
+
transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
|
48
|
+
transaction.params = { :jobstr => sidekiq_context[:jobstr] }
|
49
|
+
transaction.set_error(exception)
|
50
|
+
end
|
31
51
|
|
32
|
-
transaction.set_error(exception)
|
33
52
|
Appsignal::Transaction.complete_current!
|
34
53
|
end
|
35
54
|
end
|
@@ -5,13 +5,15 @@ require "appsignal/rack/sinatra_instrumentation"
|
|
5
5
|
|
6
6
|
Appsignal.internal_logger.debug("Loading Sinatra (#{Sinatra::VERSION}) integration")
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
+
)
|
13
14
|
|
14
|
-
Appsignal.start_logger
|
15
|
-
Appsignal.start
|
15
|
+
Appsignal.start_logger
|
16
|
+
Appsignal.start
|
17
|
+
end
|
16
18
|
|
17
19
|
::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation) if Appsignal.active?
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
module Appsignal
|
6
|
+
# @api private
|
7
|
+
module Rack
|
8
|
+
class AbstractMiddleware
|
9
|
+
def initialize(app, options = {})
|
10
|
+
Appsignal.internal_logger.debug "Initializing #{self.class}"
|
11
|
+
@app = app
|
12
|
+
@options = options
|
13
|
+
@request_class = options.fetch(:request_class, ::Rack::Request)
|
14
|
+
@params_method = options.fetch(:params_method, :params)
|
15
|
+
@instrument_span_name = options.fetch(:instrument_span_name, "process.abstract")
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
if Appsignal.active?
|
20
|
+
request = request_for(env)
|
21
|
+
# Supported nested instrumentation middlewares by checking if there's
|
22
|
+
# already a transaction active for this request.
|
23
|
+
wrapped_instrumentation = env.key?(Appsignal::Rack::APPSIGNAL_TRANSACTION)
|
24
|
+
transaction =
|
25
|
+
if wrapped_instrumentation
|
26
|
+
env[Appsignal::Rack::APPSIGNAL_TRANSACTION]
|
27
|
+
else
|
28
|
+
Appsignal::Transaction.create(
|
29
|
+
SecureRandom.uuid,
|
30
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
31
|
+
request
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
add_transaction_metadata_before(transaction, request)
|
36
|
+
if wrapped_instrumentation
|
37
|
+
instrument_wrapped_request(request, transaction)
|
38
|
+
else
|
39
|
+
# Set transaction on the request environment so other nested
|
40
|
+
# middleware can detect if there is parent instrumentation
|
41
|
+
# middleware active.
|
42
|
+
env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
|
43
|
+
instrument_request(request, transaction)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
@app.call(env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Another instrumentation middleware is active earlier in the stack, so
|
53
|
+
# don't report any exceptions here, the top instrumentation middleware
|
54
|
+
# will be the one reporting the exception.
|
55
|
+
#
|
56
|
+
# Either another {GenericInstrumentation} or {EventHandler} is higher in
|
57
|
+
# the stack and will report the exception and complete the transaction.
|
58
|
+
#
|
59
|
+
# @see {#instrument_request}
|
60
|
+
def instrument_wrapped_request(request, transaction)
|
61
|
+
instrument_app_call(request.env)
|
62
|
+
ensure
|
63
|
+
add_transaction_metadata_after(transaction, request)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Instrument the request fully. This is used by the top instrumentation
|
67
|
+
# middleware in the middleware stack. Unlike
|
68
|
+
# {#instrument_wrapped_request} this will report any exceptions being
|
69
|
+
# raised.
|
70
|
+
#
|
71
|
+
# @see {#instrument_wrapped_request}
|
72
|
+
def instrument_request(request, transaction)
|
73
|
+
instrument_app_call(request.env)
|
74
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
75
|
+
transaction.set_error(error)
|
76
|
+
raise error
|
77
|
+
ensure
|
78
|
+
add_transaction_metadata_after(transaction, request)
|
79
|
+
|
80
|
+
# Complete transaction because this is the top instrumentation middleware.
|
81
|
+
Appsignal::Transaction.complete_current!
|
82
|
+
end
|
83
|
+
|
84
|
+
def instrument_app_call(env)
|
85
|
+
Appsignal.instrument(@instrument_span_name) do
|
86
|
+
@app.call(env)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add metadata to the transaction based on the request environment.
|
91
|
+
# Override this method to set metadata before the app is called.
|
92
|
+
# Call `super` to also include the default set metadata.
|
93
|
+
def add_transaction_metadata_before(transaction, request)
|
94
|
+
params = params_for(request)
|
95
|
+
transaction.params = params if params
|
96
|
+
end
|
97
|
+
|
98
|
+
# Add metadata to the transaction based on the request environment.
|
99
|
+
# Override this method to set metadata after the app is called.
|
100
|
+
# Call `super` to also include the default set metadata.
|
101
|
+
def add_transaction_metadata_after(transaction, request)
|
102
|
+
default_action =
|
103
|
+
request.env["appsignal.route"] || request.env["appsignal.action"]
|
104
|
+
transaction.set_action_if_nil(default_action)
|
105
|
+
transaction.set_metadata("path", request.path)
|
106
|
+
transaction.set_metadata("method", request.request_method)
|
107
|
+
transaction.set_http_or_background_queue_start
|
108
|
+
end
|
109
|
+
|
110
|
+
def params_for(request)
|
111
|
+
return unless request.respond_to?(@params_method)
|
112
|
+
|
113
|
+
request.send(@params_method)
|
114
|
+
rescue => error
|
115
|
+
# Getting params from the request has been know to fail.
|
116
|
+
Appsignal.internal_logger.debug(
|
117
|
+
"Exception while getting params in #{self.class} from '#{@params_method}': #{error}"
|
118
|
+
)
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def request_for(env)
|
123
|
+
@request_class.new(env)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Appsignal
|
4
4
|
module Rack
|
5
5
|
APPSIGNAL_TRANSACTION = "appsignal.transaction"
|
6
|
+
APPSIGNAL_EVENT_HANDLER_ID = "appsignal.event_handler_id"
|
6
7
|
RACK_AFTER_REPLY = "rack.after_reply"
|
7
8
|
|
8
9
|
class EventHandler
|
@@ -16,8 +17,22 @@ module Appsignal
|
|
16
17
|
)
|
17
18
|
end
|
18
19
|
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@id = SecureRandom.uuid
|
24
|
+
end
|
25
|
+
|
26
|
+
def request_handler?(given_id)
|
27
|
+
id == given_id
|
28
|
+
end
|
29
|
+
|
19
30
|
def on_start(request, _response)
|
31
|
+
event_handler = self
|
20
32
|
self.class.safe_execution("Appsignal::Rack::EventHandler#on_start") do
|
33
|
+
request.env[APPSIGNAL_EVENT_HANDLER_ID] ||= id
|
34
|
+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
35
|
+
|
21
36
|
transaction = Appsignal::Transaction.create(
|
22
37
|
SecureRandom.uuid,
|
23
38
|
Appsignal::Transaction::HTTP_REQUEST,
|
@@ -29,6 +44,8 @@ module Appsignal
|
|
29
44
|
request.env[RACK_AFTER_REPLY] << proc do
|
30
45
|
Appsignal::Rack::EventHandler
|
31
46
|
.safe_execution("Appsignal::Rack::EventHandler's after_reply") do
|
47
|
+
next unless event_handler.request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
48
|
+
|
32
49
|
transaction.finish_event("process_request.rack", "", "")
|
33
50
|
transaction.set_http_or_background_queue_start
|
34
51
|
|
@@ -48,6 +65,8 @@ module Appsignal
|
|
48
65
|
|
49
66
|
def on_error(request, _response, error)
|
50
67
|
self.class.safe_execution("Appsignal::Rack::EventHandler#on_error") do
|
68
|
+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
69
|
+
|
51
70
|
transaction = request.env[APPSIGNAL_TRANSACTION]
|
52
71
|
return unless transaction
|
53
72
|
|
@@ -55,13 +74,22 @@ module Appsignal
|
|
55
74
|
end
|
56
75
|
end
|
57
76
|
|
58
|
-
def on_finish(request,
|
77
|
+
def on_finish(request, response)
|
59
78
|
self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
|
79
|
+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
80
|
+
|
60
81
|
transaction = request.env[APPSIGNAL_TRANSACTION]
|
61
82
|
return unless transaction
|
62
83
|
|
63
84
|
transaction.finish_event("process_request.rack", "", "")
|
85
|
+
transaction.set_tags(:response_status => response.status)
|
64
86
|
transaction.set_http_or_background_queue_start
|
87
|
+
Appsignal.increment_counter(
|
88
|
+
:response_status,
|
89
|
+
1,
|
90
|
+
:status => response.status,
|
91
|
+
:namespace => format_namespace(transaction.namespace)
|
92
|
+
)
|
65
93
|
|
66
94
|
# Make sure the current transaction is always closed when the request
|
67
95
|
# is finished
|
@@ -5,42 +5,15 @@ require "rack"
|
|
5
5
|
module Appsignal
|
6
6
|
# @api private
|
7
7
|
module Rack
|
8
|
-
class GenericInstrumentation
|
8
|
+
class GenericInstrumentation < AbstractMiddleware
|
9
9
|
def initialize(app, options = {})
|
10
|
-
|
11
|
-
|
12
|
-
@options = options
|
10
|
+
options[:instrument_span_name] ||= "process_action.generic"
|
11
|
+
super
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
@app.call(env)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def call_with_appsignal_monitoring(env)
|
24
|
-
request = ::Rack::Request.new(env)
|
25
|
-
transaction = Appsignal::Transaction.create(
|
26
|
-
SecureRandom.uuid,
|
27
|
-
Appsignal::Transaction::HTTP_REQUEST,
|
28
|
-
request
|
29
|
-
)
|
30
|
-
begin
|
31
|
-
Appsignal.instrument("process_action.generic") do
|
32
|
-
@app.call(env)
|
33
|
-
end
|
34
|
-
rescue Exception => error # rubocop:disable Lint/RescueException
|
35
|
-
transaction.set_error(error)
|
36
|
-
raise error
|
37
|
-
ensure
|
38
|
-
transaction.set_action_if_nil(env["appsignal.route"] || "unknown")
|
39
|
-
transaction.set_metadata("path", request.path)
|
40
|
-
transaction.set_metadata("method", request.request_method)
|
41
|
-
transaction.set_http_or_background_queue_start
|
42
|
-
Appsignal::Transaction.complete_current!
|
43
|
-
end
|
14
|
+
def add_transaction_metadata_after(transaction, request)
|
15
|
+
super
|
16
|
+
transaction.set_action_if_nil("unknown")
|
44
17
|
end
|
45
18
|
end
|
46
19
|
end
|
@@ -28,53 +28,29 @@ module Appsignal
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
class SinatraBaseInstrumentation
|
31
|
+
class SinatraBaseInstrumentation < AbstractMiddleware
|
32
32
|
attr_reader :raise_errors_on
|
33
33
|
|
34
34
|
def initialize(app, options = {})
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
options[:request_class] ||= Sinatra::Request
|
36
|
+
options[:params_method] ||= :params
|
37
|
+
options[:instrument_span_name] ||= "process_action.sinatra"
|
38
|
+
super
|
39
|
+
@raise_errors_on = raise_errors?(app)
|
39
40
|
end
|
40
41
|
|
41
|
-
|
42
|
-
if Appsignal.active?
|
43
|
-
call_with_appsignal_monitoring(env)
|
44
|
-
else
|
45
|
-
@app.call(env)
|
46
|
-
end
|
47
|
-
end
|
42
|
+
private
|
48
43
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
request,
|
57
|
-
options
|
58
|
-
)
|
59
|
-
begin
|
60
|
-
Appsignal.instrument("process_action.sinatra") do
|
61
|
-
@app.call(env)
|
62
|
-
end
|
63
|
-
rescue Exception => error # rubocop:disable Lint/RescueException
|
64
|
-
transaction.set_error(error)
|
65
|
-
raise error
|
66
|
-
ensure
|
67
|
-
# If raise_error is off versions of Sinatra don't raise errors, but store
|
68
|
-
# them in the sinatra.error env var.
|
69
|
-
if !raise_errors_on && env["sinatra.error"] && !env["sinatra.skip_appsignal_error"]
|
70
|
-
transaction.set_error(env["sinatra.error"])
|
71
|
-
end
|
72
|
-
transaction.set_action_if_nil(action_name(env))
|
73
|
-
transaction.set_metadata("path", request.path)
|
74
|
-
transaction.set_metadata("method", request.request_method)
|
75
|
-
transaction.set_http_or_background_queue_start
|
76
|
-
Appsignal::Transaction.complete_current!
|
44
|
+
def add_transaction_metadata_after(transaction, request)
|
45
|
+
env = request.env
|
46
|
+
transaction.set_action_if_nil(action_name(env))
|
47
|
+
# If raise_error is off versions of Sinatra don't raise errors, but store
|
48
|
+
# them in the sinatra.error env var.
|
49
|
+
if !raise_errors_on && env["sinatra.error"] && !env["sinatra.skip_appsignal_error"]
|
50
|
+
transaction.set_error(env["sinatra.error"])
|
77
51
|
end
|
52
|
+
|
53
|
+
super
|
78
54
|
end
|
79
55
|
|
80
56
|
def action_name(env)
|
@@ -88,8 +64,6 @@ module Appsignal
|
|
88
64
|
end
|
89
65
|
end
|
90
66
|
|
91
|
-
private
|
92
|
-
|
93
67
|
def raise_errors?(app)
|
94
68
|
app.respond_to?(:settings) &&
|
95
69
|
app.settings.respond_to?(:raise_errors) &&
|
data/lib/appsignal/version.rb
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -326,6 +326,7 @@ require "appsignal/garbage_collection"
|
|
326
326
|
require "appsignal/integrations/railtie" if defined?(::Rails)
|
327
327
|
require "appsignal/transaction"
|
328
328
|
require "appsignal/version"
|
329
|
+
require "appsignal/rack/abstract_middleware"
|
329
330
|
require "appsignal/rack/generic_instrumentation"
|
330
331
|
require "appsignal/rack/event_handler"
|
331
332
|
require "appsignal/transmitter"
|
@@ -187,6 +187,7 @@ describe Appsignal::Config do
|
|
187
187
|
:send_environment_metadata => true,
|
188
188
|
:send_params => true,
|
189
189
|
:send_session_data => true,
|
190
|
+
:sidekiq_report_errors => "all",
|
190
191
|
:transaction_debug_mode => false
|
191
192
|
)
|
192
193
|
end
|
@@ -583,6 +584,33 @@ describe Appsignal::Config do
|
|
583
584
|
end
|
584
585
|
end
|
585
586
|
end
|
587
|
+
|
588
|
+
context "sidekiq_report_errors" do
|
589
|
+
let(:config_options) { { :sidekiq_report_errors => "discard" } }
|
590
|
+
before do
|
591
|
+
if Appsignal::Hooks::SidekiqHook.instance_variable_defined?(:@version_5_1_or_higher)
|
592
|
+
Appsignal::Hooks::SidekiqHook.remove_instance_variable(:@version_5_1_or_higher)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
context "when Sidekiq >= 5.1 and 'discard'" do
|
597
|
+
before { stub_const("Sidekiq::VERSION", "5.1.0") }
|
598
|
+
|
599
|
+
it "does not override the sidekiq_report_errors value" do
|
600
|
+
expect(config[:sidekiq_report_errors]).to eq("discard")
|
601
|
+
expect(config.override_config[:sidekiq_report_errors]).to be_nil
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
context "when Sidekiq < 5.1 and 'discard'" do
|
606
|
+
before { stub_const("Sidekiq::VERSION", "5.0.0") }
|
607
|
+
|
608
|
+
it "sets sidekiq_report_errors to 'all'" do
|
609
|
+
expect(config[:sidekiq_report_errors]).to eq("all")
|
610
|
+
expect(config.override_config[:sidekiq_report_errors]).to eq("all")
|
611
|
+
end
|
612
|
+
end
|
613
|
+
end
|
586
614
|
end
|
587
615
|
|
588
616
|
describe "config keys" do
|