instana 1.192.0 → 1.192.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 424f7ce1ff02d56a5498df4f3f861231c30f5032cf02e8604e008155c389f4b5
4
- data.tar.gz: aac1bf703a70d5c7039fbae031846d513a5d3d9d2c5d00630308eacd8b862095
3
+ metadata.gz: 1671f39523faeeea826d7892820992a88ffbb3f923fb20b3c19c082dc281480a
4
+ data.tar.gz: a6f70177f02c753830fea6075556a70cd4c3ccd30e083d0e316f638396ea6c44
5
5
  SHA512:
6
- metadata.gz: c9470f7a3f6e1d7198a99d8017556689b0eaffb3bc22677064cbb1f5552f80c8814d481dc842b8a082e5a9c5a6cb86b0f46d95cbbc8055d56c7b2588277bbdaa
7
- data.tar.gz: c9e83f799f6b343e6dd98840fcdc48175cc52d9a876c9421e053909bf0dcbfaaf384669b449ce53edf3bd0478ece21484c01c27fd24b6247efcc86ad0a56b0f0
6
+ metadata.gz: be7333bc5dab3edff9342fd0f6a311b45df11a2fd58c9f61153e32fa3f638ac359a750365204655b6933dac90259e991fb1bddd9b9214f1d7f3fe62159c0d69b
7
+ data.tar.gz: bdc9a0ee62692ff327a849732508cf6656b76d24206528d8120830b764b2968bf040a1d93f9735f7004c1e2104c8e394f8c68834a91e1e3eaf3a2861247b295c
@@ -0,0 +1,10 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+
7
+ [*.rb]
8
+ indent_style = space
9
+ indent_size = 2
10
+ trim_trailing_whitespace = true
@@ -0,0 +1,68 @@
1
+ # Note: We really only need "cgi/util" here but Ruby 2.4.1 has an issue:
2
+ # https://bugs.ruby-lang.org/issues/13539
3
+ require "cgi"
4
+
5
+ module Instana
6
+ class InstrumentedRequest < Rack::Request
7
+ def skip_trace?
8
+ # Honor X-Instana-L
9
+ @env.has_key?('HTTP_X_INSTANA_L') && @env['HTTP_X_INSTANA_L'].start_with?('0')
10
+ end
11
+
12
+ def incoming_context
13
+ context = {}
14
+
15
+ if @env['HTTP_X_INSTANA_T']
16
+ context[:trace_id] = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T'])
17
+ context[:span_id] = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_S']) if @env['HTTP_X_INSTANA_S']
18
+ context[:level] = @env['HTTP_X_INSTANA_L'][0] if @env['HTTP_X_INSTANA_L']
19
+ end
20
+
21
+ context
22
+ end
23
+
24
+ def extra_header_tags
25
+ return nil unless ::Instana.agent.extra_headers
26
+ headers = {}
27
+
28
+ ::Instana.agent.extra_headers.each do |custom_header|
29
+ # Headers are available in this format: HTTP_X_CAPTURE_THIS
30
+ rack_header = 'HTTP_' + custom_header.upcase
31
+ rack_header.tr!('-', '_')
32
+
33
+ headers[custom_header.to_sym] = @env[rack_header] if @env.has_key?(rack_header)
34
+ end
35
+
36
+ headers
37
+ end
38
+
39
+ def request_tags
40
+ {
41
+ method: request_method,
42
+ url: CGI.unescape(path_info),
43
+ host: host_with_port,
44
+ header: extra_header_tags
45
+ }.compact
46
+ end
47
+
48
+ def correlation_data
49
+ @correlation_data ||= parse_correlation_data
50
+ end
51
+
52
+ private
53
+
54
+ def parse_correlation_data
55
+ return {} unless @env.has_key?('HTTP_X_INSTANA_L')
56
+ _level, *tokens = @env['HTTP_X_INSTANA_L'].split(/[,=;]/)
57
+ data = tokens
58
+ .map { |t| t.strip }
59
+ .each_slice(2)
60
+ .select { |a| a.length == 2 }.to_h
61
+
62
+ {
63
+ type: data['correlationType'],
64
+ id: data['correlationId']
65
+ }.compact
66
+ end
67
+ end
68
+ end
@@ -1,6 +1,4 @@
1
- # Note: We really only need "cgi/util" here but Ruby 2.4.1 has an issue:
2
- # https://bugs.ruby-lang.org/issues/13539
3
- require "cgi"
1
+ require 'instana/instrumentation/instrumented_request'
4
2
 
5
3
  module Instana
6
4
  class Rack
@@ -8,59 +6,21 @@ module Instana
8
6
  @app = app
9
7
  end
10
8
 
11
- def collect_kvs(env)
12
- kvs = {}
13
- kvs[:http] = {}
14
- kvs[:http][:method] = env['REQUEST_METHOD']
15
- kvs[:http][:url] = ::CGI.unescape(env['PATH_INFO'])
16
-
17
- if env.key?('HTTP_HOST')
18
- kvs[:http][:host] = env['HTTP_HOST']
19
- elsif env.key?('SERVER_NAME')
20
- kvs[:http][:host] = env['SERVER_NAME']
21
- end
22
-
23
- if ENV.key?('INSTANA_SERVICE_NAME')
24
- kvs[:service] = ENV['INSTANA_SERVICE_NAME']
25
- end
26
-
27
- if ::Instana.agent.extra_headers
28
- ::Instana.agent.extra_headers.each { |custom_header|
29
- # Headers are available in this format: HTTP_X_CAPTURE_THIS
30
- rack_header = 'HTTP_' + custom_header.upcase
31
- rack_header.tr!('-', '_')
32
-
33
- if env.key?(rack_header)
34
- unless kvs[:http].key?(:header)
35
- kvs[:http][:header] = {}
36
- end
37
- kvs[:http][:header][custom_header.to_sym] = env[rack_header]
38
- end
39
- }
40
- end
41
- return kvs
42
- end
43
-
44
9
  def call(env)
45
- # Check incoming context
46
- incoming_context = {}
47
- if env.key?('HTTP_X_INSTANA_T')
48
- incoming_context[:trace_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_T'])
49
- incoming_context[:span_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_S']) if env.key?('HTTP_X_INSTANA_S')
50
- incoming_context[:level] = env['HTTP_X_INSTANA_L'] if env.key?('HTTP_X_INSTANA_L')
51
-
52
- # Honor X-Instana-L
53
- if incoming_context[:level] and incoming_context[:level].length > 0
54
- if incoming_context[:level][0] == "0"
55
- return @app.call(env)
56
- end
57
- end
10
+ req = InstrumentedRequest.new(env)
11
+ return @app.call(env) if req.skip_trace?
12
+ kvs = {
13
+ http: req.request_tags,
14
+ service: ENV['INSTANA_SERVICE_NAME']
15
+ }.compact
16
+
17
+ current_span = ::Instana.tracer.log_start_or_continue(:rack, {}, req.incoming_context)
18
+
19
+ unless req.correlation_data.empty?
20
+ current_span[:crid] = req.correlation_data[:id]
21
+ current_span[:crtp] = req.correlation_data[:type]
58
22
  end
59
23
 
60
- kvs = collect_kvs(env)
61
-
62
- ::Instana.tracer.log_start_or_continue(:rack, {}, incoming_context)
63
-
64
24
  status, headers, response = @app.call(env)
65
25
 
66
26
  if ::Instana.tracer.tracing?
@@ -100,6 +100,12 @@ module Instana
100
100
  else
101
101
  self.current_span = Span.new(name)
102
102
  end
103
+
104
+ if incoming_context.is_a?(Hash) && incoming_context[:correlation] && !incoming_context[:correlation].empty?
105
+ self.current_span[:crid] = incoming_context[:correlation][:id]
106
+ self.current_span[:crtp] = incoming_context[:correlation][:type]
107
+ end
108
+
103
109
  self.current_span.set_tags(kvs) unless kvs.empty?
104
110
  self.current_span
105
111
  end
@@ -225,53 +225,39 @@ module Instana
225
225
  (time.to_f * 1000).floor
226
226
  end
227
227
 
228
- # Generate a random 64bit ID
228
+ # Generate a random 64bit/128bit ID
229
229
  #
230
- # @return [Integer] a random 64bit integer
230
+ # @param size [Integer] Number of 64 bit integers used to generate the id
231
231
  #
232
- def generate_id
233
- # Max value is 9223372036854775807 (signed long in Java)
234
- rand(ID_RANGE)
232
+ # @return [String] a random 64bit/128bit hex encoded string
233
+ #
234
+ def generate_id(size = 1)
235
+ Array.new(size) { rand(ID_RANGE) }
236
+ .pack('q>*')
237
+ .unpack('H*')
238
+ .first
235
239
  end
236
240
 
237
241
  # Convert an ID to a value appropriate to pass in a header.
238
242
  #
239
- # @param id [Integer] the id to be converted
243
+ # @param id [String] the id to be converted
240
244
  #
241
245
  # @return [String]
242
246
  #
243
247
  def id_to_header(id)
244
- unless id.is_a?(Integer) || id.is_a?(String)
245
- Instana.logger.debug "id_to_header received a #{id.class}: returning empty string"
246
- return String.new
247
- end
248
- [id.to_i].pack('q>').unpack('H*')[0].gsub(/^0+/, '')
249
- rescue => e
250
- Instana.logger.info "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
251
- Instana.logger.debug { e.backtrace.join("\r\n") }
248
+ return '' unless id.is_a?(String)
249
+ # Only send 64bit IDs downstream for now
250
+ id.length == 32 ? id[16..-1] : id
252
251
  end
253
252
 
254
253
  # Convert a received header value into a valid ID
255
254
  #
256
255
  # @param header_id [String] the header value to be converted
257
256
  #
258
- # @return [Integer]
257
+ # @return [String]
259
258
  #
260
259
  def header_to_id(header_id)
261
- if !header_id.is_a?(String)
262
- Instana.logger.debug "header_to_id received a #{header_id.class}: returning 0"
263
- return 0
264
- end
265
- if header_id.length < 16
266
- # The header is less than 16 chars. Prepend
267
- # zeros so we can convert correctly
268
- missing = 16 - header_id.length
269
- header_id = ("0" * missing) + header_id
270
- end
271
- [header_id].pack("H*").unpack("q>")[0]
272
- rescue => e
273
- Instana.logger.info "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
274
- Instana.logger.debug { e.backtrace.join("\r\n") }
260
+ header_id.is_a?(String) && header_id.match(/\A[a-z\d]{16,32}\z/i) ? header_id : ''
275
261
  end
276
262
  end
277
263
  end
@@ -1,4 +1,4 @@
1
1
  module Instana
2
- VERSION = "1.192.0"
2
+ VERSION = "1.192.1"
3
3
  VERSION_FULL = "instana-#{VERSION}"
4
4
  end
@@ -5,7 +5,7 @@ require "instana/rack"
5
5
 
6
6
  class RackTest < Minitest::Test
7
7
  include Rack::Test::Methods
8
-
8
+
9
9
  class PathTemplateApp
10
10
  def call(env)
11
11
  env['INSTANA_HTTP_PATH_TEMPLATE'] = 'sample_template'
@@ -147,8 +147,9 @@ class RackTest < Minitest::Test
147
147
 
148
148
  def test_context_continuation
149
149
  clear_all!
150
- header 'X-INSTANA-T', Instana::Util.id_to_header(1234)
151
- header 'X-INSTANA-S', Instana::Util.id_to_header(4321)
150
+ continuation_id = Instana::Util.generate_id
151
+ header 'X-INSTANA-T', continuation_id
152
+ header 'X-INSTANA-S', continuation_id
152
153
 
153
154
  get '/mrlobster'
154
155
  assert last_response.ok?
@@ -182,10 +183,30 @@ class RackTest < Minitest::Test
182
183
  # Context validation
183
184
  # The first span should have the passed in trace ID
184
185
  # and specify the passed in span ID as it's parent.
185
- assert_equal 1234, rack_span[:t]
186
- assert_equal 4321, rack_span[:p]
186
+ assert_equal continuation_id, rack_span[:t]
187
+ assert_equal continuation_id, rack_span[:p]
187
188
  end
188
189
 
190
+ def test_correlation_information
191
+ clear_all!
192
+
193
+ header 'X-INSTANA-L', '1,correlationType=test;correlationId=abcdefh123'
194
+
195
+ get '/mrlobster'
196
+ assert last_response.ok?
197
+
198
+ spans = ::Instana.processor.queued_spans
199
+
200
+ # Span validation
201
+ assert_equal 1, spans.count
202
+ rack_span = spans.first
203
+ assert_equal :rack, rack_span[:n]
204
+
205
+ assert_equal 'abcdefh123', rack_span[:crid]
206
+ assert_equal 'test', rack_span[:crtp]
207
+ end
208
+
209
+
189
210
  def test_instana_response_headers
190
211
  clear_all!
191
212
  get '/mrlobster'
@@ -235,16 +256,16 @@ class RackTest < Minitest::Test
235
256
  ::Instana.config[:collect_backtraces] = false
236
257
  ::Instana.agent.extra_headers = nil
237
258
  end
238
-
259
+
239
260
  def test_capture_http_path_template
240
261
  clear_all!
241
-
262
+
242
263
  get '/path_tpl'
243
264
  assert last_response.ok?
244
-
265
+
245
266
  spans = ::Instana.processor.queued_spans
246
267
  assert_equal 1, spans.length
247
-
268
+
248
269
  rack_span = spans.first
249
270
  assert_equal :rack, rack_span[:n]
250
271
  assert_equal 'sample_template', rack_span[:data][:http][:path_tpl]
@@ -0,0 +1,84 @@
1
+ require 'test_helper'
2
+
3
+ class InstrumentedRequestTest < Minitest::Test
4
+ def test_skip_trace_with_header
5
+ req = Instana::InstrumentedRequest.new(
6
+ 'HTTP_X_INSTANA_L' => '0;sample-data'
7
+ )
8
+
9
+ assert req.skip_trace?
10
+ end
11
+
12
+ def test_skip_trace_without_header
13
+ req = Instana::InstrumentedRequest.new({})
14
+
15
+ refute req.skip_trace?
16
+ end
17
+
18
+ def test_incomming_context
19
+ id = Instana::Util.generate_id
20
+ req = Instana::InstrumentedRequest.new(
21
+ 'HTTP_X_INSTANA_L' => '1',
22
+ 'HTTP_X_INSTANA_T' => id,
23
+ 'HTTP_X_INSTANA_S' => id
24
+ )
25
+
26
+ expected = {
27
+ trace_id: id,
28
+ span_id: id,
29
+ level: '1'
30
+ }
31
+
32
+ assert_equal expected, req.incoming_context
33
+ end
34
+
35
+ def test_request_tags
36
+ ::Instana.agent.extra_headers = %w[X-Capture-This]
37
+ req = Instana::InstrumentedRequest.new(
38
+ 'HTTP_HOST' => 'example.com',
39
+ 'REQUEST_METHOD' => 'GET',
40
+ 'HTTP_X_CAPTURE_THIS' => 'that',
41
+ 'PATH_INFO' => '/'
42
+ )
43
+
44
+ expected = {
45
+ method: 'GET',
46
+ url: '/',
47
+ host: 'example.com',
48
+ header: {
49
+ "X-Capture-This": 'that'
50
+ }
51
+ }
52
+
53
+ assert_equal expected, req.request_tags
54
+ ::Instana.agent.extra_headers = nil
55
+ end
56
+
57
+ def test_correlation_data_valid
58
+ req = Instana::InstrumentedRequest.new(
59
+ 'HTTP_X_INSTANA_L' => '1,correlationType=web ;correlationId=1234567890abcdef'
60
+ )
61
+ expected = {
62
+ type: 'web',
63
+ id: '1234567890abcdef'
64
+ }
65
+
66
+ assert_equal expected, req.correlation_data
67
+ end
68
+
69
+ def test_correlation_data_invalid
70
+ req = Instana::InstrumentedRequest.new(
71
+ 'HTTP_X_INSTANA_L' => '0;sample-data'
72
+ )
73
+
74
+ assert_equal({}, req.correlation_data)
75
+ end
76
+
77
+ def test_correlation_data_legacy
78
+ req = Instana::InstrumentedRequest.new(
79
+ 'HTTP_X_INSTANA_L' => '1'
80
+ )
81
+
82
+ assert_equal({}, req.correlation_data)
83
+ end
84
+ end
@@ -49,82 +49,20 @@ class TracerIDMgmtTest < Minitest::Test
49
49
  converted_id = Instana::Util.header_to_id(header_id)
50
50
 
51
51
  # Assert that it is an Integer
52
- assert converted_id.is_a?(Integer)
52
+ assert converted_id.is_a?(String)
53
53
  end
54
54
 
55
55
  def test_header_to_id_conversion_with_bogus_header
56
56
  # Bogus nil arg
57
57
  bogus_result = Instana::Util.header_to_id(nil)
58
- assert_equal 0, bogus_result
58
+ assert_equal '', bogus_result
59
59
 
60
60
  # Bogus Integer arg
61
61
  bogus_result = Instana::Util.header_to_id(1234)
62
- assert_equal 0, bogus_result
62
+ assert_equal '', bogus_result
63
63
 
64
64
  # Bogus Array arg
65
65
  bogus_result = Instana::Util.header_to_id([1234])
66
- assert_equal 0, bogus_result
67
- end
68
-
69
- def test_id_conversion_back_and_forth
70
- # id --> header --> id
71
- original_id = ::Instana::Util.generate_id
72
- header_id = Instana::Util.id_to_header(original_id)
73
- converted_back_id = Instana::Util.header_to_id(header_id)
74
- assert original_id == converted_back_id
75
-
76
- # header --> id --> header
77
- original_header_id = "c025ee93b1aeda7b"
78
- id = Instana::Util.header_to_id(original_header_id)
79
- converted_back_header_id = Instana::Util.id_to_header(id)
80
- assert_equal original_header_id, converted_back_header_id
81
-
82
- # Test a random value
83
- id = -7815363404733516491
84
- header = "938a406416457535"
85
-
86
- result = Instana::Util.header_to_id(header)
87
- assert_equal id, result
88
-
89
- result = Instana::Util.id_to_header(id)
90
- assert_equal header, result
91
-
92
- 10000.times do
93
- original_id = ::Instana::Util.generate_id
94
- header_id = Instana::Util.id_to_header(original_id)
95
- converted_back_id = Instana::Util.header_to_id(header_id)
96
- assert original_id == converted_back_id
97
- end
98
- end
99
-
100
- def test_id_max_value_and_conversion
101
- max_id = 9223372036854775807
102
- min_id = -9223372036854775808
103
- max_hex = "7fffffffffffffff"
104
- min_hex = "8000000000000000"
105
-
106
- assert_equal max_hex, Instana::Util.id_to_header(max_id)
107
- assert_equal min_hex, Instana::Util.id_to_header(min_id)
108
-
109
- assert_equal max_id, Instana::Util.header_to_id(max_hex)
110
- assert_equal min_id, Instana::Util.header_to_id(min_hex)
111
- end
112
-
113
- def test_that_leading_zeros_handled_correctly
114
-
115
- header = ::Instana::Util.id_to_header(16)
116
- assert_equal "10", header
117
-
118
- id = ::Instana::Util.header_to_id("10")
119
- assert_equal 16, id
120
-
121
- id = ::Instana::Util.header_to_id("0000000000000010")
122
- assert_equal 16, id
123
-
124
- id = ::Instana::Util.header_to_id("88b6c735206ca42")
125
- assert_equal 615705016619420226, id
126
-
127
- id = ::Instana::Util.header_to_id("088b6c735206ca42")
128
- assert_equal 615705016619420226, id
66
+ assert_equal '', bogus_result
129
67
  end
130
68
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.192.0
4
+ version: 1.192.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Giacomo Lombardo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-12 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -175,6 +175,7 @@ extra_rdoc_files: []
175
175
  files:
176
176
  - ".circleci/config.yml"
177
177
  - ".codeclimate.yml"
178
+ - ".editorconfig"
178
179
  - ".fasterer.yml"
179
180
  - ".gitignore"
180
181
  - ".rubocop.yml"
@@ -233,6 +234,7 @@ files:
233
234
  - lib/instana/instrumentation/excon.rb
234
235
  - lib/instana/instrumentation/graphql.rb
235
236
  - lib/instana/instrumentation/grpc.rb
237
+ - lib/instana/instrumentation/instrumented_request.rb
236
238
  - lib/instana/instrumentation/net-http.rb
237
239
  - lib/instana/instrumentation/rack.rb
238
240
  - lib/instana/instrumentation/redis.rb
@@ -278,6 +280,7 @@ files:
278
280
  - test/instrumentation/excon_test.rb
279
281
  - test/instrumentation/graphql_test.rb
280
282
  - test/instrumentation/grpc_test.rb
283
+ - test/instrumentation/instrumented_request_test.rb
281
284
  - test/instrumentation/net-http_test.rb
282
285
  - test/instrumentation/redis_test.rb
283
286
  - test/instrumentation/resque_test.rb
@@ -325,7 +328,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
325
328
  - !ruby/object:Gem::Version
326
329
  version: '0'
327
330
  requirements: []
328
- rubygems_version: 3.1.4
331
+ rubygems_version: 3.2.6
329
332
  signing_key:
330
333
  specification_version: 4
331
334
  summary: Ruby Distributed Tracing & Metrics Sensor for Instana
@@ -348,6 +351,7 @@ test_files:
348
351
  - test/instrumentation/rest-client_test.rb
349
352
  - test/instrumentation/dalli_test.rb
350
353
  - test/instrumentation/excon_test.rb
354
+ - test/instrumentation/instrumented_request_test.rb
351
355
  - test/instrumentation/grpc_test.rb
352
356
  - test/instrumentation/net-http_test.rb
353
357
  - test/benchmarks/bench_opentracing.rb