instana 1.192.0 → 1.192.1

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 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