appsignal 3.10.0-java → 3.12.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +197 -0
- data/Gemfile +1 -0
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +204 -130
- data/lib/appsignal/demo.rb +16 -26
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
- data/lib/appsignal/event_formatter.rb +3 -2
- data/lib/appsignal/helpers/instrumentation.rb +331 -19
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +14 -8
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/shoryuken.rb +3 -63
- data/lib/appsignal/integrations/action_cable.rb +5 -7
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
- data/lib/appsignal/integrations/data_mapper.rb +1 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
- data/lib/appsignal/integrations/dry_monitor.rb +1 -0
- data/lib/appsignal/integrations/excon.rb +1 -0
- data/lib/appsignal/integrations/grape.rb +7 -0
- data/lib/appsignal/integrations/hanami.rb +8 -43
- data/lib/appsignal/integrations/http.rb +1 -0
- data/lib/appsignal/integrations/net_http.rb +1 -0
- data/lib/appsignal/integrations/object.rb +6 -0
- data/lib/appsignal/integrations/padrino.rb +8 -73
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +36 -14
- data/lib/appsignal/integrations/rake.rb +1 -5
- data/lib/appsignal/integrations/redis.rb +1 -0
- data/lib/appsignal/integrations/redis_client.rb +1 -0
- data/lib/appsignal/integrations/resque.rb +2 -5
- data/lib/appsignal/integrations/shoryuken.rb +75 -0
- data/lib/appsignal/integrations/sidekiq.rb +7 -15
- data/lib/appsignal/integrations/sinatra.rb +8 -19
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +2 -5
- data/lib/appsignal/loaders/grape.rb +13 -0
- data/lib/appsignal/loaders/hanami.rb +40 -0
- data/lib/appsignal/loaders/padrino.rb +68 -0
- data/lib/appsignal/loaders/sinatra.rb +24 -0
- data/lib/appsignal/loaders.rb +92 -0
- data/lib/appsignal/logger.rb +7 -3
- data/lib/appsignal/probes/helpers.rb +1 -0
- data/lib/appsignal/probes/mri.rb +1 -0
- data/lib/appsignal/probes/sidekiq.rb +1 -0
- data/lib/appsignal/probes.rb +3 -0
- data/lib/appsignal/rack/abstract_middleware.rb +20 -13
- data/lib/appsignal/rack/event_handler.rb +44 -13
- data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
- data/lib/appsignal/rack/grape_middleware.rb +2 -1
- data/lib/appsignal/rack/streaming_listener.rb +1 -0
- data/lib/appsignal/rack.rb +35 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +308 -101
- data/lib/appsignal/utils/data.rb +0 -1
- data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
- data/lib/appsignal/utils/integration_logger.rb +0 -13
- data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
- data/lib/appsignal/utils/json.rb +0 -1
- data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
- data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
- data/lib/appsignal/utils.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +169 -14
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
- data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
- data/spec/lib/appsignal/config_spec.rb +291 -44
- data/spec/lib/appsignal/demo_spec.rb +1 -2
- data/spec/lib/appsignal/environment_spec.rb +4 -2
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
- data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
- data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
- data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
- data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
- data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
- data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
- data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
- data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
- data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
- data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
- data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
- data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
- data/spec/lib/appsignal/loaders_spec.rb +137 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/probes_spec.rb +6 -5
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
- data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
- data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/span_spec.rb +1 -3
- data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
- data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
- data/spec/lib/appsignal_spec.rb +601 -36
- data/spec/lib/puma/appsignal_spec.rb +0 -3
- data/spec/spec_helper.rb +5 -4
- data/spec/support/helpers/config_helpers.rb +2 -1
- data/spec/support/helpers/loader_helper.rb +21 -0
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
- data/spec/support/testing.rb +47 -1
- metadata +19 -2
|
@@ -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
|
|
87
|
-
|
|
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"
|
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "appsignal"
|
|
4
|
-
require "appsignal/rack/sinatra_instrumentation"
|
|
5
4
|
|
|
6
|
-
Appsignal.
|
|
5
|
+
Appsignal::Utils::StdoutAndLoggerMessage.warning(
|
|
6
|
+
"The 'require \"appsignal/integrations/sinatra\"' file require integration " \
|
|
7
|
+
"method is deprecated. " \
|
|
8
|
+
"Please follow the Sinatra setup guide in our docs for the new method: " \
|
|
9
|
+
"https://docs.appsignal.com/ruby/integrations/sinatra.html"
|
|
10
|
+
)
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Appsignal.config = Appsignal::Config.new(
|
|
11
|
-
app_settings.root || Dir.pwd,
|
|
12
|
-
app_settings.environment
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
Appsignal.start
|
|
16
|
-
end
|
|
17
|
-
|
|
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
|
|
12
|
+
Appsignal.load(:sinatra)
|
|
13
|
+
Appsignal.start
|
|
@@ -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
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
module Loaders
|
|
5
|
+
class HanamiLoader < Loader
|
|
6
|
+
register :hanami
|
|
7
|
+
|
|
8
|
+
def on_load
|
|
9
|
+
hanami_app_config = ::Hanami.app.config
|
|
10
|
+
register_config_defaults(
|
|
11
|
+
:root_path => hanami_app_config.root.to_s,
|
|
12
|
+
:env => hanami_app_config.env
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def on_start
|
|
17
|
+
require "appsignal/rack/hanami_middleware"
|
|
18
|
+
|
|
19
|
+
hanami_app_config = ::Hanami.app.config
|
|
20
|
+
hanami_app_config.middleware.use(
|
|
21
|
+
::Rack::Events,
|
|
22
|
+
[Appsignal::Rack::EventHandler.new]
|
|
23
|
+
)
|
|
24
|
+
hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
|
|
25
|
+
|
|
26
|
+
::Hanami::Action.prepend Appsignal::Loaders::HanamiLoader::HanamiIntegration
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module HanamiIntegration
|
|
30
|
+
def call(env)
|
|
31
|
+
super
|
|
32
|
+
ensure
|
|
33
|
+
transaction = env[::Appsignal::Rack::APPSIGNAL_TRANSACTION]
|
|
34
|
+
|
|
35
|
+
transaction&.set_action_if_nil(self.class.name)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
module Loaders
|
|
5
|
+
class PadrinoLoader < Loader
|
|
6
|
+
register :padrino
|
|
7
|
+
|
|
8
|
+
def on_load
|
|
9
|
+
register_config_defaults(
|
|
10
|
+
:root_path => Padrino.mounted_root,
|
|
11
|
+
:env => Padrino.env
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def on_start
|
|
16
|
+
require "appsignal/rack/sinatra_instrumentation"
|
|
17
|
+
|
|
18
|
+
Padrino::Application.prepend(Appsignal::Loaders::PadrinoLoader::PadrinoIntegration)
|
|
19
|
+
|
|
20
|
+
Padrino.before_load do
|
|
21
|
+
Padrino.use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
|
|
22
|
+
Padrino.use Appsignal::Rack::SinatraBaseInstrumentation,
|
|
23
|
+
:instrument_event_name => "process_action.padrino"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module PadrinoIntegration
|
|
28
|
+
def route!(base = settings, pass_block = nil)
|
|
29
|
+
return super if !Appsignal.active? || env["sinatra.static_file"]
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
super
|
|
33
|
+
ensure
|
|
34
|
+
transaction = Appsignal::Transaction.current
|
|
35
|
+
transaction.set_action_if_nil(get_payload_action(request))
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def get_payload_action(request)
|
|
42
|
+
# Short-circuit is there's no request object to obtain information from
|
|
43
|
+
return settings.name.to_s unless request
|
|
44
|
+
|
|
45
|
+
# Newer versions expose the action / controller on the request class.
|
|
46
|
+
# Newer versions also still expose a route_obj so we must prioritize the
|
|
47
|
+
# action/fullpath methods.
|
|
48
|
+
# The `request.action` and `request.controller` values are `nil` when a
|
|
49
|
+
# endpoint is not found, `""` if not specified by the user.
|
|
50
|
+
controller_name = request.controller if request.respond_to?(:controller)
|
|
51
|
+
action_name = request.action if request.respond_to?(:action)
|
|
52
|
+
action_name ||= ""
|
|
53
|
+
|
|
54
|
+
return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
|
|
55
|
+
|
|
56
|
+
# Older versions of Padrino work with a route object
|
|
57
|
+
if request.respond_to?(:route_obj) && request.route_obj
|
|
58
|
+
return "#{settings.name}:#{request.route_obj.original_path}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Fall back to the application name if we haven't found an action name in
|
|
62
|
+
# any previous methods.
|
|
63
|
+
"#{settings.name}#unknown"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
module Loaders
|
|
5
|
+
class SinatraLoader < Loader
|
|
6
|
+
register :sinatra
|
|
7
|
+
|
|
8
|
+
def on_load
|
|
9
|
+
app_settings = ::Sinatra::Application.settings
|
|
10
|
+
register_config_defaults(
|
|
11
|
+
:root_path => app_settings.root,
|
|
12
|
+
:env => app_settings.environment
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def on_start
|
|
17
|
+
require "appsignal/rack/sinatra_instrumentation"
|
|
18
|
+
|
|
19
|
+
::Sinatra::Base.use(::Rack::Events, [Appsignal::Rack::EventHandler.new])
|
|
20
|
+
::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Appsignal
|
|
4
|
+
# @api private
|
|
5
|
+
module Loaders
|
|
6
|
+
class << self
|
|
7
|
+
def loaders
|
|
8
|
+
@loaders ||= {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def instances
|
|
12
|
+
@instances ||= {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def register(name, klass)
|
|
16
|
+
loaders[name.to_sym] = klass
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def registered?(name)
|
|
20
|
+
loaders.key?(name)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def unregister(name)
|
|
24
|
+
loaders.delete(name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def load(name_str)
|
|
28
|
+
name = name_str.to_sym
|
|
29
|
+
|
|
30
|
+
unless registered?(name)
|
|
31
|
+
require_loader(name)
|
|
32
|
+
unless registered?(name)
|
|
33
|
+
Appsignal.internal_logger
|
|
34
|
+
.warn("No loader found with the name '#{name}'.")
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Appsignal.internal_logger.debug("Loading '#{name}' loader")
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
loader_klass = loaders[name]
|
|
43
|
+
loader = loader_klass.new
|
|
44
|
+
instances[name] = loader
|
|
45
|
+
loader.on_load if loader.respond_to?(:on_load)
|
|
46
|
+
rescue => e
|
|
47
|
+
Appsignal.internal_logger.error(
|
|
48
|
+
"An error occurred while loading the '#{name}' loader: " \
|
|
49
|
+
"#{e.class}: #{e.message}\n#{e.backtrace}"
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def start
|
|
55
|
+
instances.each do |name, instance|
|
|
56
|
+
Appsignal.internal_logger.debug("Starting '#{name}' loader")
|
|
57
|
+
begin
|
|
58
|
+
instance.on_start if instance.respond_to?(:on_start)
|
|
59
|
+
rescue => e
|
|
60
|
+
Appsignal.internal_logger.error(
|
|
61
|
+
"An error occurred while starting the '#{name}' loader: " \
|
|
62
|
+
"#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def require_loader(name)
|
|
71
|
+
require "appsignal/loaders/#{name}"
|
|
72
|
+
rescue LoadError
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Loader
|
|
78
|
+
class << self
|
|
79
|
+
attr_reader :loader_name
|
|
80
|
+
|
|
81
|
+
def register(name)
|
|
82
|
+
@loader_name = name
|
|
83
|
+
Loaders.register(name, self)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def register_config_defaults(options)
|
|
88
|
+
Appsignal::Config.add_loader_defaults(self.class.loader_name, options)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/appsignal/logger.rb
CHANGED
|
@@ -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
|
-
#
|
|
148
|
-
# https://github.com/rails/rails/blob/
|
|
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
|
data/lib/appsignal/probes/mri.rb
CHANGED
data/lib/appsignal/probes.rb
CHANGED
|
@@ -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
|
|
@@ -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
|
|
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
|
|
@@ -94,9 +91,10 @@ module Appsignal
|
|
|
94
91
|
def call_app(env, transaction)
|
|
95
92
|
status, headers, obody = @app.call(env)
|
|
96
93
|
body =
|
|
97
|
-
if
|
|
94
|
+
if env[Appsignal::Rack::APPSIGNAL_RESPONSE_INSTRUMENTED]
|
|
98
95
|
obody
|
|
99
96
|
else
|
|
97
|
+
env[Appsignal::Rack::APPSIGNAL_RESPONSE_INSTRUMENTED] = true
|
|
100
98
|
# Instrument response body and closing of the response body
|
|
101
99
|
Appsignal::Rack::BodyWrapper.wrap(obody, transaction)
|
|
102
100
|
end
|
|
@@ -108,7 +106,7 @@ module Appsignal
|
|
|
108
106
|
# {#instrument_app_call} this will report any exceptions being
|
|
109
107
|
# raised.
|
|
110
108
|
#
|
|
111
|
-
# @see
|
|
109
|
+
# @see #instrument_app_call
|
|
112
110
|
def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
|
|
113
111
|
instrument_app_call(env, transaction)
|
|
114
112
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
@@ -147,7 +145,14 @@ module Appsignal
|
|
|
147
145
|
transaction.set_metadata("method", request_method) if request_method
|
|
148
146
|
|
|
149
147
|
transaction.set_params_if_nil { params_for(request) }
|
|
150
|
-
transaction.
|
|
148
|
+
transaction.set_session_data_if_nil do
|
|
149
|
+
request.session if request.respond_to?(:session)
|
|
150
|
+
end
|
|
151
|
+
transaction.set_headers_if_nil do
|
|
152
|
+
request.env if request.respond_to?(:env)
|
|
153
|
+
end
|
|
154
|
+
queue_start = Appsignal::Rack::Utils.queue_start_from(request.env)
|
|
155
|
+
transaction.set_queue_start(queue_start) if queue_start
|
|
151
156
|
end
|
|
152
157
|
|
|
153
158
|
def params_for(request)
|
|
@@ -155,9 +160,9 @@ module Appsignal
|
|
|
155
160
|
|
|
156
161
|
request.send(@params_method)
|
|
157
162
|
rescue => error
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
Appsignal.internal_logger.error(
|
|
164
|
+
"Exception while fetching params from '#{@request_class}##{@params_method}': " \
|
|
165
|
+
"#{error.class} #{error}"
|
|
161
166
|
)
|
|
162
167
|
nil
|
|
163
168
|
end
|
|
@@ -165,7 +170,9 @@ module Appsignal
|
|
|
165
170
|
def request_method_for(request)
|
|
166
171
|
request.request_method
|
|
167
172
|
rescue => error
|
|
168
|
-
Appsignal.internal_logger.error(
|
|
173
|
+
Appsignal.internal_logger.error(
|
|
174
|
+
"Exception while fetching the HTTP request method: #{error.class}: #{error}"
|
|
175
|
+
)
|
|
169
176
|
nil
|
|
170
177
|
end
|
|
171
178
|
|