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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -5
  3. data/CONTRIBUTING.md +1 -7
  4. data/ext/extconf.rb +4 -3
  5. data/ext/libskylight.yml +5 -6
  6. data/ext/skylight_native.c +22 -99
  7. data/lib/skylight.rb +204 -14
  8. data/lib/skylight/api.rb +7 -3
  9. data/lib/skylight/cli.rb +4 -3
  10. data/lib/skylight/cli/doctor.rb +3 -2
  11. data/lib/skylight/cli/merger.rb +6 -4
  12. data/lib/skylight/config.rb +603 -126
  13. data/lib/skylight/deprecation.rb +15 -0
  14. data/lib/skylight/errors.rb +17 -2
  15. data/lib/skylight/extensions.rb +99 -0
  16. data/lib/skylight/extensions/source_location.rb +249 -0
  17. data/lib/skylight/fanout.rb +0 -0
  18. data/lib/skylight/formatters/http.rb +19 -0
  19. data/lib/skylight/gc.rb +109 -0
  20. data/lib/skylight/helpers.rb +18 -2
  21. data/lib/skylight/instrumenter.rb +325 -15
  22. data/lib/skylight/middleware.rb +138 -1
  23. data/lib/skylight/native.rb +51 -1
  24. data/lib/skylight/native_ext_fetcher.rb +2 -1
  25. data/lib/skylight/normalizers.rb +151 -0
  26. data/lib/skylight/normalizers/action_controller/process_action.rb +69 -0
  27. data/lib/skylight/normalizers/action_controller/send_file.rb +50 -0
  28. data/lib/skylight/normalizers/action_dispatch/process_middleware.rb +22 -0
  29. data/lib/skylight/normalizers/action_dispatch/route_set.rb +27 -0
  30. data/lib/skylight/normalizers/action_view/render_collection.rb +24 -0
  31. data/lib/skylight/normalizers/action_view/render_layout.rb +25 -0
  32. data/lib/skylight/normalizers/action_view/render_partial.rb +23 -0
  33. data/lib/skylight/normalizers/action_view/render_template.rb +23 -0
  34. data/lib/skylight/normalizers/active_job/perform.rb +81 -0
  35. data/lib/skylight/normalizers/active_model_serializers/render.rb +28 -0
  36. data/lib/skylight/normalizers/active_record/instantiation.rb +16 -0
  37. data/lib/skylight/normalizers/active_record/sql.rb +12 -0
  38. data/lib/skylight/normalizers/active_storage.rb +30 -0
  39. data/lib/skylight/normalizers/active_support/cache.rb +22 -0
  40. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  41. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  42. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  43. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  44. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  45. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  46. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  47. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  48. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  49. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  50. data/lib/skylight/normalizers/coach/handler_finish.rb +46 -0
  51. data/lib/skylight/normalizers/coach/middleware_finish.rb +33 -0
  52. data/lib/skylight/normalizers/couch_potato/query.rb +20 -0
  53. data/lib/skylight/normalizers/data_mapper/sql.rb +12 -0
  54. data/lib/skylight/normalizers/default.rb +32 -0
  55. data/lib/skylight/normalizers/elasticsearch/request.rb +20 -0
  56. data/lib/skylight/normalizers/faraday/request.rb +40 -0
  57. data/lib/skylight/normalizers/grape/endpoint.rb +34 -0
  58. data/lib/skylight/normalizers/grape/endpoint_render.rb +25 -0
  59. data/lib/skylight/normalizers/grape/endpoint_run.rb +41 -0
  60. data/lib/skylight/normalizers/grape/endpoint_run_filters.rb +22 -0
  61. data/lib/skylight/normalizers/grape/format_response.rb +20 -0
  62. data/lib/skylight/normalizers/graphiti/render.rb +22 -0
  63. data/lib/skylight/normalizers/graphiti/resolve.rb +31 -0
  64. data/lib/skylight/normalizers/graphql/base.rb +131 -0
  65. data/lib/skylight/normalizers/render.rb +81 -0
  66. data/lib/skylight/normalizers/sequel/sql.rb +12 -0
  67. data/lib/skylight/normalizers/sql.rb +44 -0
  68. data/lib/skylight/probes.rb +153 -0
  69. data/lib/skylight/probes/action_controller.rb +48 -0
  70. data/lib/skylight/probes/action_dispatch.rb +2 -0
  71. data/lib/skylight/probes/action_dispatch/request_id.rb +29 -0
  72. data/lib/skylight/probes/action_dispatch/routing/route_set.rb +28 -0
  73. data/lib/skylight/probes/action_view.rb +43 -0
  74. data/lib/skylight/probes/active_job.rb +29 -0
  75. data/lib/skylight/probes/active_job_enqueue.rb +37 -0
  76. data/lib/skylight/probes/active_model_serializers.rb +54 -0
  77. data/lib/skylight/probes/delayed_job.rb +62 -0
  78. data/lib/skylight/probes/elasticsearch.rb +38 -0
  79. data/lib/skylight/probes/excon.rb +25 -0
  80. data/lib/skylight/probes/excon/middleware.rb +66 -0
  81. data/lib/skylight/probes/faraday.rb +23 -0
  82. data/lib/skylight/probes/graphql.rb +43 -0
  83. data/lib/skylight/probes/httpclient.rb +44 -0
  84. data/lib/skylight/probes/middleware.rb +125 -0
  85. data/lib/skylight/probes/mongo.rb +163 -0
  86. data/lib/skylight/probes/mongoid.rb +13 -0
  87. data/lib/skylight/probes/net_http.rb +55 -0
  88. data/lib/skylight/probes/redis.rb +60 -0
  89. data/lib/skylight/probes/sequel.rb +33 -0
  90. data/lib/skylight/probes/sinatra.rb +63 -0
  91. data/lib/skylight/probes/sinatra_add_middleware.rb +10 -10
  92. data/lib/skylight/probes/tilt.rb +27 -0
  93. data/lib/skylight/railtie.rb +162 -18
  94. data/lib/skylight/sidekiq.rb +43 -0
  95. data/lib/skylight/subscriber.rb +110 -0
  96. data/lib/skylight/test.rb +146 -0
  97. data/lib/skylight/trace.rb +301 -10
  98. data/lib/skylight/user_config.rb +61 -0
  99. data/lib/skylight/util.rb +12 -0
  100. data/lib/skylight/util/allocation_free.rb +26 -0
  101. data/lib/skylight/util/clock.rb +56 -0
  102. data/lib/skylight/util/component.rb +5 -2
  103. data/lib/skylight/util/deploy.rb +4 -4
  104. data/lib/skylight/util/gzip.rb +20 -0
  105. data/lib/skylight/util/http.rb +4 -10
  106. data/lib/skylight/util/instrumenter_method.rb +26 -0
  107. data/lib/skylight/util/logging.rb +138 -0
  108. data/lib/skylight/util/lru_cache.rb +42 -0
  109. data/lib/skylight/vendor/cli/thor/rake_compat.rb +1 -1
  110. data/lib/skylight/version.rb +5 -1
  111. data/lib/skylight/vm/gc.rb +68 -0
  112. 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