instana 1.11.7 → 1.193.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of instana might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Rakefile +26 -37
- data/gemfiles/libraries.gemfile +2 -0
- data/lib/instana/agent.rb +6 -0
- data/lib/instana/base.rb +2 -0
- data/lib/instana/config.rb +11 -0
- data/lib/instana/frameworks/cuba.rb +33 -0
- data/lib/instana/frameworks/instrumentation/action_controller.rb +11 -0
- data/lib/instana/frameworks/instrumentation/mysql2_adapter.rb +7 -1
- data/lib/instana/frameworks/instrumentation/mysql_adapter.rb +7 -1
- data/lib/instana/frameworks/instrumentation/postgresql_adapter.rb +23 -5
- data/lib/instana/frameworks/roda.rb +41 -0
- data/lib/instana/frameworks/sinatra.rb +17 -0
- data/lib/instana/instrumentation/excon.rb +1 -1
- data/lib/instana/instrumentation/graphql.rb +77 -0
- data/lib/instana/instrumentation/net-http.rb +2 -0
- data/lib/instana/instrumentation/rack.rb +5 -0
- data/lib/instana/secrets.rb +42 -0
- data/lib/instana/setup.rb +1 -0
- data/lib/instana/tracing/span.rb +23 -10
- data/lib/instana/version.rb +1 -1
- data/test/apps/cuba.rb +4 -0
- data/test/apps/roda.rb +3 -0
- data/test/apps/sinatra.rb +4 -0
- data/test/config_test.rb +1 -17
- data/test/frameworks/cuba_test.rb +14 -1
- data/test/frameworks/rack_test.rb +27 -15
- data/test/frameworks/rails/actioncontroller_test.rb +12 -0
- data/test/frameworks/rails/activerecord_test.rb +80 -28
- data/test/frameworks/roda_test.rb +14 -0
- data/test/frameworks/sinatra_test.rb +14 -0
- data/test/instrumentation/excon_test.rb +0 -2
- data/test/instrumentation/graphql_test.rb +116 -0
- data/test/instrumentation/redis_test.rb +10 -0
- data/test/secrets_test.rb +73 -0
- data/test/tracing/tracer_test.rb +31 -1
- metadata +12 -8
- data/test/tracing/trace_test.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0c2b0b0e44a5aa72f401d7ab7009125c25d182c01aa01aade80a8ca9f9fc55b
|
4
|
+
data.tar.gz: d147f265753ba3397773197b366f8a24f53a4e928ca8e08a929664c7d5029a1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bb4b908097b92adf0169f9ca71a43f82df4349b3257cc30cdbc2b8ba3ec13b62171e9c3ed14c1233421801795ebaba4c697c43776e9e31983af900db95d56ff
|
7
|
+
data.tar.gz: f7d415705c052ab4c85d446da325569a9940c1d7bfdeb782f17d263d78152585364203120e50c91737d29e992a146710df434874c46c58ce0107df14b5bc7cab
|
data/Rakefile
CHANGED
@@ -8,44 +8,33 @@ Rake::TestTask.new(:test) do |t|
|
|
8
8
|
|
9
9
|
t.libs << "test"
|
10
10
|
t.libs << "lib"
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
'test/frameworks/sinatra_test.rb']
|
37
|
-
else
|
38
|
-
t.test_files = FileList['test/agent/*_test.rb'] +
|
39
|
-
FileList['test/tracing/*_test.rb'] +
|
40
|
-
FileList['test/profiling/*_test.rb'] +
|
41
|
-
FileList['test/benchmarks/bench_*.rb']
|
42
|
-
end
|
43
|
-
else
|
44
|
-
t.test_files = FileList['test/agent/*_test.rb'] +
|
45
|
-
FileList['test/tracing/*_test.rb'] +
|
46
|
-
FileList['test/profiling/*_test.rb'] +
|
47
|
-
FileList['test/benchmarks/bench_*.rb']
|
11
|
+
|
12
|
+
t.test_files = Dir[
|
13
|
+
'test/*_test.rb',
|
14
|
+
'test/{agent,tracing,profiling,benchmarks}/*_test.rb'
|
15
|
+
]
|
16
|
+
|
17
|
+
case File.basename(ENV.fetch('BUNDLE_GEMFILE', '')).split('.').first
|
18
|
+
when /rails6/
|
19
|
+
t.test_files = %w(test/frameworks/rails/activerecord_test.rb
|
20
|
+
test/frameworks/rails/actioncontroller_test.rb
|
21
|
+
test/frameworks/rails/actionview5_test.rb)
|
22
|
+
when /rails5/
|
23
|
+
t.test_files = %w(test/frameworks/rails/activerecord_test.rb
|
24
|
+
test/frameworks/rails/actioncontroller_test.rb
|
25
|
+
test/frameworks/rails/actionview5_test.rb)
|
26
|
+
when /rails42/
|
27
|
+
t.test_files = %w(test/frameworks/rails/activerecord_test.rb
|
28
|
+
test/frameworks/rails/actioncontroller_test.rb
|
29
|
+
test/frameworks/rails/actionview4_test.rb)
|
30
|
+
when /rails32/
|
31
|
+
t.test_files = %w(test/frameworks/rails/activerecord_test.rb
|
32
|
+
test/frameworks/rails/actioncontroller_test.rb
|
33
|
+
test/frameworks/rails/actionview3_test.rb)
|
34
|
+
when /libraries/
|
35
|
+
t.test_files = Dir['test/{instrumentation,frameworks}/*_test.rb']
|
48
36
|
end
|
37
|
+
|
49
38
|
end
|
50
39
|
|
51
40
|
task :environment do
|
data/gemfiles/libraries.gemfile
CHANGED
data/lib/instana/agent.rb
CHANGED
@@ -25,6 +25,7 @@ module Instana
|
|
25
25
|
attr_accessor :collect_thread
|
26
26
|
attr_accessor :thread_spawn_lock
|
27
27
|
attr_accessor :extra_headers
|
28
|
+
attr_reader :secret_values
|
28
29
|
|
29
30
|
attr_accessor :testmode
|
30
31
|
|
@@ -83,6 +84,10 @@ module Instana
|
|
83
84
|
|
84
85
|
# The agent may pass down custom headers for this sensor to capture
|
85
86
|
@extra_headers = nil
|
87
|
+
|
88
|
+
# The values considered sensitive and removed from http query parameters
|
89
|
+
# and database connection strings
|
90
|
+
@secret_values = nil
|
86
91
|
end
|
87
92
|
|
88
93
|
# Spawns the background thread and calls start. This method is separated
|
@@ -278,6 +283,7 @@ module Instana
|
|
278
283
|
data = Oj.load(response.body, OJ_OPTIONS)
|
279
284
|
@process[:report_pid] = data['pid']
|
280
285
|
@agent_uuid = data['agentUuid']
|
286
|
+
@secret_values = data['secrets']
|
281
287
|
|
282
288
|
if data.key?('extraHeaders')
|
283
289
|
@extra_headers = data['extraHeaders']
|
data/lib/instana/base.rb
CHANGED
@@ -12,6 +12,7 @@ module Instana
|
|
12
12
|
attr_accessor :config
|
13
13
|
attr_accessor :logger
|
14
14
|
attr_accessor :pid
|
15
|
+
attr_reader :secrets
|
15
16
|
|
16
17
|
##
|
17
18
|
# setup
|
@@ -24,6 +25,7 @@ module Instana
|
|
24
25
|
@tracer = ::Instana::Tracer.new
|
25
26
|
@processor = ::Instana::Processor.new
|
26
27
|
@collector = ::Instana::Collector.new
|
28
|
+
@secrets = ::Instana::Secrets.new
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/instana/config.rb
CHANGED
@@ -42,12 +42,23 @@ module Instana
|
|
42
42
|
# ::Instana.config[:collect_backtraces] = true
|
43
43
|
@config[:collect_backtraces] = false
|
44
44
|
|
45
|
+
# By default, collected SQL will be sanitized to remove potentially sensitive bind params such as:
|
46
|
+
# > SELECT "blocks".* FROM "blocks" WHERE "blocks"."name" = "Mr. Smith"
|
47
|
+
#
|
48
|
+
# ...would be sanitized to be:
|
49
|
+
# > SELECT "blocks".* FROM "blocks" WHERE "blocks"."name" = ?
|
50
|
+
#
|
51
|
+
# This sanitization step can be disabled by setting the following value to false.
|
52
|
+
# ::Instana.config[:sanitize_sql] = false
|
53
|
+
@config[:sanitize_sql] = true
|
54
|
+
|
45
55
|
@config[:action_controller] = { :enabled => true }
|
46
56
|
@config[:action_view] = { :enabled => true }
|
47
57
|
@config[:active_record] = { :enabled => true }
|
48
58
|
@config[:dalli] = { :enabled => true }
|
49
59
|
@config[:excon] = { :enabled => true }
|
50
60
|
@config[:grpc] = { :enabled => true }
|
61
|
+
@config[:graphql] = { :enabled => true }
|
51
62
|
@config[:nethttp] = { :enabled => true }
|
52
63
|
@config[:redis] = { :enabled => true }
|
53
64
|
@config[:'resque-client'] = { :enabled => true }
|
@@ -1,6 +1,39 @@
|
|
1
1
|
require "instana/rack"
|
2
2
|
|
3
|
+
module Instana
|
4
|
+
module CubaPathTemplateExtractor
|
5
|
+
REPLACE_TARGET = /:(?<term>[^\/]+)/i
|
6
|
+
|
7
|
+
def self.prepended(base)
|
8
|
+
::Instana.logger.debug "#{base} prepended #{self}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def on(*args, &blk)
|
12
|
+
wrapper = lambda do |*caputres|
|
13
|
+
env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] << args
|
14
|
+
.select { |a| a.is_a?(String) }
|
15
|
+
.join('/')
|
16
|
+
|
17
|
+
blk.call(*captures)
|
18
|
+
end
|
19
|
+
|
20
|
+
super(*args, &wrapper)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call!(env)
|
24
|
+
env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] = []
|
25
|
+
response = super(env)
|
26
|
+
env['INSTANA_HTTP_PATH_TEMPLATE'] = env['INSTANA_PATH_TEMPLATE_FRAGMENTS']
|
27
|
+
.join('/')
|
28
|
+
.gsub(REPLACE_TARGET, '{\k<term>}')
|
29
|
+
response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
3
35
|
if defined?(::Cuba)
|
4
36
|
::Instana.logger.debug "Instrumenting Cuba"
|
5
37
|
Cuba.use ::Instana::Rack
|
38
|
+
Cuba.prepend ::Instana::CubaPathTemplateExtractor
|
6
39
|
end
|
@@ -64,6 +64,15 @@ module Instana
|
|
64
64
|
end
|
65
65
|
name
|
66
66
|
end
|
67
|
+
|
68
|
+
def matched_path_template
|
69
|
+
Rails.application.routes.router.recognize(request) do |route, _, _|
|
70
|
+
path = route.path
|
71
|
+
return path.spec.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
nil
|
75
|
+
end
|
67
76
|
end
|
68
77
|
|
69
78
|
# Used in ActionPack versions 5 and beyond, this module provides
|
@@ -83,6 +92,7 @@ module Instana
|
|
83
92
|
::Instana.tracer.log_entry(:actioncontroller, kv_payload)
|
84
93
|
|
85
94
|
super(*args)
|
95
|
+
request.env['INSTANA_HTTP_PATH_TEMPLATE'] = matched_path_template
|
86
96
|
rescue Exception => e
|
87
97
|
::Instana.tracer.log_error(e) unless has_rails_handler?(e)
|
88
98
|
raise
|
@@ -135,6 +145,7 @@ module Instana
|
|
135
145
|
::Instana.tracer.log_entry(:actioncontroller, kv_payload)
|
136
146
|
|
137
147
|
process_action_without_instana(*args)
|
148
|
+
request.env['INSTANA_HTTP_PATH_TEMPLATE'] = matched_path_template
|
138
149
|
rescue Exception => e
|
139
150
|
::Instana.tracer.log_error(e) unless has_rails_handler?(e)
|
140
151
|
raise
|
@@ -24,7 +24,13 @@ module Instana
|
|
24
24
|
#
|
25
25
|
def collect(sql)
|
26
26
|
payload = { :activerecord => {} }
|
27
|
-
|
27
|
+
|
28
|
+
if ::Instana.config[:sanitize_sql]
|
29
|
+
payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
|
30
|
+
else
|
31
|
+
payload[:activerecord][:sql] = sql
|
32
|
+
end
|
33
|
+
|
28
34
|
payload[:activerecord][:adapter] = @config[:adapter]
|
29
35
|
payload[:activerecord][:host] = @config[:host]
|
30
36
|
payload[:activerecord][:db] = @config[:database]
|
@@ -21,7 +21,13 @@ module Instana
|
|
21
21
|
#
|
22
22
|
def collect(sql)
|
23
23
|
payload = { :activerecord => {} }
|
24
|
-
|
24
|
+
|
25
|
+
if ::Instana.config[:sanitize_sql]
|
26
|
+
payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
|
27
|
+
else
|
28
|
+
payload[:activerecord][:sql] = sql
|
29
|
+
end
|
30
|
+
|
25
31
|
payload[:activerecord][:adapter] = @config[:adapter]
|
26
32
|
payload[:activerecord][:host] = @config[:host]
|
27
33
|
payload[:activerecord][:db] = @config[:database]
|
@@ -17,7 +17,6 @@ module Instana
|
|
17
17
|
Instana::Util.method_alias(klass, :exec_delete)
|
18
18
|
Instana::Util.method_alias(klass, :execute)
|
19
19
|
|
20
|
-
|
21
20
|
@@sanitize_regexp = Regexp.new('(\'[\s\S][^\']*\'|\d*\.\d+|\d+|NULL)', Regexp::IGNORECASE)
|
22
21
|
end
|
23
22
|
end
|
@@ -27,14 +26,33 @@ module Instana
|
|
27
26
|
# @param sql [String]
|
28
27
|
# @return [Hash] Hash of collected KVs
|
29
28
|
#
|
30
|
-
def collect(sql)
|
29
|
+
def collect(sql, binds = nil)
|
31
30
|
payload = { :activerecord => {} }
|
32
|
-
|
31
|
+
|
33
32
|
payload[:activerecord][:adapter] = @config[:adapter]
|
34
33
|
payload[:activerecord][:host] = @config[:host]
|
35
34
|
payload[:activerecord][:db] = @config[:database]
|
36
35
|
payload[:activerecord][:username] = @config[:username]
|
36
|
+
|
37
|
+
if ::Instana.config[:sanitize_sql]
|
38
|
+
payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
|
39
|
+
else
|
40
|
+
# No sanitization so raw SQL and collect up binds
|
41
|
+
payload[:activerecord][:sql] = sql
|
42
|
+
|
43
|
+
# FIXME: Only works on Rails 5 as the bind format varied in previous versions of Rails
|
44
|
+
if binds.is_a?(Array)
|
45
|
+
raw_binds = []
|
46
|
+
binds.each { |x| raw_binds << x.value_before_type_cast }
|
47
|
+
payload[:activerecord][:binds] = raw_binds
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
37
51
|
payload
|
52
|
+
rescue Exception => e
|
53
|
+
::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
|
54
|
+
ensure
|
55
|
+
return payload
|
38
56
|
end
|
39
57
|
|
40
58
|
# In the spirit of ::ActiveRecord::ExplainSubscriber.ignore_payload? There are
|
@@ -53,7 +71,7 @@ module Instana
|
|
53
71
|
return exec_query_without_instana(sql, name, binds, *args)
|
54
72
|
end
|
55
73
|
|
56
|
-
kv_payload = collect(sql)
|
74
|
+
kv_payload = collect(sql, binds)
|
57
75
|
::Instana.tracer.trace(:activerecord, kv_payload) do
|
58
76
|
exec_query_without_instana(sql, name, binds, *args)
|
59
77
|
end
|
@@ -64,7 +82,7 @@ module Instana
|
|
64
82
|
return exec_delete_without_instana(sql, name, binds)
|
65
83
|
end
|
66
84
|
|
67
|
-
kv_payload = collect(sql)
|
85
|
+
kv_payload = collect(sql, binds)
|
68
86
|
::Instana.tracer.trace(:activerecord, kv_payload) do
|
69
87
|
exec_delete_without_instana(sql, name, binds)
|
70
88
|
end
|
@@ -1,6 +1,47 @@
|
|
1
1
|
require "instana/rack"
|
2
2
|
|
3
|
+
module Instana
|
4
|
+
module RodaPathTemplateExtractor
|
5
|
+
module RequestMethods
|
6
|
+
TERM = defined?(::Roda) ? ::Roda::RodaPlugins::Base::RequestMethods::TERM : Object
|
7
|
+
|
8
|
+
def if_match(args, &blk)
|
9
|
+
path = @remaining_path
|
10
|
+
captures = @captures.clear
|
11
|
+
|
12
|
+
if match_all(args)
|
13
|
+
(env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] ||= []).concat(named_args(args, blk))
|
14
|
+
block_result(blk.(*captures))
|
15
|
+
env['INSTANA_HTTP_PATH_TEMPLATE'] = env['INSTANA_PATH_TEMPLATE_FRAGMENTS']
|
16
|
+
.join('/')
|
17
|
+
.prepend('/')
|
18
|
+
throw :halt, response.finish
|
19
|
+
else
|
20
|
+
@remaining_path = path
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def named_args(args, blk)
|
26
|
+
parameters = blk.parameters
|
27
|
+
args.map do |a|
|
28
|
+
case a
|
29
|
+
when String
|
30
|
+
a
|
31
|
+
when TERM
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
_, name = parameters.pop
|
35
|
+
"{#{name}}"
|
36
|
+
end
|
37
|
+
end.compact
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
3
43
|
if defined?(::Roda)
|
4
44
|
::Instana.logger.debug "Instrumenting Roda"
|
5
45
|
Roda.use ::Instana::Rack
|
46
|
+
Roda.plugin ::Instana::RodaPathTemplateExtractor
|
6
47
|
end
|
@@ -3,7 +3,24 @@ require "instana/rack"
|
|
3
3
|
# This instrumentation will insert Rack into Sinatra _and_ Padrino since
|
4
4
|
# the latter is based on Sinatra
|
5
5
|
|
6
|
+
module Instana
|
7
|
+
module SinatraPathTemplateExtractor
|
8
|
+
def self.extended(base)
|
9
|
+
::Instana.logger.debug "#{base} extended #{self}"
|
10
|
+
base.store_path_template
|
11
|
+
end
|
12
|
+
|
13
|
+
def store_path_template
|
14
|
+
after do
|
15
|
+
@env["INSTANA_HTTP_PATH_TEMPLATE"] = @env["sinatra.route"]
|
16
|
+
.sub("#{@request.request_method} ", '')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
6
22
|
if defined?(::Sinatra)
|
7
23
|
::Instana.logger.debug "Instrumenting Sinatra"
|
8
24
|
::Sinatra::Base.use ::Instana::Rack
|
25
|
+
::Sinatra::Base.register ::Instana::SinatraPathTemplateExtractor
|
9
26
|
end
|
@@ -7,7 +7,7 @@ if defined?(::Excon) && ::Instana.config[:excon][:enabled]
|
|
7
7
|
|
8
8
|
payload = { :http => {} }
|
9
9
|
path = datum[:path].split('?').first
|
10
|
-
payload[:http][:url] = "#{datum[:connection].instance_variable_get(:@socket_key)}#{path}"
|
10
|
+
payload[:http][:url] = ::Instana.secrets.remove_from_query("#{datum[:connection].instance_variable_get(:@socket_key)}#{path}")
|
11
11
|
payload[:http][:method] = datum[:method] if datum.key?(:method)
|
12
12
|
|
13
13
|
if datum[:pipeline] == true
|
@@ -0,0 +1,77 @@
|
|
1
|
+
if defined?(GraphQL::Schema) && defined?(GraphQL::Tracing::PlatformTracing) && ::Instana.config[:graphql][:enabled]
|
2
|
+
module Instana
|
3
|
+
class GraphqlTracing < GraphQL::Tracing::PlatformTracing
|
4
|
+
self.platform_keys = {
|
5
|
+
'lex' => 'lex.graphql',
|
6
|
+
'parse' => 'parse.graphql',
|
7
|
+
'validate' => 'validate.graphql',
|
8
|
+
'analyze_query' => 'analyze.graphql',
|
9
|
+
'analyze_multiplex' => 'analyze.graphql',
|
10
|
+
'execute_multiplex' => 'execute.graphql',
|
11
|
+
'execute_query' => 'execute.graphql',
|
12
|
+
'execute_query_lazy' => 'execute.graphql',
|
13
|
+
}
|
14
|
+
|
15
|
+
def platform_trace(platform_key, key, data)
|
16
|
+
return yield unless key == 'execute_query'
|
17
|
+
operation = data[:query].selected_operation
|
18
|
+
|
19
|
+
arguments = []
|
20
|
+
fields = []
|
21
|
+
|
22
|
+
operation.selections.each do |field|
|
23
|
+
arguments.concat(walk_fields(field, :arguments))
|
24
|
+
fields.concat(walk_fields(field, :selections))
|
25
|
+
end
|
26
|
+
|
27
|
+
payload = {
|
28
|
+
operationName: data[:query].operation_name || 'anonymous',
|
29
|
+
operationType: operation.operation_type,
|
30
|
+
arguments: grouped_fields(arguments),
|
31
|
+
fields: grouped_fields(fields),
|
32
|
+
}
|
33
|
+
|
34
|
+
begin
|
35
|
+
::Instana.tracer.log_entry(:'graphql.server')
|
36
|
+
yield
|
37
|
+
rescue Exception => e
|
38
|
+
::Instana.tracer.log_error(e)
|
39
|
+
raise e
|
40
|
+
ensure
|
41
|
+
::Instana.tracer.log_exit(:'graphql.server', {graphql: payload})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def platform_field_key(type, field)
|
46
|
+
"#{type.graphql_name}.#{field.graphql_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def platform_authorized_key(type)
|
50
|
+
"#{type.graphql_name}.authorized.graphql"
|
51
|
+
end
|
52
|
+
|
53
|
+
def platform_resolve_type_key(type)
|
54
|
+
"#{type.graphql_name}.resolve_type.graphql"
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def walk_fields(parent, method)
|
60
|
+
return [] unless parent.respond_to?(method)
|
61
|
+
|
62
|
+
parent.send(method).map do |field|
|
63
|
+
[{object: parent.name, field: field.name}] + walk_fields(field, method)
|
64
|
+
end.flatten
|
65
|
+
end
|
66
|
+
|
67
|
+
def grouped_fields(fields)
|
68
|
+
fields
|
69
|
+
.group_by { |p| p[:object] }
|
70
|
+
.map { |name, p| [name, p.map { |f| f[:field] }] }
|
71
|
+
.to_h
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
::GraphQL::Schema.use(::Instana::GraphqlTracing)
|
77
|
+
end
|