appsignal 3.9.1-java → 3.9.3-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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3135 -0
- data/.rubocop.yml +28 -20
- data/.rubocop_todo.yml +7 -33
- data/CHANGELOG.md +58 -0
- data/Rakefile +79 -64
- data/appsignal.gemspec +1 -1
- data/build_matrix.yml +109 -179
- data/ext/base.rb +1 -1
- data/gemfiles/hanami-2.1.gemfile +7 -0
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +1 -1
- data/lib/appsignal/demo.rb +0 -1
- data/lib/appsignal/environment.rb +5 -1
- data/lib/appsignal/extension/jruby.rb +1 -1
- data/lib/appsignal/helpers/instrumentation.rb +3 -3
- data/lib/appsignal/hooks/active_job.rb +2 -1
- data/lib/appsignal/integrations/action_cable.rb +1 -1
- data/lib/appsignal/integrations/grape.rb +19 -47
- data/lib/appsignal/integrations/hanami.rb +27 -41
- data/lib/appsignal/integrations/padrino.rb +46 -43
- data/lib/appsignal/integrations/railtie.rb +1 -4
- data/lib/appsignal/integrations/resque.rb +1 -1
- data/lib/appsignal/integrations/sidekiq.rb +2 -4
- data/lib/appsignal/integrations/sinatra.rb +7 -2
- data/lib/appsignal/probes/gvl.rb +24 -2
- data/lib/appsignal/probes/sidekiq.rb +1 -1
- data/lib/appsignal/probes.rb +1 -1
- data/lib/appsignal/rack/abstract_middleware.rb +62 -28
- data/lib/appsignal/rack/event_handler.rb +37 -26
- data/lib/appsignal/rack/grape_middleware.rb +40 -0
- data/lib/appsignal/rack/hanami_middleware.rb +20 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +14 -56
- data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +34 -33
- data/spec/.rubocop.yml +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
- data/spec/lib/appsignal/cli/install_spec.rb +3 -3
- data/spec/lib/appsignal/config_spec.rb +7 -5
- data/spec/lib/appsignal/demo_spec.rb +38 -41
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
- data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
- data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
- data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
- data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
- data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
- data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
- data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
- data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
- data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
- data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
- data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
- data/spec/lib/appsignal/integrations/hanami_spec.rb +126 -64
- data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
- data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
- data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
- data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
- data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
- data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +8 -3
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
- data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
- data/spec/lib/appsignal/probes_spec.rb +7 -4
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
- data/spec/lib/appsignal/rack/event_handler_spec.rb +151 -69
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
- data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +36 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
- data/spec/lib/appsignal/transaction_spec.rb +79 -93
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
- data/spec/lib/appsignal_spec.rb +363 -342
- data/spec/support/hanami/hanami_app.rb +1 -3
- data/spec/support/helpers/dependency_helper.rb +6 -1
- data/spec/support/helpers/std_streams_helper.rb +1 -1
- data/spec/support/helpers/transaction_helpers.rb +8 -0
- data/spec/support/matchers/transaction.rb +185 -0
- data/spec/support/mocks/dummy_app.rb +20 -0
- data/spec/support/shared_examples/instrument.rb +17 -12
- data/spec/support/testing.rb +18 -9
- metadata +17 -10
- data/.semaphore/semaphore.yml +0 -2347
- data/script/lint_git +0 -22
- data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
- data/spec/support/matchers/be_completed.rb +0 -5
- /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
|
@@ -12,63 +12,66 @@ module Appsignal
|
|
|
12
12
|
root = Padrino.mounted_root
|
|
13
13
|
Appsignal.config = Appsignal::Config.new(root, Padrino.env)
|
|
14
14
|
|
|
15
|
-
Appsignal.start_logger
|
|
16
15
|
Appsignal.start
|
|
17
16
|
end
|
|
18
17
|
end
|
|
19
18
|
end
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
module Appsignal
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
module Appsignal
|
|
22
|
+
module Integrations
|
|
23
|
+
module PadrinoIntegration
|
|
24
|
+
def route!(base = settings, pass_block = nil)
|
|
25
|
+
return super if !Appsignal.active? || env["sinatra.static_file"]
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
transaction = Appsignal::Transaction.create(
|
|
28
|
+
SecureRandom.uuid,
|
|
29
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
|
30
|
+
request
|
|
31
|
+
)
|
|
32
|
+
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
|
|
39
|
+
ensure
|
|
40
|
+
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
|
+
end
|
|
34
46
|
end
|
|
35
|
-
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
36
|
-
transaction.set_error(error)
|
|
37
|
-
raise error
|
|
38
|
-
ensure
|
|
39
|
-
transaction.set_action_if_nil(get_payload_action(request))
|
|
40
|
-
transaction.set_metadata("path", request.path)
|
|
41
|
-
transaction.set_metadata("method", request.request_method)
|
|
42
|
-
transaction.set_http_or_background_queue_start
|
|
43
|
-
Appsignal::Transaction.complete_current!
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
private
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
def get_payload_action(request)
|
|
51
|
+
# Short-circut is there's no request object to obtain information from
|
|
52
|
+
return settings.name.to_s unless request
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
# Newer versions expose the action / controller on the request class.
|
|
55
|
+
# Newer versions also still expose a route_obj so we must prioritize the
|
|
56
|
+
# action/fullpath methods.
|
|
57
|
+
# The `request.action` and `request.controller` values are `nil` when a
|
|
58
|
+
# endpoint is not found, `""` if not specified by the user.
|
|
59
|
+
controller_name = request.controller if request.respond_to?(:controller)
|
|
60
|
+
action_name = request.action if request.respond_to?(:action)
|
|
61
|
+
action_name ||= ""
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
# Older versions of Padrino work with a route object
|
|
66
|
+
if request.respond_to?(:route_obj) && request.route_obj
|
|
67
|
+
return "#{settings.name}:#{request.route_obj.original_path}"
|
|
68
|
+
end
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
# Fall back to the application name if we haven't found an action name in
|
|
71
|
+
# any previous methods.
|
|
72
|
+
"#{settings.name}#unknown"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
|
|
@@ -26,9 +26,6 @@ module Appsignal
|
|
|
26
26
|
:log_path => Rails.root.join("log")
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
# Start logger
|
|
30
|
-
Appsignal.start_logger
|
|
31
|
-
|
|
32
29
|
app.middleware.insert(
|
|
33
30
|
0,
|
|
34
31
|
::Rack::Events,
|
|
@@ -71,7 +68,7 @@ module Appsignal
|
|
|
71
68
|
transaction.set_action(action_name) if action_name
|
|
72
69
|
transaction.set_metadata("path", path)
|
|
73
70
|
transaction.set_metadata("method", method)
|
|
74
|
-
transaction.params
|
|
71
|
+
transaction.set_params_if_nil(params)
|
|
75
72
|
transaction.set_sample_data("custom_data", custom_data) if custom_data
|
|
76
73
|
|
|
77
74
|
tags[:severity] = severity
|
|
@@ -25,7 +25,7 @@ module Appsignal
|
|
|
25
25
|
ResqueHelpers.arguments(payload),
|
|
26
26
|
Appsignal.config[:filter_parameters]
|
|
27
27
|
)
|
|
28
|
-
transaction.
|
|
28
|
+
transaction.set_params_if_nil(args)
|
|
29
29
|
transaction.set_tags("queue" => queue)
|
|
30
30
|
|
|
31
31
|
Appsignal::Transaction.complete_current!
|
|
@@ -45,7 +45,7 @@ module Appsignal
|
|
|
45
45
|
)
|
|
46
46
|
transaction.set_action_if_nil("SidekiqInternal")
|
|
47
47
|
transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
|
|
48
|
-
transaction.
|
|
48
|
+
transaction.set_params_if_nil(:jobstr => sidekiq_context[:jobstr])
|
|
49
49
|
transaction.set_error(exception)
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -83,9 +83,7 @@ module Appsignal
|
|
|
83
83
|
raise exception
|
|
84
84
|
ensure
|
|
85
85
|
if transaction
|
|
86
|
-
|
|
87
|
-
transaction.params = params if params
|
|
88
|
-
|
|
86
|
+
transaction.set_params_if_nil(filtered_arguments(item))
|
|
89
87
|
transaction.set_http_or_background_queue_start
|
|
90
88
|
Appsignal::Transaction.complete_current! unless exception
|
|
91
89
|
|
|
@@ -12,8 +12,13 @@ unless Appsignal.active?
|
|
|
12
12
|
app_settings.environment
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
Appsignal.start_logger
|
|
16
15
|
Appsignal.start
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
|
|
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
|
data/lib/appsignal/probes/gvl.rb
CHANGED
|
@@ -25,6 +25,11 @@ module Appsignal
|
|
|
25
25
|
Appsignal.internal_logger.debug("Initializing GVL probe")
|
|
26
26
|
@appsignal = appsignal
|
|
27
27
|
@gvl_tools = gvl_tools
|
|
28
|
+
|
|
29
|
+
# Store the process name and ID at initialization time
|
|
30
|
+
# to avoid picking up changes to the process name at runtime
|
|
31
|
+
@process_name = File.basename($PROGRAM_NAME).split.first || "[unknown process]"
|
|
32
|
+
@process_id = Process.pid
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
def call
|
|
@@ -39,13 +44,30 @@ module Appsignal
|
|
|
39
44
|
gauge_delta :gvl_global_timer, monotonic_time_ns do |time_delta_ns|
|
|
40
45
|
if time_delta_ns > 0
|
|
41
46
|
time_delta_ms = time_delta_ns / 1_000_000
|
|
42
|
-
|
|
47
|
+
set_gauges_with_hostname_and_process(
|
|
48
|
+
"gvl_global_timer",
|
|
49
|
+
time_delta_ms
|
|
50
|
+
)
|
|
43
51
|
end
|
|
44
52
|
end
|
|
45
53
|
end
|
|
46
54
|
|
|
47
55
|
def probe_waiting_threads
|
|
48
|
-
|
|
56
|
+
set_gauges_with_hostname_and_process(
|
|
57
|
+
"gvl_waiting_threads",
|
|
58
|
+
@gvl_tools::WaitingThreads.count
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def set_gauges_with_hostname_and_process(name, value)
|
|
63
|
+
set_gauge_with_hostname(name, value, {
|
|
64
|
+
:process_name => @process_name,
|
|
65
|
+
:process_id => @process_id
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
# Also set the gauge without the process name and ID for
|
|
69
|
+
# compatibility with existing automated dashboards
|
|
70
|
+
set_gauge_with_hostname(name, value)
|
|
49
71
|
end
|
|
50
72
|
end
|
|
51
73
|
end
|
|
@@ -47,7 +47,7 @@ module Appsignal
|
|
|
47
47
|
# @api private
|
|
48
48
|
def self.dependencies_present?
|
|
49
49
|
return true if sidekiq7_and_greater?
|
|
50
|
-
return unless defined?(::Redis::VERSION) # Sidekiq <= 6
|
|
50
|
+
return false unless defined?(::Redis::VERSION) # Sidekiq <= 6
|
|
51
51
|
|
|
52
52
|
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
|
|
53
53
|
end
|
data/lib/appsignal/probes.rb
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
require "rack"
|
|
4
4
|
|
|
5
5
|
module Appsignal
|
|
6
|
-
# @api private
|
|
7
6
|
module Rack
|
|
7
|
+
# @api private
|
|
8
8
|
class AbstractMiddleware
|
|
9
|
+
DEFAULT_ERROR_REPORTING = :default
|
|
10
|
+
|
|
9
11
|
def initialize(app, options = {})
|
|
10
12
|
Appsignal.internal_logger.debug "Initializing #{self.class}"
|
|
11
13
|
@app = app
|
|
@@ -13,6 +15,7 @@ module Appsignal
|
|
|
13
15
|
@request_class = options.fetch(:request_class, ::Rack::Request)
|
|
14
16
|
@params_method = options.fetch(:params_method, :params)
|
|
15
17
|
@instrument_span_name = options.fetch(:instrument_span_name, "process.abstract")
|
|
18
|
+
@report_errors = options.fetch(:report_errors, DEFAULT_ERROR_REPORTING)
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def call(env)
|
|
@@ -32,15 +35,31 @@ module Appsignal
|
|
|
32
35
|
)
|
|
33
36
|
end
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
if wrapped_instrumentation
|
|
37
|
-
instrument_wrapped_request(request, transaction)
|
|
38
|
-
else
|
|
38
|
+
unless wrapped_instrumentation
|
|
39
39
|
# Set transaction on the request environment so other nested
|
|
40
40
|
# middleware can detect if there is parent instrumentation
|
|
41
41
|
# middleware active.
|
|
42
42
|
env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
|
|
43
|
-
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
add_transaction_metadata_before(transaction, request)
|
|
47
|
+
# Report errors if the :report_errors option is set to true or when
|
|
48
|
+
# there is no parent instrumentation that can rescue and report the error.
|
|
49
|
+
if @report_errors || !wrapped_instrumentation
|
|
50
|
+
instrument_app_call_with_exception_handling(
|
|
51
|
+
request.env,
|
|
52
|
+
transaction,
|
|
53
|
+
wrapped_instrumentation
|
|
54
|
+
)
|
|
55
|
+
else
|
|
56
|
+
instrument_app_call(request.env)
|
|
57
|
+
end
|
|
58
|
+
ensure
|
|
59
|
+
add_transaction_metadata_after(transaction, request)
|
|
60
|
+
|
|
61
|
+
# Complete transaction because this is the top instrumentation middleware.
|
|
62
|
+
Appsignal::Transaction.complete_current! unless wrapped_instrumentation
|
|
44
63
|
end
|
|
45
64
|
else
|
|
46
65
|
@app.call(env)
|
|
@@ -56,35 +75,40 @@ module Appsignal
|
|
|
56
75
|
# Either another {GenericInstrumentation} or {EventHandler} is higher in
|
|
57
76
|
# the stack and will report the exception and complete the transaction.
|
|
58
77
|
#
|
|
59
|
-
# @see {#
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
# @see {#instrument_app_call_with_exception_handling}
|
|
79
|
+
def instrument_app_call(env)
|
|
80
|
+
if @instrument_span_name
|
|
81
|
+
Appsignal.instrument(@instrument_span_name) do
|
|
82
|
+
@app.call(env)
|
|
83
|
+
end
|
|
84
|
+
else
|
|
85
|
+
@app.call(env)
|
|
86
|
+
end
|
|
64
87
|
end
|
|
65
88
|
|
|
66
89
|
# Instrument the request fully. This is used by the top instrumentation
|
|
67
90
|
# middleware in the middleware stack. Unlike
|
|
68
|
-
# {#
|
|
91
|
+
# {#instrument_app_call} this will report any exceptions being
|
|
69
92
|
# raised.
|
|
70
93
|
#
|
|
71
|
-
# @see {#
|
|
72
|
-
def
|
|
73
|
-
instrument_app_call(
|
|
94
|
+
# @see {#instrument_app_call}
|
|
95
|
+
def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
|
|
96
|
+
instrument_app_call(env)
|
|
74
97
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
75
|
-
|
|
98
|
+
report_errors =
|
|
99
|
+
if @report_errors == DEFAULT_ERROR_REPORTING
|
|
100
|
+
# If there's no parent transaction, report the error
|
|
101
|
+
!wrapped_instrumentation
|
|
102
|
+
elsif @report_errors.respond_to?(:call)
|
|
103
|
+
# If the @report_errors option is callable, call it with the
|
|
104
|
+
# request environment so it can determine if the error needs to be
|
|
105
|
+
# reported.
|
|
106
|
+
@report_errors.call(env)
|
|
107
|
+
else
|
|
108
|
+
@report_errors
|
|
109
|
+
end
|
|
110
|
+
transaction.set_error(error) if report_errors
|
|
76
111
|
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
112
|
end
|
|
89
113
|
|
|
90
114
|
# Add metadata to the transaction based on the request environment.
|
|
@@ -101,7 +125,10 @@ module Appsignal
|
|
|
101
125
|
request.env["appsignal.route"] || request.env["appsignal.action"]
|
|
102
126
|
transaction.set_action_if_nil(default_action)
|
|
103
127
|
transaction.set_metadata("path", request.path)
|
|
104
|
-
|
|
128
|
+
|
|
129
|
+
request_method = request_method_for(request)
|
|
130
|
+
transaction.set_metadata("method", request_method) if request_method
|
|
131
|
+
|
|
105
132
|
transaction.set_params_if_nil(params_for(request))
|
|
106
133
|
transaction.set_http_or_background_queue_start
|
|
107
134
|
end
|
|
@@ -118,6 +145,13 @@ module Appsignal
|
|
|
118
145
|
nil
|
|
119
146
|
end
|
|
120
147
|
|
|
148
|
+
def request_method_for(request)
|
|
149
|
+
request.request_method
|
|
150
|
+
rescue => error
|
|
151
|
+
Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
|
|
121
155
|
def request_for(env)
|
|
122
156
|
@request_class.new(env)
|
|
123
157
|
end
|
|
@@ -4,8 +4,10 @@ module Appsignal
|
|
|
4
4
|
module Rack
|
|
5
5
|
APPSIGNAL_TRANSACTION = "appsignal.transaction"
|
|
6
6
|
APPSIGNAL_EVENT_HANDLER_ID = "appsignal.event_handler_id"
|
|
7
|
+
APPSIGNAL_EVENT_HANDLER_HAS_ERROR = "appsignal.event_handler.error"
|
|
7
8
|
RACK_AFTER_REPLY = "rack.after_reply"
|
|
8
9
|
|
|
10
|
+
# @api private
|
|
9
11
|
class EventHandler
|
|
10
12
|
include ::Rack::Events::Abstract
|
|
11
13
|
|
|
@@ -42,22 +44,22 @@ module Appsignal
|
|
|
42
44
|
|
|
43
45
|
request.env[RACK_AFTER_REPLY] ||= []
|
|
44
46
|
request.env[RACK_AFTER_REPLY] << proc do
|
|
47
|
+
next unless event_handler.request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
|
48
|
+
|
|
45
49
|
Appsignal::Rack::EventHandler
|
|
46
50
|
.safe_execution("Appsignal::Rack::EventHandler's after_reply") do
|
|
47
|
-
next unless event_handler.request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
|
48
|
-
|
|
49
51
|
transaction.finish_event("process_request.rack", "", "")
|
|
50
52
|
transaction.set_http_or_background_queue_start
|
|
51
|
-
|
|
52
|
-
# Make sure the current transaction is always closed when the request
|
|
53
|
-
# is finished. This is a fallback for in case the `on_finish`
|
|
54
|
-
# callback is not called. This is supported by servers like Puma and
|
|
55
|
-
# Unicorn.
|
|
56
|
-
#
|
|
57
|
-
# The EventHandler.on_finish callback should be called first, this is
|
|
58
|
-
# just a fallback if that doesn't get called.
|
|
59
|
-
Appsignal::Transaction.complete_current!
|
|
60
53
|
end
|
|
54
|
+
|
|
55
|
+
# Make sure the current transaction is always closed when the request
|
|
56
|
+
# is finished. This is a fallback for in case the `on_finish`
|
|
57
|
+
# callback is not called. This is supported by servers like Puma and
|
|
58
|
+
# Unicorn.
|
|
59
|
+
#
|
|
60
|
+
# The EventHandler.on_finish callback should be called first, this is
|
|
61
|
+
# just a fallback if that doesn't get called.
|
|
62
|
+
Appsignal::Transaction.complete_current!
|
|
61
63
|
end
|
|
62
64
|
transaction.start_event
|
|
63
65
|
end
|
|
@@ -70,31 +72,40 @@ module Appsignal
|
|
|
70
72
|
transaction = request.env[APPSIGNAL_TRANSACTION]
|
|
71
73
|
return unless transaction
|
|
72
74
|
|
|
75
|
+
request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] = true
|
|
73
76
|
transaction.set_error(error)
|
|
74
77
|
end
|
|
75
78
|
end
|
|
76
79
|
|
|
77
80
|
def on_finish(request, response)
|
|
78
|
-
|
|
79
|
-
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
|
81
|
+
return unless request_handler?(request.env[APPSIGNAL_EVENT_HANDLER_ID])
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
transaction = request.env[APPSIGNAL_TRANSACTION]
|
|
84
|
+
return unless transaction
|
|
83
85
|
|
|
86
|
+
self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
|
|
84
87
|
transaction.finish_event("process_request.rack", "", "")
|
|
85
|
-
transaction.set_tags(:response_status => response.status)
|
|
86
88
|
transaction.set_http_or_background_queue_start
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
response_status =
|
|
90
|
+
if response
|
|
91
|
+
response.status
|
|
92
|
+
elsif request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] == true
|
|
93
|
+
500
|
|
94
|
+
end
|
|
95
|
+
if response_status
|
|
96
|
+
transaction.set_tags(:response_status => response_status)
|
|
97
|
+
Appsignal.increment_counter(
|
|
98
|
+
:response_status,
|
|
99
|
+
1,
|
|
100
|
+
:status => response_status,
|
|
101
|
+
:namespace => format_namespace(transaction.namespace)
|
|
102
|
+
)
|
|
103
|
+
end
|
|
97
104
|
end
|
|
105
|
+
|
|
106
|
+
# Make sure the current transaction is always closed when the request
|
|
107
|
+
# is finished
|
|
108
|
+
Appsignal::Transaction.complete_current!
|
|
98
109
|
end
|
|
99
110
|
|
|
100
111
|
private
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
module Rack
|
|
5
|
+
# @api private
|
|
6
|
+
class GrapeMiddleware < Appsignal::Rack::AbstractMiddleware
|
|
7
|
+
def initialize(app, options = {})
|
|
8
|
+
options[:instrument_span_name] = "process_request.grape"
|
|
9
|
+
options[:report_errors] = lambda { |env| !env["grape.skip_appsignal_error"] }
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def add_transaction_metadata_after(transaction, request)
|
|
16
|
+
endpoint = request.env["api.endpoint"]
|
|
17
|
+
unless endpoint&.options
|
|
18
|
+
super
|
|
19
|
+
return
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
options = endpoint.options
|
|
23
|
+
request_method = options[:method].first.to_s.upcase
|
|
24
|
+
klass = options[:for]
|
|
25
|
+
namespace = endpoint.namespace
|
|
26
|
+
namespace = "" if namespace == "/"
|
|
27
|
+
|
|
28
|
+
path = options[:path].first.to_s
|
|
29
|
+
path = "/#{path}" if path[0] != "/"
|
|
30
|
+
path = "#{namespace}#{path}"
|
|
31
|
+
|
|
32
|
+
transaction.set_action_if_nil("#{request_method}::#{klass}##{path}")
|
|
33
|
+
|
|
34
|
+
super
|
|
35
|
+
|
|
36
|
+
transaction.set_metadata("path", path)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
module Rack
|
|
5
|
+
# @api private
|
|
6
|
+
class HanamiMiddleware < AbstractMiddleware
|
|
7
|
+
def initialize(app, options = {})
|
|
8
|
+
options[:params_method] ||= :params
|
|
9
|
+
options[:instrument_span_name] ||= "process_action.hanami"
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def params_for(request)
|
|
16
|
+
::Hanami::Action.params_class.new(request.env).to_h
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -3,69 +3,27 @@
|
|
|
3
3
|
require "rack"
|
|
4
4
|
|
|
5
5
|
module Appsignal
|
|
6
|
-
# @api private
|
|
7
6
|
module Rack
|
|
8
|
-
|
|
7
|
+
# @api private
|
|
8
|
+
class RailsInstrumentation < Appsignal::Rack::AbstractMiddleware
|
|
9
9
|
def initialize(app, options = {})
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
options[:request_class] ||= ActionDispatch::Request
|
|
11
|
+
options[:params_method] ||= :filtered_parameters
|
|
12
|
+
options[:instrument_span_name] = nil
|
|
13
|
+
options[:report_errors] = true
|
|
14
|
+
super
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
if Appsignal.active?
|
|
17
|
-
call_with_appsignal_monitoring(env)
|
|
18
|
-
else
|
|
19
|
-
@app.call(env)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def call_with_appsignal_monitoring(env)
|
|
24
|
-
request = ActionDispatch::Request.new(env)
|
|
25
|
-
transaction = env.fetch(
|
|
26
|
-
Appsignal::Rack::APPSIGNAL_TRANSACTION,
|
|
27
|
-
Appsignal::Transaction::NilTransaction.new
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
begin
|
|
31
|
-
transaction.params = fetch_params(request)
|
|
32
|
-
|
|
33
|
-
@app.call(env)
|
|
34
|
-
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
35
|
-
transaction.set_error(error)
|
|
36
|
-
raise error
|
|
37
|
-
ensure
|
|
38
|
-
controller = env["action_controller.instance"]
|
|
39
|
-
if controller
|
|
40
|
-
transaction.set_action_if_nil("#{controller.class}##{controller.action_name}")
|
|
41
|
-
end
|
|
42
|
-
request_id = fetch_request_id(env)
|
|
43
|
-
transaction.set_tags(:request_id => request_id) if request_id
|
|
44
|
-
transaction.set_metadata("path", request.path)
|
|
45
|
-
request_method = fetch_request_method(request)
|
|
46
|
-
transaction.set_metadata("method", request_method) if request_method
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def fetch_request_id(env)
|
|
51
|
-
env["action_dispatch.request_id"]
|
|
52
|
-
end
|
|
17
|
+
private
|
|
53
18
|
|
|
54
|
-
def
|
|
55
|
-
|
|
19
|
+
def add_transaction_metadata_after(transaction, request)
|
|
20
|
+
controller = request.env["action_controller.instance"]
|
|
21
|
+
transaction.set_action_if_nil("#{controller.class}##{controller.action_name}") if controller
|
|
56
22
|
|
|
57
|
-
request.
|
|
58
|
-
|
|
59
|
-
# Getting params from the request has been know to fail.
|
|
60
|
-
Appsignal.internal_logger.debug "Exception while getting Rails params: #{error}"
|
|
61
|
-
nil
|
|
62
|
-
end
|
|
23
|
+
request_id = request.env["action_dispatch.request_id"]
|
|
24
|
+
transaction.set_tags(:request_id => request_id) if request_id
|
|
63
25
|
|
|
64
|
-
|
|
65
|
-
request.request_method
|
|
66
|
-
rescue => error
|
|
67
|
-
Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
|
|
68
|
-
nil
|
|
26
|
+
super
|
|
69
27
|
end
|
|
70
28
|
end
|
|
71
29
|
end
|