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.

Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +26 -37
  3. data/gemfiles/libraries.gemfile +2 -0
  4. data/lib/instana/agent.rb +6 -0
  5. data/lib/instana/base.rb +2 -0
  6. data/lib/instana/config.rb +11 -0
  7. data/lib/instana/frameworks/cuba.rb +33 -0
  8. data/lib/instana/frameworks/instrumentation/action_controller.rb +11 -0
  9. data/lib/instana/frameworks/instrumentation/mysql2_adapter.rb +7 -1
  10. data/lib/instana/frameworks/instrumentation/mysql_adapter.rb +7 -1
  11. data/lib/instana/frameworks/instrumentation/postgresql_adapter.rb +23 -5
  12. data/lib/instana/frameworks/roda.rb +41 -0
  13. data/lib/instana/frameworks/sinatra.rb +17 -0
  14. data/lib/instana/instrumentation/excon.rb +1 -1
  15. data/lib/instana/instrumentation/graphql.rb +77 -0
  16. data/lib/instana/instrumentation/net-http.rb +2 -0
  17. data/lib/instana/instrumentation/rack.rb +5 -0
  18. data/lib/instana/secrets.rb +42 -0
  19. data/lib/instana/setup.rb +1 -0
  20. data/lib/instana/tracing/span.rb +23 -10
  21. data/lib/instana/version.rb +1 -1
  22. data/test/apps/cuba.rb +4 -0
  23. data/test/apps/roda.rb +3 -0
  24. data/test/apps/sinatra.rb +4 -0
  25. data/test/config_test.rb +1 -17
  26. data/test/frameworks/cuba_test.rb +14 -1
  27. data/test/frameworks/rack_test.rb +27 -15
  28. data/test/frameworks/rails/actioncontroller_test.rb +12 -0
  29. data/test/frameworks/rails/activerecord_test.rb +80 -28
  30. data/test/frameworks/roda_test.rb +14 -0
  31. data/test/frameworks/sinatra_test.rb +14 -0
  32. data/test/instrumentation/excon_test.rb +0 -2
  33. data/test/instrumentation/graphql_test.rb +116 -0
  34. data/test/instrumentation/redis_test.rb +10 -0
  35. data/test/secrets_test.rb +73 -0
  36. data/test/tracing/tracer_test.rb +31 -1
  37. metadata +12 -8
  38. data/test/tracing/trace_test.rb +0 -67
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d29c335511f3dec4cac5857ac4d1b84b1b84f70a2f5974ed9b0f20992dc2cb7
4
- data.tar.gz: 9560b29a9d7902f0f013a4b586fed564c8eb854a6e700e1798e8c71463dbdf7a
3
+ metadata.gz: e0c2b0b0e44a5aa72f401d7ab7009125c25d182c01aa01aade80a8ca9f9fc55b
4
+ data.tar.gz: d147f265753ba3397773197b366f8a24f53a4e928ca8e08a929664c7d5029a1e
5
5
  SHA512:
6
- metadata.gz: ccd6ac828673bf6f731b0b75d09f4009a6f02e74c80eb2258af40e5993e0dd15c710e4936c2db53691a7a8f43234adbed0bbe45e13d9fe56ce99dbd2491ddf47
7
- data.tar.gz: 347b2d4e384e37e74ce51d68bbce5059e4f8de7d1ea0aa7ab6dbb82b7ddc4c67d6b97479f1de8152c9fff988994e3daf0642f34712f0a152eaa3ba80b975de3a
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
- t.test_files = FileList['test/**/*_test.rb']
12
-
13
- if ENV.key?('BUNDLE_GEMFILE')
14
- case File.basename(ENV['BUNDLE_GEMFILE']).split('.').first
15
- when /rails6/
16
- t.test_files = %w(test/frameworks/rails/activerecord_test.rb
17
- test/frameworks/rails/actioncontroller_test.rb
18
- test/frameworks/rails/actionview5_test.rb)
19
- when /rails5/
20
- t.test_files = %w(test/frameworks/rails/activerecord_test.rb
21
- test/frameworks/rails/actioncontroller_test.rb
22
- test/frameworks/rails/actionview5_test.rb)
23
- when /rails42/
24
- t.test_files = %w(test/frameworks/rails/activerecord_test.rb
25
- test/frameworks/rails/actioncontroller_test.rb
26
- test/frameworks/rails/actionview4_test.rb)
27
- when /rails32/
28
- t.test_files = %w(test/frameworks/rails/activerecord_test.rb
29
- test/frameworks/rails/actioncontroller_test.rb
30
- test/frameworks/rails/actionview3_test.rb)
31
- when /libraries/
32
- t.test_files = FileList['test/instrumentation/*_test.rb',
33
- 'test/frameworks/cuba_test.rb',
34
- 'test/frameworks/rack_test.rb',
35
- 'test/frameworks/roda_test.rb',
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
@@ -65,6 +65,8 @@ if RUBY_VERSION < '2.2'
65
65
  gem 'rack', '< 2.0'
66
66
  end
67
67
 
68
+ gem 'graphql'
69
+
68
70
  # Include the Instana Ruby gem's base set of gems
69
71
  gemspec :path => File.expand_path(File.dirname(__FILE__) + '/../')
70
72
 
@@ -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']
@@ -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
@@ -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
- payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
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
- payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
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
- payload[:activerecord][:sql] = sql.gsub(@@sanitize_regexp, '?')
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