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,33 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Coach
|
|
4
|
+
class MiddlewareFinish < Normalizer
|
|
5
|
+
begin
|
|
6
|
+
require "coach/version"
|
|
7
|
+
version = Gem::Version.new(::Coach::VERSION)
|
|
8
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
if version && version < Gem::Version.new("1.0")
|
|
12
|
+
register "coach.middleware.finish"
|
|
13
|
+
else
|
|
14
|
+
register "finish_middleware.coach"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
CAT = "app.coach.middleware".freeze
|
|
18
|
+
|
|
19
|
+
# See information on the events Coach emits here:
|
|
20
|
+
# https://github.com/gocardless/coach#instrumentation
|
|
21
|
+
|
|
22
|
+
# Called whenever a new middleware is executed. We can expect this to happen
|
|
23
|
+
# within a Coach::Handler.
|
|
24
|
+
#
|
|
25
|
+
# We can expect the payload to have the :middleware key.
|
|
26
|
+
def normalize(trace, _name, payload)
|
|
27
|
+
trace.endpoint = payload[:middleware]
|
|
28
|
+
[CAT, payload[:middleware], nil]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Normalizers
|
|
5
|
+
module CouchPotato
|
|
6
|
+
class Query < Normalizer
|
|
7
|
+
register "couch_potato.load"
|
|
8
|
+
register "couch_potato.view"
|
|
9
|
+
|
|
10
|
+
CAT = "db.couch_db.query".freeze
|
|
11
|
+
|
|
12
|
+
def normalize(_trace, name, payload)
|
|
13
|
+
description = payload[:name] if payload
|
|
14
|
+
name = name.sub("couch_potato.", "")
|
|
15
|
+
[CAT, name, description]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
# The default normalizer, used if no other is found.
|
|
4
|
+
class Default < Normalizer
|
|
5
|
+
def initialize
|
|
6
|
+
super(nil) # Pass no config and handle it in new method
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def config
|
|
10
|
+
Skylight.config
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @param trace [Skylight::Messages::Trace::Builder] ignored, only present to match API
|
|
14
|
+
# @param name [String]
|
|
15
|
+
# @param payload [Hash]
|
|
16
|
+
# @option payload [String] :title
|
|
17
|
+
# @option payload [String] :description
|
|
18
|
+
# @return [Array, :skip] the normalized array or `:skip` if `name` is not part of a known {Skylight::TIERS tier}
|
|
19
|
+
def normalize(_trace, name, payload)
|
|
20
|
+
if name =~ Skylight::TIER_REGEX
|
|
21
|
+
[
|
|
22
|
+
name,
|
|
23
|
+
payload[:title],
|
|
24
|
+
payload[:description]
|
|
25
|
+
]
|
|
26
|
+
else
|
|
27
|
+
:skip
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Elasticsearch
|
|
4
|
+
class Request < Normalizer
|
|
5
|
+
register "request.elasticsearch"
|
|
6
|
+
|
|
7
|
+
CAT = "db.elasticsearch.request".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(_trace, _name, payload)
|
|
10
|
+
path = payload[:path].split("/")
|
|
11
|
+
title = [payload[:method], path[0]].compact.join(" ")
|
|
12
|
+
desc = {}
|
|
13
|
+
desc[:type] = path[1] if path[1]
|
|
14
|
+
desc[:id] = "?" if path[2]
|
|
15
|
+
[CAT, title, desc.empty? ? nil : desc.to_json]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "skylight/formatters/http"
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Normalizers
|
|
5
|
+
module Faraday
|
|
6
|
+
class Request < Normalizer
|
|
7
|
+
register "request.faraday"
|
|
8
|
+
|
|
9
|
+
DISABLED_KEY = :__skylight_faraday_disabled
|
|
10
|
+
|
|
11
|
+
def self.disable
|
|
12
|
+
old_value = Thread.current[DISABLED_KEY]
|
|
13
|
+
Thread.current[DISABLED_KEY] = true
|
|
14
|
+
yield
|
|
15
|
+
ensure
|
|
16
|
+
Thread.current[DISABLED_KEY] = old_value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def disabled?
|
|
20
|
+
!!Thread.current[DISABLED_KEY]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def normalize(_trace, _name, payload)
|
|
24
|
+
uri = payload[:url]
|
|
25
|
+
|
|
26
|
+
if disabled?
|
|
27
|
+
return :skip
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
opts = Formatters::HTTP.build_opts(payload[:method], uri.scheme, uri.host, uri.port, uri.path, uri.query)
|
|
31
|
+
description = opts[:title]
|
|
32
|
+
|
|
33
|
+
# We use "Faraday" as the title to differentiate it in the UI in
|
|
34
|
+
# case it's wrapping or is wrapped by another HTTP backend
|
|
35
|
+
[opts[:category], "Faraday", description, opts[:meta]]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Grape
|
|
4
|
+
class Endpoint < Normalizer
|
|
5
|
+
%w[
|
|
6
|
+
run
|
|
7
|
+
render
|
|
8
|
+
run_filters
|
|
9
|
+
].each do |type|
|
|
10
|
+
require "skylight/normalizers/grape/endpoint_#{type}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
require "skylight/normalizers/grape/format_response"
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def get_method(endpoint)
|
|
18
|
+
method = endpoint.options[:method].first
|
|
19
|
+
method = "#{method}..." if endpoint.options[:method].length > 1
|
|
20
|
+
method
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_path(endpoint)
|
|
24
|
+
endpoint.options[:path].join("/")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_namespace(endpoint)
|
|
28
|
+
# slice off preceding slash for data continuity
|
|
29
|
+
::Grape::Namespace.joined_space_path(endpoint.namespace_stackable(:namespace)).to_s[1..-1]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Grape
|
|
4
|
+
class EndpointRender < Endpoint
|
|
5
|
+
register "endpoint_render.grape"
|
|
6
|
+
|
|
7
|
+
CAT = "app.grape.endpoint".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(_trace, _name, payload)
|
|
10
|
+
if (endpoint = payload[:endpoint])
|
|
11
|
+
path = get_path(endpoint)
|
|
12
|
+
namespace = get_namespace(endpoint)
|
|
13
|
+
method = get_method(endpoint)
|
|
14
|
+
|
|
15
|
+
title = [method, namespace, path].join(" ").gsub(/\s+/, " ")
|
|
16
|
+
|
|
17
|
+
[CAT, title, nil]
|
|
18
|
+
else
|
|
19
|
+
:skip
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Grape
|
|
4
|
+
class EndpointRun < Endpoint
|
|
5
|
+
register "endpoint_run.grape"
|
|
6
|
+
|
|
7
|
+
def normalize(trace, _name, payload)
|
|
8
|
+
trace.endpoint = get_endpoint_name(payload[:endpoint]) if payload[:endpoint]
|
|
9
|
+
|
|
10
|
+
# We don't necessarily want this to be all instrumented since it's fairly internal.
|
|
11
|
+
# However, it is a good place to get the endpoint name.
|
|
12
|
+
:skip
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def get_endpoint_name(endpoint)
|
|
18
|
+
method = get_method(endpoint)
|
|
19
|
+
path = get_path(endpoint)
|
|
20
|
+
namespace = get_namespace(endpoint)
|
|
21
|
+
|
|
22
|
+
if namespace && !namespace.empty?
|
|
23
|
+
path = "/#{path}" if path[0] != "/"
|
|
24
|
+
path = "#{namespace}#{path}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
"#{base_app_name(endpoint)} [#{method}] #{path}".strip
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def base_app_name(endpoint)
|
|
31
|
+
ep = endpoint.options[:for]
|
|
32
|
+
return ep.name if ep.name
|
|
33
|
+
|
|
34
|
+
if ep.respond_to?(:base) && ep.base.respond_to?(:name)
|
|
35
|
+
ep.base.name
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Grape
|
|
4
|
+
class EndpointRunFilters < Endpoint
|
|
5
|
+
register "endpoint_run_filters.grape"
|
|
6
|
+
|
|
7
|
+
CAT = "app.grape.filters".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(_trace, _name, payload)
|
|
10
|
+
filters = payload[:filters]
|
|
11
|
+
type = payload[:type]
|
|
12
|
+
|
|
13
|
+
if (!filters || filters.empty?) || !type
|
|
14
|
+
return :skip
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
[CAT, "#{type.to_s.capitalize} Filters", nil]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Skylight
|
|
2
|
+
module Normalizers
|
|
3
|
+
module Grape
|
|
4
|
+
class FormatResponse < Normalizer
|
|
5
|
+
register "format_response.grape"
|
|
6
|
+
|
|
7
|
+
CAT = "view.grape.format_response".freeze
|
|
8
|
+
|
|
9
|
+
def normalize(_trace, _name, payload)
|
|
10
|
+
if (formatter = payload[:formatter])
|
|
11
|
+
title = formatter.is_a?(Module) ? formatter.to_s : formatter.class.to_s
|
|
12
|
+
[CAT, title, nil]
|
|
13
|
+
else
|
|
14
|
+
:skip
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Normalizers
|
|
5
|
+
module Graphiti
|
|
6
|
+
class Render < Normalizer
|
|
7
|
+
register "render.graphiti"
|
|
8
|
+
|
|
9
|
+
CAT = "view.render.graphiti"
|
|
10
|
+
ANONYMOUS = "<Anonymous Resource>"
|
|
11
|
+
|
|
12
|
+
def normalize(_trace, _name, payload)
|
|
13
|
+
resource_class = payload[:proxy]&.resource&.class
|
|
14
|
+
title = "Render #{resource_class&.name || ANONYMOUS}"
|
|
15
|
+
desc = nil
|
|
16
|
+
|
|
17
|
+
[CAT, title, desc]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Skylight
|
|
4
|
+
module Normalizers
|
|
5
|
+
module Graphiti
|
|
6
|
+
class Resolve < Normalizer
|
|
7
|
+
register "resolve.graphiti"
|
|
8
|
+
|
|
9
|
+
CAT = "app.resolve.graphiti"
|
|
10
|
+
|
|
11
|
+
ANONYMOUS_RESOURCE = "<Anonymous Resource>"
|
|
12
|
+
ANONYMOUS_ADAPTER = "<Anonymous Adapter>"
|
|
13
|
+
|
|
14
|
+
def normalize(_trace, _name, payload)
|
|
15
|
+
resource = payload[:resource]
|
|
16
|
+
|
|
17
|
+
if (sideload = payload[:sideload])
|
|
18
|
+
type = sideload.type.to_s.split("_").map(&:capitalize).join(" ")
|
|
19
|
+
desc = "Custom Scope" if sideload.class.scope_proc
|
|
20
|
+
else
|
|
21
|
+
type = "Primary"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
title = "Resolve #{type} #{resource.class.name || ANONYMOUS_RESOURCE}"
|
|
25
|
+
|
|
26
|
+
[CAT, title, desc]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
|
|
5
|
+
module Skylight::Normalizers::GraphQL
|
|
6
|
+
# Some AS::N events in GraphQL are not super useful.
|
|
7
|
+
# We are purposefully ignoring the following keys (and you probably shouldn't add them):
|
|
8
|
+
# - "graphql.analyze_multiplex"
|
|
9
|
+
# - "graphql.execute_field" (very frequently called)
|
|
10
|
+
# - "graphql.execute_field_lazy"
|
|
11
|
+
|
|
12
|
+
class Base < Skylight::Normalizers::Normalizer
|
|
13
|
+
ANONYMOUS = "[anonymous]"
|
|
14
|
+
CAT = "app.graphql"
|
|
15
|
+
|
|
16
|
+
if defined?(::GraphQL::VERSION) && Gem::Version.new(::GraphQL::VERSION) >= Gem::Version.new("1.10")
|
|
17
|
+
def self.register_graphql
|
|
18
|
+
register("#{key}.graphql")
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
def self.register_graphql
|
|
22
|
+
register("graphql.#{key}")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.inherited(klass)
|
|
27
|
+
klass.const_set(
|
|
28
|
+
:KEY,
|
|
29
|
+
ActiveSupport::Inflector.underscore(
|
|
30
|
+
ActiveSupport::Inflector.demodulize(klass.name)
|
|
31
|
+
).freeze
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.key
|
|
36
|
+
self::KEY
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def normalize(_trace, _name, _payload)
|
|
40
|
+
[CAT, "graphql.#{key}", nil]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def key
|
|
46
|
+
self.class.key
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def extract_query_name(query)
|
|
50
|
+
query&.context&.[](:skylight_endpoint) ||
|
|
51
|
+
query&.operation_name ||
|
|
52
|
+
ANONYMOUS
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Lex < Base
|
|
57
|
+
register_graphql
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class Parse < Base
|
|
61
|
+
register_graphql
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class Validate < Base
|
|
65
|
+
register_graphql
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class ExecuteMultiplex < Base
|
|
69
|
+
register_graphql
|
|
70
|
+
|
|
71
|
+
def normalize_after(trace, _span, _name, payload)
|
|
72
|
+
# This is in normalize_after because the queries may not have
|
|
73
|
+
# an assigned operation name before they are executed.
|
|
74
|
+
# For example, if you send a single query with a defined operation name, e.g.:
|
|
75
|
+
# ```graphql
|
|
76
|
+
# query MyNamedQuery { user(id: 1) { name } }
|
|
77
|
+
# ```
|
|
78
|
+
# ... but do _not_ send the operationName request param, the GraphQL docs[1]
|
|
79
|
+
# specify that the executor should use the operation name from the definition.
|
|
80
|
+
#
|
|
81
|
+
# In graphql-ruby's case, the calculation of the operation name is lazy, and
|
|
82
|
+
# has not been done yet at the point where execute_multiplex starts.
|
|
83
|
+
# [1] https://graphql.org/learn/serving-over-http/#post-request
|
|
84
|
+
queries, has_errors = payload[:multiplex].queries.each_with_object([Set.new, Set.new]) do |query, (names, errors)|
|
|
85
|
+
names << extract_query_name(query)
|
|
86
|
+
errors << query.static_errors.any?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
trace.endpoint = "graphql:#{queries.sort.join('+')}"
|
|
90
|
+
trace.compound_response_error_status = if has_errors.all?
|
|
91
|
+
:all
|
|
92
|
+
elsif has_errors.any?
|
|
93
|
+
:partial
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class AnalyzeQuery < Base
|
|
99
|
+
register_graphql
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class ExecuteQuery < Base
|
|
103
|
+
register_graphql
|
|
104
|
+
|
|
105
|
+
def normalize(trace, _name, payload)
|
|
106
|
+
query_name = extract_query_name(payload[:query])
|
|
107
|
+
|
|
108
|
+
if query_name == ANONYMOUS
|
|
109
|
+
meta = { mute_children: true }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# This is probably always overriden by execute_multiplex#normalize_after,
|
|
113
|
+
# but in the case of a single query, it will be the same value anyway.
|
|
114
|
+
trace.endpoint = "graphql:#{query_name}"
|
|
115
|
+
|
|
116
|
+
[CAT, "graphql.#{key}: #{query_name}", nil, meta]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class ExecuteQueryLazy < ExecuteQuery
|
|
121
|
+
register_graphql
|
|
122
|
+
|
|
123
|
+
def normalize(trace, _name, payload)
|
|
124
|
+
if payload[:query]
|
|
125
|
+
super
|
|
126
|
+
elsif payload[:multiplex]
|
|
127
|
+
[CAT, "graphql.#{key}.multiplex", nil]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|