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
@@ -32,6 +32,8 @@ if defined?(::Net::HTTP) && ::Instana.config[:nethttp][:enabled]
32
32
  kv_payload[:http][:url] = "http://#{@address}:#{@port}#{request.path}"
33
33
  end
34
34
  end
35
+
36
+ kv_payload[:http][:url] = ::Instana.secrets.remove_from_query(kv_payload[:http][:url])
35
37
 
36
38
  # The core call
37
39
  response = request_without_instana(*args, &block)
@@ -76,6 +76,11 @@ module Instana
76
76
  ::Instana.tracer.log_error(nil)
77
77
  end
78
78
 
79
+ # If the framework instrumentation provides a path template,
80
+ # pass it into the span here.
81
+ # See: https://www.instana.com/docs/tracing/custom-best-practices/#path-templates-visual-grouping-of-http-endpoints
82
+ kvs[:http][:path_tpl] = env['INSTANA_HTTP_PATH_TEMPLATE'] if env['INSTANA_HTTP_PATH_TEMPLATE']
83
+
79
84
  # Save the IDs before the trace ends so we can place
80
85
  # them in the response headers in the ensure block
81
86
  trace_id = ::Instana.tracer.current_span.trace_id
@@ -0,0 +1,42 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+
4
+ module Instana
5
+ class Secrets
6
+ def remove_from_query(str, secret_values = Instana.agent.secret_values)
7
+ return str unless secret_values
8
+
9
+ url = URI(str)
10
+ params = CGI.parse(url.query)
11
+
12
+ redacted = params.map do |k, v|
13
+ needs_redaction = secret_values['list']
14
+ .any? { |t| matcher(secret_values['matcher']).(t,k) }
15
+ [k, needs_redaction ? '<redacted>' : v]
16
+ end
17
+
18
+ url.query = URI.encode_www_form(redacted)
19
+ CGI.unescape(url.to_s)
20
+ end
21
+
22
+ private
23
+
24
+ def matcher(name)
25
+ case name
26
+ when 'equals-ignore-case'
27
+ ->(expected, actual) { expected.casecmp(actual) == 0 }
28
+ when 'equals'
29
+ ->(expected, actual) { (expected <=> actual) == 0 }
30
+ when 'contains-ignore-case'
31
+ ->(expected, actual) { actual.downcase.include?(expected) }
32
+ when 'contains'
33
+ ->(expected, actual) { actual.include?(expected) }
34
+ when 'regex'
35
+ ->(expected, actual) { !Regexp.new(expected).match(actual).nil? }
36
+ else
37
+ ::Instana.logger.warn("Matcher #{name} is not supported.")
38
+ lambda { false }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -4,6 +4,7 @@ require "instana/base"
4
4
  require "instana/config"
5
5
  require "instana/agent"
6
6
  require "instana/collector"
7
+ require "instana/secrets"
7
8
  require "instana/tracer"
8
9
  require "instana/tracing/processor"
9
10
  require "instana/instrumentation"
@@ -3,8 +3,8 @@ module Instana
3
3
  REGISTERED_SPANS = [ :actioncontroller, :actionview, :activerecord, :excon,
4
4
  :memcache, :'net-http', :rack, :render, :'rpc-client',
5
5
  :'rpc-server', :'sidekiq-client', :'sidekiq-worker',
6
- :redis, :'resque-client', :'resque-worker' ].freeze
7
- ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker' ].freeze
6
+ :redis, :'resque-client', :'resque-worker', :'graphql.server' ].freeze
7
+ ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server' ].freeze
8
8
  EXIT_SPANS = [ :activerecord, :excon, :'net-http', :'resque-client',
9
9
  :'rpc-client', :'sidekiq-client', :redis ].freeze
10
10
  HTTP_SPANS = [ :rack, :excon, :'net-http' ].freeze
@@ -57,9 +57,6 @@ module Instana
57
57
  end
58
58
 
59
59
  if ::Instana.config[:collect_backtraces]
60
- # For entry spans, add a backtrace fingerprint
61
- add_stack(limit: 2) if ENTRY_SPANS.include?(name)
62
-
63
60
  # Attach a backtrace to all exit spans
64
61
  add_stack if EXIT_SPANS.include?(name)
65
62
  end
@@ -76,9 +73,11 @@ module Instana
76
73
  #
77
74
  # @param limit [Integer] Limit the backtrace to the top <limit> frames
78
75
  #
79
- def add_stack(limit: nil, stack: Kernel.caller)
76
+ def add_stack(limit: 30, stack: Kernel.caller)
80
77
  frame_count = 0
78
+ sanitized_stack = []
81
79
  @data[:stack] = []
80
+ limit = 40 if limit > 40
82
81
 
83
82
  stack.each do |i|
84
83
  # If the stack has the full instana gem version in it's path
@@ -86,18 +85,23 @@ module Instana
86
85
  if !i.match(/instana\/instrumentation\/rack.rb/).nil? ||
87
86
  (i.match(::Instana::VERSION_FULL).nil? && i.match('lib/instana/').nil?)
88
87
 
89
- break if limit && frame_count >= limit
90
-
91
88
  x = i.split(':')
92
89
 
93
- @data[:stack] << {
90
+ sanitized_stack << {
94
91
  :c => x[0],
95
92
  :n => x[1],
96
93
  :m => x[2]
97
94
  }
98
- frame_count = frame_count + 1 if limit
99
95
  end
100
96
  end
97
+
98
+ if sanitized_stack.length > limit
99
+ # (limit * -1) gives us negative form of <limit> used for
100
+ # slicing from the end of the list. e.g. stack[-30, 30]
101
+ @data[:stack] = sanitized_stack[limit*-1, limit]
102
+ else
103
+ @data[:stack] = sanitized_stack
104
+ end
101
105
  end
102
106
 
103
107
  # Log an error into the span
@@ -303,6 +307,15 @@ module Instana
303
307
  # a String, Numeric, or Boolean it will be encoded with to_s
304
308
  #
305
309
  def set_tag(key, value)
310
+ if ![Symbol, String].include?(key.class)
311
+ key = key.to_s
312
+ end
313
+
314
+ # If <value> is not a Symbol, String, Array, Hash or Numeric - convert to string
315
+ if ![Symbol, String, Array, TrueClass, FalseClass, Hash].include?(value.class) && !value.is_a?(Numeric)
316
+ value = value.to_s
317
+ end
318
+
306
319
  if custom?
307
320
  @data[:data][:sdk][:custom] ||= {}
308
321
  @data[:data][:sdk][:custom][:tags] ||= {}
@@ -1,4 +1,4 @@
1
1
  module Instana
2
- VERSION = "1.11.7"
2
+ VERSION = "1.193.1"
3
3
  VERSION_FULL = "instana-#{VERSION}"
4
4
  end
@@ -7,6 +7,10 @@ Cuba.define do
7
7
  on "hello" do
8
8
  res.write "Hello Instana!"
9
9
  end
10
+
11
+ on "greet/:name" do |name|
12
+ res.write "Hello, #{name}"
13
+ end
10
14
 
11
15
  on root do
12
16
  res.redirect '/hello'
@@ -6,5 +6,8 @@ class InstanaRodaApp < Roda
6
6
  r.get "hello" do
7
7
  "Hello Roda + Instana"
8
8
  end
9
+ r.get "greet", String do |name|
10
+ "Hello, #{name}!"
11
+ end
9
12
  end
10
13
  end
@@ -2,4 +2,8 @@ class InstanaSinatraApp < ::Sinatra::Base
2
2
  get '/' do
3
3
  "Hello Sinatra!"
4
4
  end
5
+
6
+ get '/greet/:name' do
7
+ "Hello, #{params[:name]}!"
8
+ end
5
9
  end
@@ -10,28 +10,12 @@ class ConfigTest < Minitest::Test
10
10
  assert_equal '127.0.0.1', ::Instana.config[:agent_host]
11
11
  assert_equal 42699, ::Instana.config[:agent_port]
12
12
 
13
- assert ::Instana.config[:enabled]
14
13
  assert ::Instana.config[:tracing][:enabled]
15
14
  assert ::Instana.config[:metrics][:enabled]
16
15
 
17
16
  ::Instana.config[:metrics].each do |k, v|
17
+ next unless v.is_a? Hash
18
18
  assert_equal true, ::Instana.config[:metrics][k].key?(:enabled)
19
19
  end
20
20
  end
21
-
22
- def test_that_global_affects_children
23
- # Disabling the gem should explicitly disable
24
- # metrics and tracing flags
25
- ::Instana.config[:enabled] = false
26
-
27
- assert_equal false, ::Instana.config[:tracing][:enabled]
28
- assert_equal false, ::Instana.config[:metrics][:enabled]
29
-
30
- # Enabling the gem should explicitly enable
31
- # metrics and tracing flags
32
- ::Instana.config[:enabled] = true
33
-
34
- assert_equal ::Instana.config[:tracing][:enabled]
35
- assert_equal ::Instana.config[:metrics][:enabled]
36
- end
37
21
  end
@@ -1,4 +1,3 @@
1
-
2
1
  if defined?(::Cuba)
3
2
  require 'test_helper'
4
3
  require File.expand_path(File.dirname(__FILE__) + '/../apps/cuba')
@@ -40,5 +39,19 @@ if defined?(::Cuba)
40
39
  assert first_span[:data][:http].key?(:host)
41
40
  assert_equal "example.org", first_span[:data][:http][:host]
42
41
  end
42
+
43
+ def test_path_template
44
+ clear_all!
45
+
46
+ r = get '/greet/instana'
47
+ assert last_response.ok?
48
+
49
+ spans = ::Instana.processor.queued_spans
50
+ assert_equal 1, spans.count
51
+
52
+ first_span = spans.first
53
+ assert_equal :rack, first_span[:n]
54
+ assert_equal '/greet/{name}', first_span[:data][:http][:path_tpl]
55
+ end
43
56
  end
44
57
  end
@@ -5,16 +5,22 @@ require "instana/rack"
5
5
 
6
6
  class RackTest < Minitest::Test
7
7
  include Rack::Test::Methods
8
+
9
+ class PathTemplateApp
10
+ def call(env)
11
+ env['INSTANA_HTTP_PATH_TEMPLATE'] = 'sample_template'
12
+ [200, {}, ['Ok']]
13
+ end
14
+ end
8
15
 
9
16
  def app
10
- @app = Rack::Builder.new {
17
+ @app = Rack::Builder.new do
11
18
  use Rack::CommonLogger
12
19
  use Rack::ShowExceptions
13
20
  use Instana::Rack
14
- map "/mrlobster" do
15
- run Rack::Lobster.new
16
- end
17
- }
21
+ map("/mrlobster") { run Rack::Lobster.new }
22
+ map("/path_tpl") { run PathTemplateApp.new }
23
+ end
18
24
  end
19
25
 
20
26
  def test_basic_get
@@ -51,11 +57,7 @@ class RackTest < Minitest::Test
51
57
  assert rack_span[:f].key?(:e)
52
58
  assert rack_span[:f].key?(:h)
53
59
  assert_equal ::Instana.agent.agent_uuid, rack_span[:f][:h]
54
-
55
- # Backtrace fingerprint validation
56
- assert rack_span.key?(:stack)
57
- assert_equal 2, rack_span[:stack].count
58
- refute_nil rack_span[:stack].first[:c].match(/instana\/instrumentation\/rack.rb/)
60
+ assert !rack_span.key?(:stack)
59
61
 
60
62
  # Restore to default
61
63
  ::Instana.config[:collect_backtraces] = false
@@ -227,14 +229,24 @@ class RackTest < Minitest::Test
227
229
  assert rack_span[:data][:http][:header].key?(:"X-Capture-This")
228
230
  assert !rack_span[:data][:http][:header].key?(:"X-Capture-That")
229
231
  assert_equal "ThereYouGo", rack_span[:data][:http][:header][:"X-Capture-This"]
230
-
231
- # Backtrace fingerprint validation
232
- assert rack_span.key?(:stack)
233
- assert_equal 2, rack_span[:stack].count
234
- refute_nil rack_span[:stack].first[:c].match(/instana\/instrumentation\/rack.rb/)
232
+ assert !rack_span.key?(:stack)
235
233
 
236
234
  # Restore to default
237
235
  ::Instana.config[:collect_backtraces] = false
238
236
  ::Instana.agent.extra_headers = nil
239
237
  end
238
+
239
+ def test_capture_http_path_template
240
+ clear_all!
241
+
242
+ get '/path_tpl'
243
+ assert last_response.ok?
244
+
245
+ spans = ::Instana.processor.queued_spans
246
+ assert_equal 1, spans.length
247
+
248
+ rack_span = spans.first
249
+ assert_equal :rack, rack_span[:n]
250
+ assert_equal 'sample_template', rack_span[:data][:http][:path_tpl]
251
+ end
240
252
  end
@@ -153,4 +153,16 @@ class ActionControllerTest < Minitest::Test
153
153
  assert ac_span.key?(:stack)
154
154
  assert 1, ac_span[:ec]
155
155
  end
156
+
157
+ def test_path_template
158
+ clear_all!
159
+
160
+ Net::HTTP.get(URI.parse('http://localhost:3205/test/world'))
161
+
162
+ spans = ::Instana.processor.queued_spans
163
+ rack_span = find_first_span_by_name(spans, :rack)
164
+
165
+ assert_equal false, rack_span.key?(:error)
166
+ assert_equal '/test/world(.:format)', rack_span[:data][:http][:path_tpl]
167
+ end
156
168
  end
@@ -2,7 +2,14 @@ require 'test_helper'
2
2
  require 'active_record'
3
3
 
4
4
  class ActiveRecordTest < Minitest::Test
5
+
6
+ def teardown
7
+ # Make sure defaults are back in place
8
+ ::Instana.config[:sanitize_sql] = true
9
+ end
10
+
5
11
  def test_config_defaults
12
+ assert ::Instana.config[:sanitize_sql] == true
6
13
  assert ::Instana.config[:active_record].is_a?(Hash)
7
14
  assert ::Instana.config[:active_record].key?(:enabled)
8
15
  assert_equal true, ::Instana.config[:active_record][:enabled]
@@ -28,19 +35,14 @@ class ActiveRecordTest < Minitest::Test
28
35
  assert span[:data][:activerecord].key?(:username)
29
36
  end
30
37
 
31
-
32
- found = false
33
38
  if ::Rails::VERSION::MAJOR < 4
34
39
  sql = "INSERT INTO \"blocks\" (\"color\", \"created_at\", \"name\", \"updated_at\") VALUES ($?, $?, $?, $?) RETURNING \"id\""
35
40
  else
36
41
  sql = "INSERT INTO \"blocks\" (\"name\", \"color\", \"created_at\", \"updated_at\") VALUES ($?, $?, $?, $?) RETURNING \"id\""
37
42
  end
38
- ar_spans.each do |span|
39
- if span[:data][:activerecord][:sql] ==
40
- found = true
41
- end
43
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
44
+ span[:data][:activerecord][:sql] == sql
42
45
  end
43
- assert found
44
46
 
45
47
  found = false
46
48
  if ::Rails::VERSION::MAJOR >= 5
@@ -50,12 +52,9 @@ class ActiveRecordTest < Minitest::Test
50
52
  else
51
53
  sql = "SELECT \"blocks\".* FROM \"blocks\" WHERE \"blocks\".\"name\" = ? LIMIT ?"
52
54
  end
53
- ar_spans.each do |span|
54
- if span[:data][:activerecord][:sql] == sql
55
- found = true
56
- end
55
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
56
+ span[:data][:activerecord][:sql] == sql
57
57
  end
58
- assert found
59
58
 
60
59
  found = false
61
60
  if ::Rails::VERSION::MAJOR == 3
@@ -63,12 +62,73 @@ class ActiveRecordTest < Minitest::Test
63
62
  else
64
63
  sql = "DELETE FROM \"blocks\" WHERE \"blocks\".\"id\" = $?"
65
64
  end
65
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
66
+ span[:data][:activerecord][:sql] == sql
67
+ end
68
+ end
69
+
70
+ def test_postgresql_without_sanitize
71
+ skip unless ::Instana::Test.postgresql?
72
+
73
+ # Shut SQL sanitization off
74
+ ::Instana.config[:sanitize_sql] = false
75
+ # Pause so the thread can syncronize values
76
+ sleep 1
77
+
78
+ clear_all!
79
+
80
+ Net::HTTP.get(URI.parse('http://localhost:3205/test/db'))
81
+
82
+ spans = Instana.processor.queued_spans
83
+ assert_equal 6, spans.length
84
+ rack_span = find_first_span_by_name(spans, :rack)
85
+
86
+ ar_spans = find_spans_by_name(spans, :activerecord)
87
+ assert_equal 3, ar_spans.length
88
+
66
89
  ar_spans.each do |span|
67
- if span[:data][:activerecord][:sql] == sql
68
- found = true
69
- end
90
+ assert_equal "postgresql", span[:data][:activerecord][:adapter]
91
+ assert span[:data][:activerecord].key?(:host)
92
+ assert span[:data][:activerecord].key?(:username)
93
+ end
94
+
95
+ if ::Rails::VERSION::MAJOR < 4
96
+ sql = "INSERT INTO \"blocks\" (\"color\", \"created_at\", \"name\", \"updated_at\") VALUES ($1, $2, $3, $4) RETURNING \"id\""
97
+ else
98
+ sql = "INSERT INTO \"blocks\" (\"name\", \"color\", \"created_at\", \"updated_at\") VALUES ($1, $2, $3, $4) RETURNING \"id\""
70
99
  end
71
- assert found
100
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
101
+ span[:data][:activerecord][:sql] == sql
102
+ end
103
+ assert ar_span[:data][:activerecord].key?(:binds)
104
+ assert ar_span[:data][:activerecord][:binds].is_a?(Array)
105
+ assert_equal 4, ar_span[:data][:activerecord][:binds].length
106
+
107
+ if ::Rails::VERSION::MAJOR >= 5
108
+ sql = "SELECT \"blocks\".* FROM \"blocks\" WHERE \"blocks\".\"name\" = $1 ORDER BY \"blocks\".\"id\" ASC LIMIT $2"
109
+ elsif ::Rails::VERSION::MAJOR == 4
110
+ sql = "SELECT \"blocks\".* FROM \"blocks\" WHERE \"blocks\".\"name\" = $? ORDER BY \"blocks\".\"id\" ASC LIMIT ?"
111
+ else
112
+ sql = "SELECT \"blocks\".* FROM \"blocks\" WHERE \"blocks\".\"name\" = ? LIMIT ?"
113
+ end
114
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
115
+ span[:data][:activerecord][:sql] == sql
116
+ end
117
+ assert ar_span[:data][:activerecord].key?(:binds)
118
+ assert ar_span[:data][:activerecord][:binds].is_a?(Array)
119
+ assert_equal 2, ar_span[:data][:activerecord][:binds].length
120
+
121
+ if ::Rails::VERSION::MAJOR == 3
122
+ sql = "DELETE FROM \"blocks\" WHERE \"blocks\".\"id\" = 1"
123
+ else
124
+ sql = "DELETE FROM \"blocks\" WHERE \"blocks\".\"id\" = $1"
125
+ end
126
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
127
+ span[:data][:activerecord][:sql] == sql
128
+ end
129
+ assert ar_span[:data][:activerecord].key?(:binds)
130
+ assert ar_span[:data][:activerecord][:binds].is_a?(Array)
131
+ assert_equal 1, ar_span[:data][:activerecord][:binds].length
72
132
  end
73
133
 
74
134
  def test_postgresql_lock_table
@@ -93,21 +153,13 @@ class ActiveRecordTest < Minitest::Test
93
153
  assert_equal "postgres", ar_span[:data][:activerecord][:username]
94
154
  end
95
155
 
96
- found = false
97
- ar_spans.each do |span|
98
- if span[:data][:activerecord][:sql] == "LOCK blocks IN ACCESS EXCLUSIVE MODE"
99
- found = true
100
- end
156
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
157
+ span[:data][:activerecord][:sql] == "LOCK blocks IN ACCESS EXCLUSIVE MODE"
101
158
  end
102
- assert found
103
159
 
104
- found = false
105
- ar_spans.each do |span|
106
- if span[:data][:activerecord][:sql] == "SELECT ?"
107
- found = true
108
- end
160
+ ar_span = find_first_span_by_qualifier(ar_spans) do |span|
161
+ span[:data][:activerecord][:sql] == "SELECT ?"
109
162
  end
110
- assert found
111
163
  end
112
164
 
113
165
  def test_postgresql_raw_execute