skylight 4.3.2 → 5.0.0.beta
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/CHANGELOG.md +14 -5
- data/CONTRIBUTING.md +1 -7
- data/ext/extconf.rb +4 -3
- data/ext/libskylight.yml +5 -6
- data/ext/skylight_native.c +22 -99
- data/lib/skylight.rb +204 -14
- data/lib/skylight/api.rb +7 -3
- data/lib/skylight/cli.rb +4 -3
- data/lib/skylight/cli/doctor.rb +3 -2
- data/lib/skylight/cli/merger.rb +6 -4
- data/lib/skylight/config.rb +603 -126
- data/lib/skylight/deprecation.rb +15 -0
- data/lib/skylight/errors.rb +17 -2
- data/lib/skylight/extensions.rb +99 -0
- data/lib/skylight/extensions/source_location.rb +249 -0
- data/lib/skylight/fanout.rb +0 -0
- data/lib/skylight/formatters/http.rb +19 -0
- data/lib/skylight/gc.rb +109 -0
- data/lib/skylight/helpers.rb +18 -2
- data/lib/skylight/instrumenter.rb +325 -15
- data/lib/skylight/middleware.rb +138 -1
- data/lib/skylight/native.rb +51 -1
- data/lib/skylight/native_ext_fetcher.rb +2 -1
- data/lib/skylight/normalizers.rb +151 -0
- data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
- data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
- data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
- data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
- data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
- data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
- data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
- data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
- data/lib/skylight/normalizers/active_job/perform.rb +81 -0
- data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
- data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
- data/lib/skylight/normalizers/active_record/sql.rb +12 -0
- data/lib/skylight/normalizers/active_storage.rb +30 -0
- data/lib/skylight/normalizers/active_support/cache.rb +22 -0
- data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
- data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
- data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
- data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
- data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
- data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
- data/lib/skylight/normalizers/default.rb +32 -0
- data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
- data/lib/skylight/normalizers/faraday/request.rb +40 -0
- data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
- data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
- data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
- data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
- data/lib/skylight/normalizers/grape/format_response.rb +20 -0
- data/lib/skylight/normalizers/graphiti/render.rb +22 -0
- data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
- data/lib/skylight/normalizers/graphql/base.rb +131 -0
- data/lib/skylight/normalizers/render.rb +81 -0
- data/lib/skylight/normalizers/sequel/sql.rb +12 -0
- data/lib/skylight/normalizers/sql.rb +44 -0
- data/lib/skylight/probes.rb +153 -0
- data/lib/skylight/probes/action_controller.rb +48 -0
- data/lib/skylight/probes/action_dispatch.rb +2 -0
- data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
- data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
- data/lib/skylight/probes/action_view.rb +43 -0
- data/lib/skylight/probes/active_job.rb +29 -0
- data/lib/skylight/probes/active_job_enqueue.rb +37 -0
- data/lib/skylight/probes/active_model_serializers.rb +54 -0
- data/lib/skylight/probes/delayed_job.rb +62 -0
- data/lib/skylight/probes/elasticsearch.rb +38 -0
- data/lib/skylight/probes/excon.rb +25 -0
- data/lib/skylight/probes/excon/middleware.rb +66 -0
- data/lib/skylight/probes/faraday.rb +23 -0
- data/lib/skylight/probes/graphql.rb +43 -0
- data/lib/skylight/probes/httpclient.rb +44 -0
- data/lib/skylight/probes/middleware.rb +125 -0
- data/lib/skylight/probes/mongo.rb +163 -0
- data/lib/skylight/probes/mongoid.rb +13 -0
- data/lib/skylight/probes/net_http.rb +55 -0
- data/lib/skylight/probes/redis.rb +60 -0
- data/lib/skylight/probes/sequel.rb +33 -0
- data/lib/skylight/probes/sinatra.rb +63 -0
- data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
- data/lib/skylight/probes/tilt.rb +27 -0
- data/lib/skylight/railtie.rb +162 -18
- data/lib/skylight/sidekiq.rb +43 -0
- data/lib/skylight/subscriber.rb +110 -0
- data/lib/skylight/test.rb +146 -0
- data/lib/skylight/trace.rb +301 -10
- data/lib/skylight/user_config.rb +61 -0
- data/lib/skylight/util.rb +12 -0
- data/lib/skylight/util/allocation_free.rb +26 -0
- data/lib/skylight/util/clock.rb +56 -0
- data/lib/skylight/util/component.rb +5 -2
- data/lib/skylight/util/deploy.rb +4 -4
- data/lib/skylight/util/gzip.rb +20 -0
- data/lib/skylight/util/http.rb +4 -10
- data/lib/skylight/util/instrumenter_method.rb +26 -0
- data/lib/skylight/util/logging.rb +138 -0
- data/lib/skylight/util/lru_cache.rb +42 -0
- data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
- data/lib/skylight/version.rb +5 -1
- data/lib/skylight/vm/gc.rb +68 -0
- metadata +110 -11
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module ActiveJob
|
|
4
|
+
TITLE = "ActiveJob.execute".freeze
|
|
5
|
+
|
|
6
|
+
module Instrumentation
|
|
7
|
+
def execute(*)
|
|
8
|
+
Skylight.trace(TITLE, "app.job.execute", component: :worker) do |trace|
|
|
9
|
+
# See normalizers/active_job/perform for endpoint/segment assignment
|
|
10
|
+
begin
|
|
11
|
+
super
|
|
12
|
+
rescue Exception
|
|
13
|
+
trace.segment = "error" if trace
|
|
14
|
+
raise
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Probe
|
|
21
|
+
def install
|
|
22
|
+
::ActiveJob::Base.singleton_class.prepend(Instrumentation)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
register(:active_job, "ActiveJob::Base", "active_job/base", ActiveJob::Probe.new)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module ActiveJob
|
|
4
|
+
class EnqueueProbe
|
|
5
|
+
CAT = "other.active_job.enqueue".freeze
|
|
6
|
+
|
|
7
|
+
def install
|
|
8
|
+
::ActiveJob::Base.around_enqueue do |job, block|
|
|
9
|
+
begin
|
|
10
|
+
job_class = job.class
|
|
11
|
+
adapter_name = EnqueueProbe.normalize_adapter_name(job_class)
|
|
12
|
+
|
|
13
|
+
# If this is an ActionMailer::DeliveryJob, we'll report this as the mailer title
|
|
14
|
+
# and include ActionMailer::DeliveryJob in the description.
|
|
15
|
+
name, job_class_name = Normalizers::ActiveJob::Perform.normalize_title(job)
|
|
16
|
+
descriptors = ["adapter: '#{adapter_name}'", "queue: '#{job.queue_name}'"]
|
|
17
|
+
descriptors << "job: '#{job_class_name}'" if job_class_name
|
|
18
|
+
desc = "{ #{descriptors.join(', ')} }"
|
|
19
|
+
rescue
|
|
20
|
+
block.call
|
|
21
|
+
else
|
|
22
|
+
Skylight.instrument(title: "Enqueue #{name}", category: CAT, description: desc, &block)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
self.class.instance_eval do
|
|
27
|
+
def normalize_adapter_name(job_class)
|
|
28
|
+
job_class.queue_adapter_name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
register(:active_job_enqueue, "ActiveJob::Base", "active_job/base", ActiveJob::EnqueueProbe.new)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Instrumentation
|
|
5
|
+
def as_json(*)
|
|
6
|
+
payload = { serializer: self.class }
|
|
7
|
+
ActiveSupport::Notifications.instrument("render.active_model_serializers", payload) { super }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Probe
|
|
12
|
+
def install
|
|
13
|
+
version = nil
|
|
14
|
+
|
|
15
|
+
# File moved location between version
|
|
16
|
+
%w[serializer serializers].each do |dir|
|
|
17
|
+
# rubocop:disable Lint/SuppressedException
|
|
18
|
+
begin
|
|
19
|
+
require "active_model/#{dir}/version"
|
|
20
|
+
rescue LoadError
|
|
21
|
+
end
|
|
22
|
+
# rubocop:enable Lint/SuppressedException
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if Gem.loaded_specs["active_model_serializers"]
|
|
26
|
+
version = Gem.loaded_specs["active_model_serializers"].version
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if !version || version < Gem::Version.new("0.5.0")
|
|
30
|
+
Skylight.error "Instrumention is only available for ActiveModelSerializers version 0.5.0 and greater."
|
|
31
|
+
return
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# We don't actually support the RCs correctly, requires
|
|
35
|
+
# a release after 0.10.0.rc3
|
|
36
|
+
if version >= Gem::Version.new("0.10.0.rc1")
|
|
37
|
+
# AS::N is built in to newer versions
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# End users could override as_json without calling super, but it's likely safer
|
|
42
|
+
# than overriding serializable_array/hash/object.
|
|
43
|
+
|
|
44
|
+
[::ActiveModel::Serializer, ::ActiveModel::ArraySerializer].each do |klass|
|
|
45
|
+
klass.prepend(Instrumentation)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
register(:active_model_serializers, "ActiveModel::Serializer", "active_model/serializer",
|
|
52
|
+
ActiveModelSerializers::Probe.new)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module DelayedJob
|
|
4
|
+
module Instrumentation
|
|
5
|
+
include Skylight::Util::Logging
|
|
6
|
+
|
|
7
|
+
def run(job, *)
|
|
8
|
+
t { "Delayed::Job beginning trace" }
|
|
9
|
+
|
|
10
|
+
handler_name =
|
|
11
|
+
begin
|
|
12
|
+
if defined?(::Delayed::PerformableMethod) && job.payload_object.is_a?(::Delayed::PerformableMethod)
|
|
13
|
+
job.name
|
|
14
|
+
else
|
|
15
|
+
job.payload_object.class.name
|
|
16
|
+
end
|
|
17
|
+
rescue
|
|
18
|
+
UNKNOWN
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Skylight.trace(handler_name, "app.delayed_job.worker", "Delayed::Worker#run",
|
|
22
|
+
component: :worker, segment: job.queue) { super }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def handle_failed_job(*)
|
|
26
|
+
super
|
|
27
|
+
return unless Skylight.trace
|
|
28
|
+
|
|
29
|
+
Skylight.trace.segment = "error"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Probe
|
|
34
|
+
UNKNOWN = "<Delayed::Job Unknown>".freeze
|
|
35
|
+
|
|
36
|
+
def install
|
|
37
|
+
return unless validate_version
|
|
38
|
+
|
|
39
|
+
::Delayed::Worker.prepend(Instrumentation)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def validate_version
|
|
45
|
+
spec = Gem.loaded_specs["delayed_job"]
|
|
46
|
+
version = spec&.version
|
|
47
|
+
|
|
48
|
+
if !version || version < Gem::Version.new("4.0.0")
|
|
49
|
+
Skylight.error "The installed version of DelayedJob is not supported on Skylight. " \
|
|
50
|
+
"Your jobs will not be tracked."
|
|
51
|
+
|
|
52
|
+
return false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
register(:delayed_job, "Delayed::Worker", "delayed_job", DelayedJob::Probe.new)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Elasticsearch
|
|
4
|
+
class Probe
|
|
5
|
+
def install
|
|
6
|
+
# Prepending doesn't work here since this a module that's already been included
|
|
7
|
+
::Elasticsearch::Transport::Transport::Base.class_eval do
|
|
8
|
+
alias_method :perform_request_without_sk, :perform_request
|
|
9
|
+
def perform_request(method, path, *args, &block)
|
|
10
|
+
ActiveSupport::Notifications.instrument(
|
|
11
|
+
"request.elasticsearch",
|
|
12
|
+
name: "Request",
|
|
13
|
+
method: method,
|
|
14
|
+
path: path
|
|
15
|
+
) do
|
|
16
|
+
# Prevent HTTP-related probes from firing
|
|
17
|
+
Skylight::Normalizers::Faraday::Request.disable do
|
|
18
|
+
disable_skylight_probe(:NetHTTP) do
|
|
19
|
+
disable_skylight_probe(:HTTPClient) do
|
|
20
|
+
perform_request_without_sk(method, path, *args, &block)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def disable_skylight_probe(class_name)
|
|
28
|
+
klass = ::ActiveSupport::Inflector.safe_constantize("Skylight::Probes::#{class_name}::Probe")
|
|
29
|
+
(klass ? klass.disable { yield } : yield).tap { puts "re-enabling: #{klass}" }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
register(:elasticsearch, "Elasticsearch", "elasticsearch", Elasticsearch::Probe.new)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Excon
|
|
4
|
+
# Probe for instrumenting Excon requests. Installs {Excon::Middleware} to achieve this.
|
|
5
|
+
class Probe
|
|
6
|
+
def install
|
|
7
|
+
if defined?(::Excon::Middleware)
|
|
8
|
+
# Don't require until installation since it depends on Excon being loaded
|
|
9
|
+
require "skylight/probes/excon/middleware"
|
|
10
|
+
|
|
11
|
+
idx = ::Excon.defaults[:middlewares].index(::Excon::Middleware::Instrumentor)
|
|
12
|
+
|
|
13
|
+
# TODO: Handle possibility of idx being nil
|
|
14
|
+
::Excon.defaults[:middlewares].insert(idx, Probes::Excon::Middleware)
|
|
15
|
+
else
|
|
16
|
+
Skylight.error "The installed version of Excon doesn't support Middlewares. " \
|
|
17
|
+
"The Excon probe will be disabled."
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
register(:excon, "Excon", "excon", Excon::Probe.new)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "skylight/formatters/http"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Probes
|
|
5
|
+
module Excon
|
|
6
|
+
# Middleware for Excon that instruments requests
|
|
7
|
+
class Middleware < ::Excon::Middleware::Base
|
|
8
|
+
def initialize(*)
|
|
9
|
+
@requests = {}
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# TODO: Review the following:
|
|
14
|
+
# - Consider whether a LIFO queue would be sufficient
|
|
15
|
+
# - Check that errors can't be called without a request
|
|
16
|
+
|
|
17
|
+
def request_call(datum)
|
|
18
|
+
begin_instrumentation(datum)
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def response_call(datum)
|
|
23
|
+
super
|
|
24
|
+
ensure
|
|
25
|
+
end_instrumentation(datum)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def error_call(datum)
|
|
29
|
+
super
|
|
30
|
+
ensure
|
|
31
|
+
end_instrumentation(datum)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def begin_instrumentation(datum)
|
|
37
|
+
method = datum[:method].to_s
|
|
38
|
+
scheme = datum[:scheme]
|
|
39
|
+
host = datum[:host]
|
|
40
|
+
# TODO: Maybe don't show other default ports like 443
|
|
41
|
+
port = datum[:port] != 80 ? datum[:port] : nil
|
|
42
|
+
path = datum[:path]
|
|
43
|
+
query = datum[:query]
|
|
44
|
+
|
|
45
|
+
opts = Formatters::HTTP.build_opts(method, scheme, host, port, path, query)
|
|
46
|
+
|
|
47
|
+
@requests[datum.object_id] = Skylight.instrument(opts)
|
|
48
|
+
rescue Exception => e
|
|
49
|
+
Skylight.error "failed to begin instrumentation for Excon; msg=%s", e.message
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def end_instrumentation(datum)
|
|
53
|
+
if (request = @requests.delete(datum.object_id))
|
|
54
|
+
meta = {}
|
|
55
|
+
if datum[:error].is_a?(Exception)
|
|
56
|
+
meta[:exception_object] = datum[:error]
|
|
57
|
+
end
|
|
58
|
+
Skylight.done(request, meta)
|
|
59
|
+
end
|
|
60
|
+
rescue Exception => e
|
|
61
|
+
Skylight.error "failed to end instrumentation for Excon; msg=%s", e.message
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Faraday
|
|
4
|
+
module Instrumentation
|
|
5
|
+
def builder
|
|
6
|
+
unless defined?(@__sk__setup)
|
|
7
|
+
@__sk__setup = true
|
|
8
|
+
@builder.insert 0, ::Faraday::Request::Instrumentation
|
|
9
|
+
end
|
|
10
|
+
@builder
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Probe
|
|
15
|
+
def install
|
|
16
|
+
::Faraday::Connection.prepend(Instrumentation)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
register(:faraday, "Faraday", "faraday", Faraday::Probe.new)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
|
|
5
|
+
module Skylight
|
|
6
|
+
module Probes
|
|
7
|
+
module GraphQL
|
|
8
|
+
module Instrumentation
|
|
9
|
+
def initialize(*, **)
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
return unless defined?(@tracers)
|
|
13
|
+
|
|
14
|
+
unless @tracers.include?(::GraphQL::Tracing::ActiveSupportNotificationsTracing)
|
|
15
|
+
@tracers << ::GraphQL::Tracing::ActiveSupportNotificationsTracing
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Probe
|
|
21
|
+
def install
|
|
22
|
+
tracing_klass_name = "::GraphQL::Tracing::ActiveSupportNotificationsTracing"
|
|
23
|
+
klasses_to_probe = %w[
|
|
24
|
+
::GraphQL::Execution::Multiplex
|
|
25
|
+
::GraphQL::Query
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
return unless ([tracing_klass_name] + klasses_to_probe).all?(&method(:safe_constantize))
|
|
29
|
+
|
|
30
|
+
klasses_to_probe.each do |klass_name|
|
|
31
|
+
safe_constantize(klass_name).prepend(Instrumentation)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def safe_constantize(klass_name)
|
|
36
|
+
ActiveSupport::Inflector.safe_constantize(klass_name)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
register(:graphql, "GraphQL", "graphql", GraphQL::Probe.new)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "skylight/formatters/http"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Probes
|
|
5
|
+
module HTTPClient
|
|
6
|
+
module Instrumentation
|
|
7
|
+
# HTTPClient has request methods on the class object itself,
|
|
8
|
+
# but they internally instantiate a client and perform the method
|
|
9
|
+
# on that, so this instance method override will cover both
|
|
10
|
+
# `HTTPClient.get(...)` and `HTTPClient.new.get(...)`
|
|
11
|
+
|
|
12
|
+
def do_request(method, uri, *)
|
|
13
|
+
return super if Probes::HTTPClient::Probe.disabled?
|
|
14
|
+
|
|
15
|
+
opts = Formatters::HTTP.build_opts(method, uri.scheme, uri.host, uri.port, uri.path, uri.query)
|
|
16
|
+
|
|
17
|
+
Skylight.instrument(opts) { super }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Probe
|
|
22
|
+
DISABLED_KEY = :__skylight_httpclient_disabled
|
|
23
|
+
|
|
24
|
+
def self.disable
|
|
25
|
+
old_value = Thread.current[DISABLED_KEY]
|
|
26
|
+
Thread.current[DISABLED_KEY] = true
|
|
27
|
+
yield
|
|
28
|
+
ensure
|
|
29
|
+
Thread.current[DISABLED_KEY] = old_value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.disabled?
|
|
33
|
+
!!Thread.current[DISABLED_KEY]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def install
|
|
37
|
+
::HTTPClient.prepend(Instrumentation)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
register(:httpclient, "HTTPClient", "httpclient", HTTPClient::Probe.new)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Probes
|
|
3
|
+
module Middleware
|
|
4
|
+
# for Rails >= 6.0, which includes InstrumentationProxy
|
|
5
|
+
module InstrumentationExtensions
|
|
6
|
+
def initialize(middleware, class_name)
|
|
7
|
+
super
|
|
8
|
+
|
|
9
|
+
# NOTE: Caching here leads to better performance, but will not notice if the method is overridden
|
|
10
|
+
# We don't have access to the config here so we can't check whether source locations are enabled.
|
|
11
|
+
# However, this only happens once per middleware so it should be minimal impact.
|
|
12
|
+
@payload[:sk_source_location] =
|
|
13
|
+
begin
|
|
14
|
+
if middleware.is_a?(Proc)
|
|
15
|
+
middleware.source_location
|
|
16
|
+
elsif middleware.respond_to?(:call)
|
|
17
|
+
middleware.method(:call).source_location
|
|
18
|
+
end
|
|
19
|
+
rescue
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# for Rails <= 5.2 ActionDispatch::MiddlewareStack::Middleware
|
|
26
|
+
module Instrumentation
|
|
27
|
+
def build(*)
|
|
28
|
+
sk_instrument_middleware(super)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def sk_instrument_middleware(middleware)
|
|
32
|
+
return middleware if middleware.is_a?(Skylight::Middleware)
|
|
33
|
+
|
|
34
|
+
# Not sure how this would actually happen
|
|
35
|
+
return middleware if middleware.respond_to?(:__has_sk__)
|
|
36
|
+
|
|
37
|
+
# On Rails 3, ActionDispatch::Session::CookieStore is frozen, for one
|
|
38
|
+
return middleware if middleware.frozen?
|
|
39
|
+
|
|
40
|
+
Skylight::Probes::Middleware::Probe.add_instrumentation(middleware)
|
|
41
|
+
|
|
42
|
+
middleware
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class Probe
|
|
47
|
+
DISABLED_KEY = :__skylight_middleware_disabled
|
|
48
|
+
|
|
49
|
+
def self.disable!
|
|
50
|
+
@disabled = true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.enable!
|
|
54
|
+
@disabled = false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.disabled?
|
|
58
|
+
!!@disabled
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module InstanceInstrumentation
|
|
62
|
+
def call(*args)
|
|
63
|
+
return super(*args) if Skylight::Probes::Middleware::Probe.disabled?
|
|
64
|
+
|
|
65
|
+
trace = Skylight.instrumenter&.current_trace
|
|
66
|
+
return super(*args) unless trace
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
name = self.class.name || __sk_default_name
|
|
70
|
+
|
|
71
|
+
trace.endpoint = name
|
|
72
|
+
|
|
73
|
+
source_file, source_line = method(__method__).super_method.source_location
|
|
74
|
+
|
|
75
|
+
spans = Skylight.instrument(title: name, category: __sk_category, source_file: source_file, source_line: source_line)
|
|
76
|
+
|
|
77
|
+
proxied_response =
|
|
78
|
+
Skylight::Middleware.with_after_close(super(*args), debug_identifier: "Middleware: #{name}") do
|
|
79
|
+
Skylight.done(spans)
|
|
80
|
+
end
|
|
81
|
+
rescue Exception => e
|
|
82
|
+
Skylight.done(spans, exception_object: e)
|
|
83
|
+
raise
|
|
84
|
+
ensure
|
|
85
|
+
unless e || proxied_response
|
|
86
|
+
# If we've gotten to this point, the most likely scenario is that
|
|
87
|
+
# a throw/catch has bypassed a portion of the callstack. Since these spans would not otherwise
|
|
88
|
+
# be closed, mark them deferred to indicate that they should be implicitly closed.
|
|
89
|
+
# See Trace#deferred_spans or Trace#stop for more information.
|
|
90
|
+
Skylight.done(spans, defer: true)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def __sk_default_name
|
|
96
|
+
"Anonymous Middleware"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def __sk_category
|
|
100
|
+
"rack.middleware"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def __has_sk__
|
|
104
|
+
true
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.add_instrumentation(middleware)
|
|
109
|
+
middleware.singleton_class.prepend(InstanceInstrumentation)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def install
|
|
113
|
+
if defined?(::ActionDispatch::MiddlewareStack::InstrumentationProxy)
|
|
114
|
+
::ActionDispatch::MiddlewareStack::InstrumentationProxy.prepend(InstrumentationExtensions)
|
|
115
|
+
else
|
|
116
|
+
::ActionDispatch::MiddlewareStack::Middleware.prepend(Instrumentation)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
register(:middleware, "ActionDispatch::MiddlewareStack::Middleware", "actionpack/action_dispatch",
|
|
123
|
+
Middleware::Probe.new)
|
|
124
|
+
end
|
|
125
|
+
end
|