instana 1.195.3 → 1.198.0.pre1

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -2
  3. data/Rakefile +1 -1
  4. data/instana.gemspec +3 -7
  5. data/lib/instana.rb +3 -0
  6. data/lib/instana/activator.rb +2 -0
  7. data/lib/instana/backend/agent.rb +62 -0
  8. data/lib/instana/backend/gc_snapshot.rb +41 -0
  9. data/lib/instana/backend/host_agent.rb +74 -0
  10. data/lib/instana/backend/host_agent_activation_observer.rb +97 -0
  11. data/lib/instana/backend/host_agent_lookup.rb +57 -0
  12. data/lib/instana/backend/host_agent_reporting_observer.rb +106 -0
  13. data/lib/instana/backend/process_info.rb +64 -0
  14. data/lib/instana/backend/request_client.rb +74 -0
  15. data/lib/instana/backend/serverless_agent.rb +113 -0
  16. data/lib/instana/base.rb +10 -27
  17. data/lib/instana/config.rb +8 -22
  18. data/lib/instana/instrumentation/excon.rb +17 -8
  19. data/lib/instana/instrumentation/instrumented_request.rb +62 -7
  20. data/lib/instana/instrumentation/net-http.rb +7 -5
  21. data/lib/instana/instrumentation/rack.rb +12 -7
  22. data/lib/instana/logger_delegator.rb +31 -0
  23. data/lib/instana/{opentracing → open_tracing}/carrier.rb +0 -0
  24. data/lib/instana/open_tracing/instana_tracer.rb +99 -0
  25. data/lib/instana/secrets.rb +6 -2
  26. data/lib/instana/serverless.rb +133 -0
  27. data/lib/instana/setup.rb +23 -11
  28. data/lib/instana/snapshot/deltable.rb +25 -0
  29. data/lib/instana/snapshot/docker_container.rb +151 -0
  30. data/lib/instana/snapshot/fargate_container.rb +88 -0
  31. data/lib/instana/snapshot/fargate_process.rb +67 -0
  32. data/lib/instana/snapshot/fargate_task.rb +72 -0
  33. data/lib/instana/snapshot/lambda_function.rb +39 -0
  34. data/lib/instana/snapshot/ruby_process.rb +48 -0
  35. data/lib/instana/tracer.rb +25 -143
  36. data/lib/instana/tracing/processor.rb +14 -22
  37. data/lib/instana/tracing/span.rb +33 -36
  38. data/lib/instana/tracing/span_context.rb +15 -10
  39. data/lib/instana/util.rb +8 -69
  40. data/lib/instana/version.rb +1 -1
  41. data/lib/opentracing.rb +26 -3
  42. data/test/backend/agent_test.rb +67 -0
  43. data/test/backend/gc_snapshot_test.rb +11 -0
  44. data/test/backend/host_agent_activation_observer_test.rb +72 -0
  45. data/test/backend/host_agent_lookup_test.rb +78 -0
  46. data/test/backend/host_agent_reporting_observer_test.rb +192 -0
  47. data/test/backend/host_agent_test.rb +47 -0
  48. data/test/backend/process_info_test.rb +63 -0
  49. data/test/backend/request_client_test.rb +39 -0
  50. data/test/backend/serverless_agent_test.rb +73 -0
  51. data/test/config_test.rb +10 -0
  52. data/test/instana_test.rb +11 -4
  53. data/test/instrumentation/excon_test.rb +15 -1
  54. data/test/instrumentation/rack_instrumented_request_test.rb +5 -2
  55. data/test/instrumentation/rack_test.rb +2 -14
  56. data/test/secrets_test.rb +41 -22
  57. data/test/serverless_test.rb +323 -0
  58. data/test/snapshot/deltable_test.rb +17 -0
  59. data/test/snapshot/docker_container_test.rb +82 -0
  60. data/test/snapshot/fargate_container_test.rb +82 -0
  61. data/test/snapshot/fargate_process_test.rb +35 -0
  62. data/test/snapshot/fargate_task_test.rb +49 -0
  63. data/test/snapshot/lambda_function_test.rb +37 -0
  64. data/test/snapshot/ruby_process_test.rb +14 -0
  65. data/test/support/mock_timer.rb +20 -0
  66. data/test/test_helper.rb +16 -4
  67. data/test/tracing/custom_test.rb +1 -3
  68. data/test/tracing/id_management_test.rb +8 -0
  69. data/test/tracing/opentracing_test.rb +15 -2
  70. data/test/tracing/processor_test.rb +58 -0
  71. data/test/tracing/span_context_test.rb +22 -0
  72. data/test/tracing/span_test.rb +136 -0
  73. data/test/tracing/tracer_async_test.rb +29 -0
  74. data/test/tracing/tracer_test.rb +82 -16
  75. data/test/util_test.rb +10 -0
  76. metadata +78 -45
  77. data/lib/instana/agent.rb +0 -508
  78. data/lib/instana/agent/helpers.rb +0 -87
  79. data/lib/instana/agent/hooks.rb +0 -44
  80. data/lib/instana/agent/tasks.rb +0 -51
  81. data/lib/instana/collector.rb +0 -119
  82. data/lib/instana/collectors/gc.rb +0 -60
  83. data/lib/instana/collectors/memory.rb +0 -37
  84. data/lib/instana/collectors/thread.rb +0 -33
  85. data/lib/instana/eum/eum-test.js.erb +0 -17
  86. data/lib/instana/eum/eum.js.erb +0 -17
  87. data/lib/instana/helpers.rb +0 -47
  88. data/lib/instana/opentracing/tracer.rb +0 -21
  89. data/lib/instana/thread_local.rb +0 -18
  90. data/lib/oj_check.rb +0 -19
  91. data/test/agent/agent_test.rb +0 -151
@@ -0,0 +1,64 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # Wrapper around {Sys::ProcTable} that adds support for reading the /proc
7
+ # file system for extra information around containers
8
+ # @since 1.197.0
9
+ class ProcessInfo < SimpleDelegator
10
+ def name
11
+ cmdline
12
+ .split(' ').first
13
+ end
14
+
15
+ def arguments
16
+ _, *arguments = cmdline.split(' ')
17
+ clean_arguments(arguments)
18
+ end
19
+
20
+ def parent_pid
21
+ if in_container? && sched_pid != pid
22
+ sched_pid
23
+ else
24
+ pid
25
+ end
26
+ end
27
+
28
+ def from_parent_namespace
29
+ !in_container? || in_container? && sched_pid != pid
30
+ end
31
+
32
+ def cpuset
33
+ path = "/proc/#{pid}/cpuset"
34
+ return unless File.exist?(path)
35
+
36
+ File.read(path).strip
37
+ end
38
+
39
+ def in_container?
40
+ !cpuset.nil? && cpuset != '/'
41
+ end
42
+
43
+ def sched_pid
44
+ path = '/proc/self/sched'
45
+ return unless File.exist?(path)
46
+
47
+ File.read(path).match(/\d+/).to_s.to_i
48
+ end
49
+
50
+ private
51
+
52
+ def clean_arguments(arguments)
53
+ return arguments unless RbConfig::CONFIG['host_os'].include?('darwin')
54
+
55
+ arguments.reject do |a|
56
+ if a.include?('=')
57
+ k, = a.split('=', 2)
58
+ ENV[k]
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,74 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'net/http'
5
+ require 'delegate'
6
+ require 'json'
7
+
8
+ # :nocov:
9
+ begin
10
+ require 'oj'
11
+ rescue LoadError => _e
12
+ Instana.logger.warn("Unable to load Oj.")
13
+ end
14
+ # :nocov:
15
+
16
+ module Instana
17
+ module Backend
18
+ # Convince wrapper around {Net::HTTP}.
19
+ # @since 1.197.0
20
+ class RequestClient
21
+ attr_reader :host, :port
22
+
23
+ class Response < SimpleDelegator
24
+ # @return [Hash] the decoded json response
25
+ def json
26
+ JSON.parse(body)
27
+ end
28
+
29
+ # @return [Boolean] true if the request was successful
30
+ def ok?
31
+ __getobj__.is_a?(Net::HTTPSuccess)
32
+ end
33
+ end
34
+
35
+ def initialize(host, port, use_ssl: false)
36
+ timeout = Integer(ENV.fetch('INSTANA_TIMEOUT', 500))
37
+ @host = host
38
+ @port = port
39
+ @client = Net::HTTP.start(host, port, use_ssl: use_ssl, read_timeout: timeout)
40
+ end
41
+
42
+ # Send a request to the backend. If data is a {Hash},
43
+ # encode the object as JSON and set the proper headers.
44
+ #
45
+ # @param [String] method request method
46
+ # @param [String] path request path
47
+ # @param [Hash, String] data request body
48
+ # @param [Hash] headers extra request headers to send
49
+ def send_request(method, path, data = nil, headers = {})
50
+ body = if data.is_a?(Hash) || data.is_a?(Array)
51
+ headers['Content-Type'] = 'application/json'
52
+ headers['Accept'] = 'application/json'
53
+
54
+ encode_body(data)
55
+ else
56
+ headers['Content-Type'] = 'application/octet-stream'
57
+
58
+ data
59
+ end
60
+
61
+ response = @client.send_request(method, path, body, headers)
62
+ Response.new(response)
63
+ end
64
+
65
+ private
66
+
67
+ def encode_body(data)
68
+ # :nocov:
69
+ defined?(Oj) ? Oj.dump(data, mode: :strict) : JSON.dump(data)
70
+ # :nocov:
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,113 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # @since 1.197.0
7
+ class ServerlessAgent
8
+ DEFAULT_SECRETS = 'contains-ignore-case:key,password,secret'.freeze
9
+ attr_reader :timer
10
+
11
+ # rubocop:disable Metrics/ParameterLists
12
+ def initialize(snapshots,
13
+ timer_class: Concurrent::TimerTask,
14
+ processor: ::Instana.processor,
15
+ logger: ::Instana.logger,
16
+ backend_uri: ENV['INSTANA_ENDPOINT_URL'],
17
+ secrets: ENV.fetch('INSTANA_SECRETS', DEFAULT_SECRETS), headers: ENV.fetch('INSTANA_EXTRA_HTTP_HEADERS', ''))
18
+ @snapshots = snapshots
19
+ @processor = processor
20
+ @logger = logger
21
+ @timer = timer_class.new(execution_interval: 1, run_now: true) { send_bundle }
22
+ @backend_uri = URI(backend_uri)
23
+ @client = Backend::RequestClient.new(@backend_uri.host, @backend_uri.port, use_ssl: @backend_uri.scheme == "https")
24
+ @secrets = secrets
25
+ @headers = headers
26
+ end
27
+ # rubocop:enable Metrics/ParameterLists
28
+
29
+ def setup; end
30
+
31
+ def spawn_background_thread
32
+ @timer.execute
33
+ end
34
+
35
+ # @return [Boolean] true if the agent able to send spans to the backend
36
+ def ready?
37
+ true
38
+ end
39
+
40
+ # @return [Hash, NilClass] the backend friendly description of the current in process collector
41
+ def source
42
+ snapshot = @snapshots.detect { |s| s.respond_to?(:source) }
43
+
44
+ if snapshot
45
+ snapshot.source
46
+ else
47
+ @logger.warn('Unable to find a snapshot which provides a source.')
48
+ {}
49
+ end
50
+ end
51
+
52
+ # @return [Array] extra headers to include in the trace
53
+ def extra_headers
54
+ @headers.split(';')
55
+ end
56
+
57
+ # @return [Hash] values which are removed from urls sent to the backend
58
+ def secret_values
59
+ matcher, *keys = @secrets.split(/[:,]/)
60
+ {'matcher' => matcher, 'list' => keys}
61
+ end
62
+
63
+ def send_bundle
64
+ spans = @processor.queued_spans
65
+ bundle = {
66
+ spans: spans,
67
+ metrics: {
68
+ plugins: agent_snapshots
69
+ }
70
+ }
71
+
72
+ path = "#{@backend_uri.path}/bundle"
73
+ response = @client.send_request('POST', path, bundle, request_headers)
74
+
75
+ return if response.ok?
76
+
77
+ @logger.warn("Recived a `#{response.code}` when sending data.")
78
+ end
79
+
80
+ private
81
+
82
+ def request_headers
83
+ {
84
+ 'X-Instana-Host' => host_name,
85
+ 'X-Instana-Key' => ENV['INSTANA_AGENT_KEY'],
86
+ 'X-Instana-Time' => (Time.now.to_i * 1000).to_s
87
+ }
88
+ end
89
+
90
+ def agent_snapshots
91
+ @snapshots.map do |snapshot|
92
+ begin # rubocop:disable Style/RedundantBegin, Lint/RedundantCopDisableDirective
93
+ snapshot.snapshot
94
+ rescue StandardError => e
95
+ @logger.error(e.message)
96
+ nil
97
+ end
98
+ end.compact
99
+ end
100
+
101
+ def host_name
102
+ snapshot = @snapshots.detect { |s| s.respond_to?(:host_name) }
103
+
104
+ if snapshot
105
+ snapshot.host_name
106
+ else
107
+ @logger.warn('Unable to find a snapshot which provides a host_name.')
108
+ ''
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
data/lib/instana/base.rb CHANGED
@@ -4,18 +4,16 @@
4
4
  require "logger"
5
5
  require "instana/version"
6
6
  require "instana/util"
7
- require "instana/helpers"
8
7
 
9
8
  module Instana
10
9
  class << self
11
10
  attr_accessor :agent
12
- attr_accessor :collector
13
11
  attr_accessor :tracer
14
12
  attr_accessor :processor
15
13
  attr_accessor :config
16
- attr_accessor :logger
17
14
  attr_accessor :pid
18
15
  attr_reader :secrets
16
+ attr_reader :serverless
19
17
 
20
18
  ##
21
19
  # setup
@@ -24,36 +22,21 @@ module Instana
24
22
  # to run" state.
25
23
  #
26
24
  def setup
27
- @agent = ::Instana::Agent.new
25
+ @agent = ::Instana::Backend::Agent.new
28
26
  @tracer = ::Instana::Tracer.new
29
27
  @processor = ::Instana::Processor.new
30
- @collector = ::Instana::Collector.new
31
28
  @secrets = ::Instana::Secrets.new
29
+ @serverless = ::Instana::Serverless.new
32
30
  end
33
- end
34
- end
35
-
36
- # Setup the logger as early as possible
37
-
38
- # Default Logger outputs to STDOUT
39
- ::Instana.logger = Logger.new(STDOUT)
40
-
41
- # Can instead log to a file that is rotated every 10M
42
- # ::Instana.logger = Logger.new("instana.log", 10, 1073741824)
43
31
 
44
- if ENV.key?('INSTANA_GEM_TEST')
45
- ::Instana.logger.level = Logger::DEBUG
46
- elsif ENV.key?('INSTANA_GEM_DEV') || ENV.key?('INSTANA_DEBUG')
47
- ::Instana.logger.level = Logger::DEBUG
48
- elsif ENV.key?('INSTANA_QUIET')
49
- ::Instana.logger.level = Logger::FATAL
50
- else
51
- ::Instana.logger.level = Logger::WARN
52
- end
32
+ def logger
33
+ @logger ||= ::Instana::LoggerDelegator.new(Logger.new(STDOUT))
34
+ end
53
35
 
54
- ::Instana.logger.formatter = proc do |severity, datetime, progname, msg|
55
- "#{datetime}: #{severity.rjust(5)} Instana: #{progname} #{msg}\n"
36
+ def logger=(val)
37
+ @logger.__setobj__(val)
38
+ end
39
+ end
56
40
  end
57
41
 
58
-
59
42
  ::Instana.logger.info "Stan is on the scene. Starting Instana instrumentation version #{::Instana::VERSION}"
@@ -3,26 +3,21 @@
3
3
 
4
4
  module Instana
5
5
  class Config
6
-
7
- def initialize
6
+ def initialize(logger: ::Instana.logger, agent_host: ENV['INSTANA_AGENT_HOST'], agent_port: ENV['INSTANA_AGENT_PORT'])
8
7
  @config = {}
9
- if ENV.key?('INSTANA_AGENT_HOST')
10
- ::Instana.logger.debug "Using custom agent host location specified in INSTANA_AGENT_HOST (#{ENV['INSTANA_AGENT_HOST']})"
11
- @config[:agent_host] = ENV['INSTANA_AGENT_HOST']
8
+ if agent_host
9
+ logger.debug "Using custom agent host location specified in INSTANA_AGENT_HOST (#{ENV['INSTANA_AGENT_HOST']})"
10
+ @config[:agent_host] = agent_host
12
11
  else
13
12
  @config[:agent_host] = '127.0.0.1'
14
13
  end
15
- if ENV.key?('INSTANA_AGENT_PORT')
16
- ::Instana.logger.debug "Using custom agent port specified in INSTANA_AGENT_PORT (#{ENV['INSTANA_AGENT_PORT']})"
17
- @config[:agent_port] = ENV['INSTANA_AGENT_PORT']
14
+ if agent_port
15
+ logger.debug "Using custom agent port specified in INSTANA_AGENT_PORT (#{ENV['INSTANA_AGENT_PORT']})"
16
+ @config[:agent_port] = agent_port
18
17
  else
19
18
  @config[:agent_port] = 42699
20
19
  end
21
20
 
22
- # This option has been DEPRECATED. Use the INSTANA_DISABLE environment variable instead.
23
- # https://docs.instana.io/ecosystem/ruby/configuration/
24
- @config[:enabled] = true
25
-
26
21
  # Enable/disable metrics globally or individually (default: all enabled)
27
22
  @config[:metrics] = { :enabled => true }
28
23
  @config[:metrics][:gc] = { :enabled => true }
@@ -56,7 +51,7 @@ module Instana
56
51
  @config[:sanitize_sql] = true
57
52
 
58
53
  # W3 Trace Context Support
59
- @config[:w3_trace_correlation] = ENV.fetch('INSTANA_W3C_TRACE_CORRELATION', 'true').eql?('true')
54
+ @config[:w3_trace_correlation] = ENV['INSTANA_DISABLE_W3C_TRACE_CORRELATION'].nil?
60
55
 
61
56
  @config[:action_controller] = { :enabled => true }
62
57
  @config[:action_view] = { :enabled => true }
@@ -80,15 +75,6 @@ module Instana
80
75
 
81
76
  def []=(key, value)
82
77
  @config[key.to_sym] = value
83
-
84
- if key == :enabled
85
- # Configuring global enable/disable flag, then set the
86
- # appropriate children flags.
87
- @config[:metrics][:enabled] = value
88
- @config[:tracing][:enabled] = value
89
-
90
- ::Instana.logger.warn "::Instana.config[:enabled] has been deprecated. Set INSTANA_DISABLE environment variable to any value instead."
91
- end
92
78
  end
93
79
  end
94
80
  end
@@ -5,7 +5,7 @@ module Instana
5
5
  module Instrumentation
6
6
  class Excon < ::Excon::Middleware::Base
7
7
  def request_call(datum)
8
- return @stack.request_call(datum) unless ::Instana.tracer.tracing? && !Instana.tracer.current_span.exit_span?
8
+ return @stack.request_call(datum) unless traceable?
9
9
 
10
10
  payload = { :http => {} }
11
11
  path, query = datum[:path].split('?', 2)
@@ -24,19 +24,21 @@ module Instana
24
24
  end
25
25
 
26
26
  # Set request headers; encode IDs as hexadecimal strings
27
- datum[:headers]['X-Instana-T'] = t_context.trace_id_header
28
- datum[:headers]['X-Instana-S'] = t_context.span_id_header
27
+ datum[:headers]['X-Instana-L'] = t_context.level.to_s
29
28
 
30
- if ::Instana.config[:w3_trace_correlation]
31
- datum[:headers]['Traceparent'] = t_context.trace_parent_header
32
- datum[:headers]['Tracestate'] = t_context.trace_state_header
29
+ if t_context.active?
30
+ datum[:headers]['X-Instana-T'] = t_context.trace_id_header
31
+ datum[:headers]['X-Instana-S'] = t_context.span_id_header
33
32
  end
34
33
 
34
+ datum[:headers]['Traceparent'] = t_context.trace_parent_header
35
+ datum[:headers]['Tracestate'] = t_context.trace_state_header unless t_context.trace_state_header.empty?
36
+
35
37
  @stack.request_call(datum)
36
38
  end
37
39
 
38
40
  def error_call(datum)
39
- return @stack.error_call(datum) unless ::Instana.tracer.tracing? || !Instana.tracer.current_span.exit_span?
41
+ return @stack.error_call(datum) unless traceable?
40
42
 
41
43
  if datum[:pipeline] == true
42
44
  ::Instana.tracer.log_async_error(datum[:error], datum[:instana_span])
@@ -49,7 +51,7 @@ module Instana
49
51
  def response_call(datum)
50
52
  # FIXME: Will connect exceptions call a response?
51
53
  #
52
- return @stack.response_call(datum) unless ::Instana.tracer.tracing? || !Instana.tracer.current_span.exit_span?
54
+ return @stack.response_call(datum) unless traceable?
53
55
 
54
56
  result = @stack.response_call(datum)
55
57
 
@@ -72,6 +74,13 @@ module Instana
72
74
  end
73
75
  result
74
76
  end
77
+
78
+ private
79
+
80
+ def traceable?
81
+ ::Instana.tracer.tracing? &&
82
+ (!Instana.tracer.current_span.exit_span? || Instana.tracer.current_span.name == :excon)
83
+ end
75
84
  end
76
85
  end
77
86
  end
@@ -18,16 +18,33 @@ module Instana
18
18
  end
19
19
 
20
20
  def incoming_context
21
- context = if @env['HTTP_X_INSTANA_T']
21
+ context = if !correlation_data.empty?
22
+ {}
23
+ elsif @env['HTTP_X_INSTANA_T']
22
24
  context_from_instana_headers
23
- elsif @env['HTTP_TRACEPARENT'] && ::Instana.config[:w3_trace_correlation]
25
+ elsif @env['HTTP_TRACEPARENT']
24
26
  context_from_trace_parent
27
+ elsif @env['HTTP_TRACESTATE']
28
+ context_from_trace_state
25
29
  else
26
30
  {}
27
31
  end
28
32
 
29
33
  context[:level] = @env['HTTP_X_INSTANA_L'][0] if @env['HTTP_X_INSTANA_L']
30
34
 
35
+ unless ::Instana.config[:w3_trace_correlation]
36
+ trace_state = parse_trace_state
37
+
38
+ if context[:from_w3] && trace_state.empty?
39
+ context.delete(:span_id)
40
+ context[:from_w3] = false
41
+ elsif context[:from_w3] && !trace_state.empty?
42
+ context[:trace_id] = trace_state[:t]
43
+ context[:span_id] = trace_state[:p]
44
+ context[:from_w3] = false
45
+ end
46
+ end
47
+
31
48
  context
32
49
  end
33
50
 
@@ -69,19 +86,43 @@ module Instana
69
86
  end
70
87
 
71
88
  def continuing_from_trace_parent?
72
- incoming_context.include?(:external_trace_id)
89
+ incoming_context[:from_w3]
73
90
  end
74
91
 
75
92
  def synthetic?
76
93
  @env.has_key?('HTTP_X_INSTANA_SYNTHETIC') && @env['HTTP_X_INSTANA_SYNTHETIC'].eql?('1')
77
94
  end
78
95
 
96
+ def long_instana_id?
97
+ ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T']).length == 32
98
+ end
99
+
100
+ def external_trace_id?
101
+ continuing_from_trace_parent? || long_instana_id?
102
+ end
103
+
104
+ def external_trace_id
105
+ incoming_context[:long_instana_id] || incoming_context[:external_trace_id]
106
+ end
107
+
79
108
  private
80
109
 
81
110
  def context_from_instana_headers
111
+ sanitized_t = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T'])
112
+ sanitized_s = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_S'])
113
+ external_trace_id = if @env['HTTP_TRACEPARENT']
114
+ context_from_trace_parent[:external_trace_id]
115
+ elsif long_instana_id?
116
+ sanitized_t
117
+ end
118
+
82
119
  {
83
- trace_id: ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T']),
84
- span_id: ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_S'])
120
+ span_id: sanitized_s,
121
+ trace_id: long_instana_id? ? sanitized_t[16..-1] : sanitized_t, # rubocop:disable Style/SlicingWithRange, Lint/RedundantCopDisableDirective
122
+ long_instana_id: long_instana_id? ? sanitized_t : nil,
123
+ external_trace_id: external_trace_id,
124
+ external_state: @env['HTTP_TRACESTATE'],
125
+ from_w3: false
85
126
  }.compact
86
127
  end
87
128
 
@@ -90,14 +131,28 @@ module Instana
90
131
  matches = @env['HTTP_TRACEPARENT'].match(W3_TRACE_PARENT_FORMAT)
91
132
  return {} unless matches
92
133
 
134
+ trace_id = ::Instana::Util.header_to_id(matches['trace'][16..-1]) # rubocop:disable Style/SlicingWithRange, Lint/RedundantCopDisableDirective
135
+ span_id = ::Instana::Util.header_to_id(matches['parent'])
136
+
93
137
  {
94
138
  external_trace_id: matches['trace'],
95
139
  external_state: @env['HTTP_TRACESTATE'],
96
- trace_id: ::Instana::Util.header_to_id(matches['trace'][16..-1]), # rubocop:disable Style/SlicingWithRange, Lint/RedundantCopDisableDirective
97
- span_id: ::Instana::Util.header_to_id(matches['parent'])
140
+ trace_id: trace_id,
141
+ span_id: span_id,
142
+ from_w3: true
98
143
  }
99
144
  end
100
145
 
146
+ def context_from_trace_state
147
+ state = parse_trace_state
148
+
149
+ {
150
+ trace_id: state[:t],
151
+ span_id: state[:p],
152
+ from_w3: false
153
+ }.compact
154
+ end
155
+
101
156
  def parse_trace_state
102
157
  return {} unless @env.has_key?('HTTP_TRACESTATE')
103
158
  token = @env['HTTP_TRACESTATE']