instana 2.10.0 → 2.11.0
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 +4 -4
- data/lib/instana/base.rb +5 -0
- data/lib/instana/config.rb +49 -0
- data/lib/instana/instrumentation/active_job.rb +34 -19
- data/lib/instana/instrumentation/aws_sdk_lambda.rb +16 -7
- data/lib/instana/instrumentation/aws_sdk_sns.rb +31 -1
- data/lib/instana/instrumentation/aws_sdk_sqs.rb +10 -5
- data/lib/instana/instrumentation/bunny.rb +23 -6
- data/lib/instana/instrumentation/grpc.rb +39 -11
- data/lib/instana/instrumentation/instrumented_request.rb +21 -11
- data/lib/instana/instrumentation/rack.rb +2 -0
- data/lib/instana/instrumentation/resque.rb +2 -1
- data/lib/instana/instrumentation/shoryuken.rb +33 -12
- data/lib/instana/instrumentation/sidekiq-client.rb +1 -0
- data/lib/instana/instrumentation/sidekiq-worker.rb +4 -2
- data/lib/instana/trace/span_context.rb +1 -1
- data/lib/instana/util.rb +68 -1
- data/lib/instana/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 651f82ecb4bf26f63225bb880fff4028fca72f641eeac492b3bbb85d4c0be0d2
|
|
4
|
+
data.tar.gz: b311f0c13d53cf688247b580f018a57a62569eb0a1fa5c25d8fac1a8939ffdf0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29c82de02af9e09ebaa84da9429d70867f1f8eb3c397836d50a78eaddecf8339a6b20e809bbdadc22dbd0f5f8672e766d96aff1c0802f9a08edefd7bccb0a1ae
|
|
7
|
+
data.tar.gz: e099c624a54ce5871010efad8ad469d8aebf0672cc7011a49bd26c9b448fcc6883eb58122cc9424f69757432b418b1a38fe332d78b1718c65ba60cae8958754e
|
data/lib/instana/base.rb
CHANGED
|
@@ -6,6 +6,11 @@ require "instana/version"
|
|
|
6
6
|
require "instana/util"
|
|
7
7
|
|
|
8
8
|
module Instana
|
|
9
|
+
# Instana trace context header names
|
|
10
|
+
INSTANA_TRACE_ID_HEADER = 'X-Instana-T'.freeze
|
|
11
|
+
INSTANA_SPAN_ID_HEADER = 'X-Instana-S'.freeze
|
|
12
|
+
INSTANA_LEVEL_HEADER = 'X-Instana-L'.freeze
|
|
13
|
+
|
|
9
14
|
class << self
|
|
10
15
|
attr_accessor :agent
|
|
11
16
|
attr_accessor :tracer
|
data/lib/instana/config.rb
CHANGED
|
@@ -83,6 +83,10 @@ module Instana
|
|
|
83
83
|
# W3C Trace Context Support
|
|
84
84
|
@config[:w3c_trace_correlation] = ENV.fetch('INSTANA_DISABLE_W3C_TRACE_CORRELATION', nil).nil?
|
|
85
85
|
|
|
86
|
+
# Server-Timing response header injection (default: injected)
|
|
87
|
+
# Priority: YAML > env var > agent config > default (false)
|
|
88
|
+
read_disable_server_timing_config
|
|
89
|
+
|
|
86
90
|
# HTTP exit span 4xx error classification (opt-in, default: off)
|
|
87
91
|
# Priority: env vars > agent config > default (false / [])
|
|
88
92
|
read_http_exit_config
|
|
@@ -151,6 +155,8 @@ module Instana
|
|
|
151
155
|
read_otlp_config_from_agent(tracing_config) if should_read_from_agent?(:otlp)
|
|
152
156
|
# Read HTTP exit 4xx classification from agent if env vars did not already set it
|
|
153
157
|
read_http_exit_classification_from_agent(tracing_config) unless env_http_exit_classification_set?
|
|
158
|
+
# Read Server-Timing disable flag from agent if not already set from YAML or env
|
|
159
|
+
read_disable_server_timing_from_agent(tracing_config) if @config[:disable_server_timing_source] == 'default'
|
|
154
160
|
# Read span filtering configuration from agent
|
|
155
161
|
::Instana.span_filtering_config&.read_config_from_agent(discovery)
|
|
156
162
|
rescue => e
|
|
@@ -268,6 +274,49 @@ module Instana
|
|
|
268
274
|
|
|
269
275
|
private
|
|
270
276
|
|
|
277
|
+
# Read disable-server-timing from YAML (tracing.global) or INSTANA_TRACING_DISABLE_SERVER_TIMING.
|
|
278
|
+
# Agent value is applied later via read_config_from_agent if neither is set.
|
|
279
|
+
def read_disable_server_timing_config
|
|
280
|
+
@config[:disable_server_timing] = false
|
|
281
|
+
@config[:disable_server_timing_source] = 'default'
|
|
282
|
+
|
|
283
|
+
yaml_value = parse_disable_server_timing_from_yaml
|
|
284
|
+
unless yaml_value.nil?
|
|
285
|
+
@config[:disable_server_timing] = truthy?(yaml_value)
|
|
286
|
+
@config[:disable_server_timing_source] = 'yaml'
|
|
287
|
+
return
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
env_value = ENV.fetch('INSTANA_TRACING_DISABLE_SERVER_TIMING', nil)
|
|
291
|
+
return if env_value.nil? || env_value.strip.empty?
|
|
292
|
+
|
|
293
|
+
@config[:disable_server_timing] = truthy?(env_value.strip)
|
|
294
|
+
@config[:disable_server_timing_source] = 'env'
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# @return [Object, nil] raw YAML value of tracing.global.disable-server-timing, or nil if not set
|
|
298
|
+
def parse_disable_server_timing_from_yaml
|
|
299
|
+
config_path = ENV.fetch('INSTANA_CONFIG_PATH', nil)
|
|
300
|
+
return nil unless config_path && File.exist?(config_path)
|
|
301
|
+
|
|
302
|
+
yaml_content = YAML.safe_load(File.read(config_path))
|
|
303
|
+
tracing_config = yaml_content[TRACING_KEY] || yaml_content[LEGACY_TRACING_KEY]
|
|
304
|
+
global_config = tracing_config && tracing_config['global']
|
|
305
|
+
global_config.is_a?(Hash) ? global_config['disable-server-timing'] : nil
|
|
306
|
+
rescue => e
|
|
307
|
+
::Instana.logger.warn("Failed to load disable-server-timing configuration from YAML: #{e.message}")
|
|
308
|
+
nil
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# @param tracing_config [Hash] the tracing sub-hash from the discovery payload
|
|
312
|
+
def read_disable_server_timing_from_agent(tracing_config)
|
|
313
|
+
global_config = tracing_config['global']
|
|
314
|
+
return unless global_config.is_a?(Hash) && !global_config['disable-server-timing'].nil?
|
|
315
|
+
|
|
316
|
+
@config[:disable_server_timing] = truthy?(global_config['disable-server-timing'])
|
|
317
|
+
@config[:disable_server_timing_source] = 'agent'
|
|
318
|
+
end
|
|
319
|
+
|
|
271
320
|
# Read HTTP exit 4xx error classification config (wrapper — same pattern as read_span_stack_config / read_otlp_config)
|
|
272
321
|
def read_http_exit_config
|
|
273
322
|
@config[:http_exit_classify_all_4xx_as_errors] = false
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
# (c) Copyright IBM Corp. 2021
|
|
2
2
|
# (c) Copyright Instana Inc. 2021
|
|
3
|
-
module OpenTelemetry
|
|
4
|
-
module Trace
|
|
5
|
-
module Propagation
|
|
6
|
-
module TraceContext
|
|
7
|
-
# A TraceParent is an implementation of the W3C trace context specification
|
|
8
|
-
# https://www.w3.org/TR/trace-context/
|
|
9
|
-
# {Trace::SpanContext}
|
|
10
|
-
class TraceParent
|
|
11
|
-
REGEXP = /^(?<version>[A-Fa-f0-9]{2})-(?<trace_id>[A-Fa-f0-9]{32})-(?<span_id>[A-Fa-f0-9]{32})-(?<flags>[A-Fa-f0-9]{2})(?<ignored>-.*)?$/
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
3
|
|
|
18
4
|
module Instana
|
|
19
5
|
module Instrumentation
|
|
@@ -48,11 +34,8 @@ module Instana
|
|
|
48
34
|
job_id: job.job_id
|
|
49
35
|
}
|
|
50
36
|
}
|
|
51
|
-
incoming_context =
|
|
52
|
-
|
|
53
|
-
job.arguments.pop
|
|
54
|
-
instana_context ? ::Instana::SpanContext.new(trace_id: instana_context[:trace_id], span_id: instana_context[:span_id]) : nil
|
|
55
|
-
end
|
|
37
|
+
incoming_context = ::Instana::Instrumentation::ActiveJob.extract_context(job)
|
|
38
|
+
|
|
56
39
|
Trace.with_span(OpenTelemetry::Trace.non_recording_span(incoming_context)) do
|
|
57
40
|
::Instana.tracer.in_span(:activejob, attributes: tags) do
|
|
58
41
|
block.call
|
|
@@ -60,6 +43,38 @@ module Instana
|
|
|
60
43
|
end
|
|
61
44
|
end
|
|
62
45
|
end
|
|
46
|
+
|
|
47
|
+
def self.extract_context(job)
|
|
48
|
+
# 1. From job arguments (Instana payload)
|
|
49
|
+
if job.arguments.is_a?(Array) && job.arguments.last.is_a?(Hash) && job.arguments.last.key?(:instana_context)
|
|
50
|
+
instana_context = job.arguments.last[:instana_context]
|
|
51
|
+
job.arguments.pop
|
|
52
|
+
return instana_context ? ::Instana::SpanContext.new(
|
|
53
|
+
trace_id: instana_context[:trace_id],
|
|
54
|
+
span_id: instana_context[:span_id],
|
|
55
|
+
level: instana_context[:level] || 1
|
|
56
|
+
) : nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# 2. From job.__otel_headers (if opentelemetry-instrumentation-active_job is active)
|
|
60
|
+
if job.respond_to?(:__otel_headers) && job.__otel_headers.is_a?(Hash)
|
|
61
|
+
headers = job.__otel_headers
|
|
62
|
+
tp = headers['traceparent'] || headers[:traceparent]
|
|
63
|
+
if tp
|
|
64
|
+
ctx = parse_w3c_traceparent(tp, headers['tracestate'] || headers[:tracestate])
|
|
65
|
+
return ctx if ctx
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.parse_w3c_traceparent(traceparent, tracestate)
|
|
73
|
+
ctx = ::Instana::Util.parse_w3c_trace_context(traceparent, tracestate)
|
|
74
|
+
return nil unless ctx
|
|
75
|
+
|
|
76
|
+
::Instana::SpanContext.new(trace_id: ctx[:trace_id], span_id: ctx[:span_id], level: ctx[:level])
|
|
77
|
+
end
|
|
63
78
|
end
|
|
64
79
|
end
|
|
65
80
|
end
|
|
@@ -9,15 +9,24 @@ module Instana
|
|
|
9
9
|
def call(context)
|
|
10
10
|
return @handler.call(context) unless [:invoke_async, :invoke].include?(context.operation_name)
|
|
11
11
|
|
|
12
|
-
if
|
|
12
|
+
if ::Instana.tracer.tracing? && context.operation_name == :invoke
|
|
13
13
|
span_context = ::Instana.tracer.context
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
if span_context
|
|
15
|
+
trace_payload = {
|
|
16
|
+
'X-INSTANA-T' => span_context.trace_id,
|
|
17
|
+
'X-INSTANA-S' => span_context.span_id,
|
|
18
|
+
'X-INSTANA-L' => span_context.level.to_s,
|
|
19
|
+
'traceparent' => span_context.trace_parent_header,
|
|
20
|
+
'tracestate' => span_context.trace_state_header
|
|
21
|
+
}.reject { |_, v| v.nil? || v.empty? }
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
merged = if context.params[:client_context]
|
|
24
|
+
JSON.parse(Base64.strict_decode64(context.params[:client_context])).merge(trace_payload)
|
|
25
|
+
else
|
|
26
|
+
trace_payload
|
|
27
|
+
end
|
|
28
|
+
context.params[:client_context] = Base64.strict_encode64(JSON.dump(merged))
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
|
|
23
32
|
tags = {
|
|
@@ -14,11 +14,41 @@ module Instana
|
|
|
14
14
|
}.reject { |_, v| v.nil? }
|
|
15
15
|
|
|
16
16
|
if context.operation_name == :publish
|
|
17
|
-
::Instana.tracer.in_span(:sns, attributes: {sns: sns_tags})
|
|
17
|
+
::Instana.tracer.in_span(:sns, attributes: { sns: sns_tags }) do |_span|
|
|
18
|
+
if ::Instana.tracer.tracing?
|
|
19
|
+
inject_trace_attributes(context.params)
|
|
20
|
+
end
|
|
21
|
+
@handler.call(context)
|
|
22
|
+
end
|
|
23
|
+
elsif context.operation_name == :publish_batch
|
|
24
|
+
::Instana.tracer.in_span(:sns, attributes: { sns: sns_tags }) do |_span|
|
|
25
|
+
if ::Instana.tracer.tracing?
|
|
26
|
+
context.params[:publish_batch_request_entries]&.each do |entry|
|
|
27
|
+
inject_trace_attributes(entry)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
@handler.call(context)
|
|
31
|
+
end
|
|
18
32
|
else
|
|
19
33
|
@handler.call(context)
|
|
20
34
|
end
|
|
21
35
|
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def inject_trace_attributes(params)
|
|
40
|
+
span_context = ::Instana.tracer.context
|
|
41
|
+
return unless span_context
|
|
42
|
+
|
|
43
|
+
params[:message_attributes] ||= {}
|
|
44
|
+
available_slots = 10 - params[:message_attributes].size
|
|
45
|
+
|
|
46
|
+
extra = ::Instana::Util.aws_message_attributes_w3c(span_context)
|
|
47
|
+
extra.merge!(::Instana::Util.aws_message_attributes_instana(span_context)) if available_slots >= 5
|
|
48
|
+
|
|
49
|
+
extra.reject! { |_, v| v[:string_value].nil? || v[:string_value].empty? }
|
|
50
|
+
params[:message_attributes].merge!(extra)
|
|
51
|
+
end
|
|
22
52
|
end
|
|
23
53
|
|
|
24
54
|
def add_handlers(handlers, _config)
|
|
@@ -36,11 +36,16 @@ module Instana
|
|
|
36
36
|
|
|
37
37
|
def inject_instana_headers(span, params)
|
|
38
38
|
params[:message_attributes] ||= {}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
span_context = span.context
|
|
40
|
+
return unless span_context
|
|
41
|
+
|
|
42
|
+
available_slots = 10 - params[:message_attributes].size
|
|
43
|
+
|
|
44
|
+
extra = ::Instana::Util.aws_message_attributes_w3c(span_context)
|
|
45
|
+
extra.merge!(::Instana::Util.aws_message_attributes_instana(span_context)) if available_slots >= 5
|
|
46
|
+
|
|
47
|
+
extra.reject! { |_, v| v[:string_value].nil? || v[:string_value].empty? }
|
|
48
|
+
params[:message_attributes].merge!(extra)
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
def tags_for(operation_name, params)
|
|
@@ -20,9 +20,11 @@ module Instana
|
|
|
20
20
|
::Instana.tracer.in_span(:rabbitmq, attributes: kvs) do |span|
|
|
21
21
|
# Inject trace context into message headers
|
|
22
22
|
options[:headers] ||= {}
|
|
23
|
-
options[:headers][
|
|
24
|
-
options[:headers][
|
|
25
|
-
options[:headers][
|
|
23
|
+
options[:headers][INSTANA_TRACE_ID_HEADER] = span.context.trace_id
|
|
24
|
+
options[:headers][INSTANA_SPAN_ID_HEADER] = span.context.span_id
|
|
25
|
+
options[:headers][INSTANA_LEVEL_HEADER] = span.context.level.to_s
|
|
26
|
+
options[:headers]['traceparent'] = span.context.trace_parent_header
|
|
27
|
+
options[:headers]['tracestate'] = span.context.trace_state_header
|
|
26
28
|
|
|
27
29
|
super(payload, options)
|
|
28
30
|
end
|
|
@@ -113,13 +115,28 @@ module Instana
|
|
|
113
115
|
return {} unless properties && properties.headers
|
|
114
116
|
|
|
115
117
|
headers = properties.headers
|
|
118
|
+
|
|
119
|
+
if headers[INSTANA_TRACE_ID_HEADER]
|
|
120
|
+
extract_instana_context(headers)
|
|
121
|
+
elsif headers['traceparent']
|
|
122
|
+
extract_w3c_context(headers)
|
|
123
|
+
else
|
|
124
|
+
{}
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def extract_instana_context(headers)
|
|
116
129
|
{
|
|
117
|
-
trace_id: headers[
|
|
118
|
-
span_id: headers[
|
|
119
|
-
level: headers[
|
|
130
|
+
trace_id: headers[INSTANA_TRACE_ID_HEADER],
|
|
131
|
+
span_id: headers[INSTANA_SPAN_ID_HEADER],
|
|
132
|
+
level: headers[INSTANA_LEVEL_HEADER]&.to_i || 1
|
|
120
133
|
}.reject { |_, v| v.nil? }
|
|
121
134
|
end
|
|
122
135
|
|
|
136
|
+
def extract_w3c_context(headers)
|
|
137
|
+
::Instana::Util.parse_w3c_trace_context(headers['traceparent'], headers['tracestate']) || {}
|
|
138
|
+
end
|
|
139
|
+
|
|
123
140
|
def log_error(error)
|
|
124
141
|
# Log errors on to console if INSTANA_DEBUG is enabled
|
|
125
142
|
::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{error.message}" }
|
|
@@ -8,8 +8,8 @@ module Instana
|
|
|
8
8
|
module GRPCCientInstrumentation
|
|
9
9
|
CALL_TYPES = [:request_response, :client_streamer, :server_streamer, :bidi_streamer]
|
|
10
10
|
|
|
11
|
-
CALL_TYPES.each do |call_type|
|
|
12
|
-
define_method(call_type) do |method, *others, **options|
|
|
11
|
+
CALL_TYPES.each do |call_type| # rubocop:disable Metrics/BlockLength
|
|
12
|
+
define_method(call_type) do |method, *others, **options| # rubocop:disable Metrics/BlockLength
|
|
13
13
|
begin
|
|
14
14
|
kvs = { rpc: {} }
|
|
15
15
|
|
|
@@ -26,10 +26,15 @@ module Instana
|
|
|
26
26
|
|
|
27
27
|
context = ::Instana.tracer.context
|
|
28
28
|
if context
|
|
29
|
-
|
|
29
|
+
extra = {
|
|
30
30
|
'x-instana-t' => context.trace_id_header,
|
|
31
|
-
'x-instana-s' => context.span_id_header
|
|
32
|
-
|
|
31
|
+
'x-instana-s' => context.span_id_header,
|
|
32
|
+
'x-instana-l' => context.level.to_s,
|
|
33
|
+
'traceparent' => context.trace_parent_header,
|
|
34
|
+
'tracestate' => context.trace_state_header
|
|
35
|
+
}
|
|
36
|
+
extra.reject! { |_, v| v.nil? || v.empty? }
|
|
37
|
+
options[:metadata] = (options[:metadata] || {}).merge(extra)
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
super(method, *others, **options)
|
|
@@ -58,12 +63,7 @@ module Instana
|
|
|
58
63
|
kvs = { rpc: {} }
|
|
59
64
|
metadata = active_call.metadata
|
|
60
65
|
|
|
61
|
-
incoming_context =
|
|
62
|
-
if metadata.key?('x-instana-t')
|
|
63
|
-
incoming_context = SpanContext.new(trace_id: ::Instana::Util.header_to_id(metadata['x-instana-t']),
|
|
64
|
-
span_id: metadata.key?('x-instana-s') ? ::Instana::Util.header_to_id(metadata['x-instana-s']) : nil,
|
|
65
|
-
level: metadata.key?('x-instana-l') ? metadata['x-instana-l'] : nil)
|
|
66
|
-
end
|
|
66
|
+
incoming_context = extract_grpc_context(metadata)
|
|
67
67
|
|
|
68
68
|
kvs[:rpc][:flavor] = :grpc
|
|
69
69
|
kvs[:rpc][:host] = Socket.gethostname
|
|
@@ -87,6 +87,34 @@ module Instana
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def extract_grpc_context(metadata)
|
|
94
|
+
if metadata.key?('x-instana-t')
|
|
95
|
+
extract_instana_grpc_context(metadata)
|
|
96
|
+
elsif metadata.key?('traceparent')
|
|
97
|
+
extract_w3c_grpc_context(metadata)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def extract_instana_grpc_context(metadata)
|
|
102
|
+
SpanContext.new(
|
|
103
|
+
trace_id: ::Instana::Util.header_to_id(metadata['x-instana-t']),
|
|
104
|
+
span_id: metadata.key?('x-instana-s') ? ::Instana::Util.header_to_id(metadata['x-instana-s']) : nil,
|
|
105
|
+
level: metadata['x-instana-l'] || 1
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def extract_w3c_grpc_context(metadata)
|
|
110
|
+
ctx = ::Instana::Util.parse_w3c_trace_context(metadata['traceparent'], metadata['tracestate'])
|
|
111
|
+
return nil unless ctx
|
|
112
|
+
|
|
113
|
+
SpanContext.new(trace_id: ctx[:trace_id],
|
|
114
|
+
span_id: ctx[:span_id],
|
|
115
|
+
level: ctx[:level],
|
|
116
|
+
baggage: ctx.slice(:external_trace_id, :external_trace_flags, :external_state))
|
|
117
|
+
end
|
|
90
118
|
end
|
|
91
119
|
end
|
|
92
120
|
end
|
|
@@ -32,19 +32,14 @@ module Instana
|
|
|
32
32
|
|
|
33
33
|
context[:level] = @env['HTTP_X_INSTANA_L'][0] if @env['HTTP_X_INSTANA_L']
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
context.delete(:span_id)
|
|
40
|
-
context[:from_w3c] = false
|
|
41
|
-
elsif context[:from_w3c] && !trace_state.empty?
|
|
42
|
-
context[:trace_id] = trace_state[:t]
|
|
43
|
-
context[:span_id] = trace_state[:p]
|
|
44
|
-
context[:from_w3c] = false
|
|
45
|
-
end
|
|
35
|
+
# Honour W3C sampled bit when no X-Instana-L is present.
|
|
36
|
+
if context[:level].nil? && context[:external_trace_flags]
|
|
37
|
+
w3c_sampled = (context[:external_trace_flags].to_i(16) & 0x01) == 1
|
|
38
|
+
context[:level] = w3c_sampled ? '1' : '0'
|
|
46
39
|
end
|
|
47
40
|
|
|
41
|
+
apply_legacy_w3c_override(context) unless ::Instana.config[:w3c_trace_correlation]
|
|
42
|
+
|
|
48
43
|
context
|
|
49
44
|
end
|
|
50
45
|
|
|
@@ -107,6 +102,21 @@ module Instana
|
|
|
107
102
|
|
|
108
103
|
private
|
|
109
104
|
|
|
105
|
+
def apply_legacy_w3c_override(context)
|
|
106
|
+
return unless context[:from_w3c]
|
|
107
|
+
|
|
108
|
+
trace_state = parse_trace_state
|
|
109
|
+
|
|
110
|
+
if trace_state.empty?
|
|
111
|
+
context.delete(:span_id)
|
|
112
|
+
else
|
|
113
|
+
context[:trace_id] = trace_state[:t]
|
|
114
|
+
context[:span_id] = trace_state[:p]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context[:from_w3c] = false
|
|
118
|
+
end
|
|
119
|
+
|
|
110
120
|
def context_from_instana_headers
|
|
111
121
|
sanitized_t = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T'])
|
|
112
122
|
sanitized_s = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_S'])
|
|
@@ -79,7 +79,8 @@ module Instana
|
|
|
79
79
|
context_from_wire = job.payload['args'].pop
|
|
80
80
|
::Instana::SpanContext.new(
|
|
81
81
|
trace_id: context_from_wire['trace_id'],
|
|
82
|
-
span_id: context_from_wire['span_id']
|
|
82
|
+
span_id: context_from_wire['span_id'],
|
|
83
|
+
level: context_from_wire['level'] || 1
|
|
83
84
|
)
|
|
84
85
|
end
|
|
85
86
|
span = OpenTelemetry::Trace.non_recording_span(trace_context) if trace_context
|
|
@@ -15,24 +15,45 @@ module Instana
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
context = incomming_context_from(sqs_message.message_attributes)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if context[:trace_id]
|
|
19
|
+
instana_context = Instana::SpanContext.new(
|
|
20
|
+
trace_id: context[:trace_id],
|
|
21
|
+
span_id: context[:span_id],
|
|
22
|
+
level: context[:level] || 1
|
|
23
|
+
)
|
|
24
|
+
Trace.with_span(OpenTelemetry::Trace.non_recording_span(instana_context)) do
|
|
25
|
+
::Instana.tracer.in_span(:sqs, attributes: { sqs: sqs_tags }, &block)
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
::Instana.tracer.in_span(:sqs, attributes: { sqs: sqs_tags }, &block)
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
|
|
24
32
|
private
|
|
25
33
|
|
|
26
34
|
def incomming_context_from(attributes)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
return {} unless attributes
|
|
36
|
+
|
|
37
|
+
if read_message_header(attributes, 'X_INSTANA_T')
|
|
38
|
+
trace_id = read_message_header(attributes, 'X_INSTANA_T')
|
|
39
|
+
span_id = read_message_header(attributes, 'X_INSTANA_S')
|
|
40
|
+
level = read_message_header(attributes, 'X_INSTANA_L')
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
trace_id: trace_id,
|
|
44
|
+
span_id: span_id,
|
|
45
|
+
level: level ? level.to_i : 1
|
|
46
|
+
}.reject { |_, v| v.nil? }
|
|
47
|
+
else
|
|
48
|
+
w3c_context_from(attributes)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def w3c_context_from(attributes)
|
|
53
|
+
::Instana::Util.parse_w3c_trace_context(
|
|
54
|
+
read_message_header(attributes, 'traceparent'),
|
|
55
|
+
read_message_header(attributes, 'tracestate')
|
|
56
|
+
) || {}
|
|
36
57
|
end
|
|
37
58
|
|
|
38
59
|
def read_message_header(attributes, key)
|
|
@@ -30,10 +30,12 @@ module Instana
|
|
|
30
30
|
trace_context = nil
|
|
31
31
|
if msg.key?('X-Instana-T')
|
|
32
32
|
trace_id = msg.delete('X-Instana-T')
|
|
33
|
-
span_id
|
|
33
|
+
span_id = msg.delete('X-Instana-S')
|
|
34
|
+
level = msg.delete('X-Instana-L')
|
|
34
35
|
trace_context = ::Instana::SpanContext.new(
|
|
35
36
|
trace_id: ::Instana::Util.header_to_id(trace_id),
|
|
36
|
-
span_id: span_id ? ::Instana::Util.header_to_id(span_id) : nil
|
|
37
|
+
span_id: span_id ? ::Instana::Util.header_to_id(span_id) : nil,
|
|
38
|
+
level: level || 1
|
|
37
39
|
)
|
|
38
40
|
end
|
|
39
41
|
|
data/lib/instana/util.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# (c) Copyright Instana Inc. 2016
|
|
3
3
|
|
|
4
4
|
module Instana
|
|
5
|
-
module Util
|
|
5
|
+
module Util # rubocop:disable Metrics/ModuleLength
|
|
6
6
|
class << self
|
|
7
7
|
ID_RANGE = -2**63..2**63-1
|
|
8
8
|
# Retrieves and returns the source code for any ruby
|
|
@@ -171,6 +171,44 @@ module Instana
|
|
|
171
171
|
given
|
|
172
172
|
end
|
|
173
173
|
|
|
174
|
+
# Parse W3C +traceparent+ / +tracestate+ values using the OpenTelemetry
|
|
175
|
+
# trace-context propagator.
|
|
176
|
+
#
|
|
177
|
+
# When the tracestate carries an Instana entry (+in=<trace>;<span>+) it
|
|
178
|
+
# takes precedence over the ids in the traceparent.
|
|
179
|
+
#
|
|
180
|
+
# @param traceparent [String] the traceparent header value
|
|
181
|
+
# @param tracestate [String, nil] the tracestate header value
|
|
182
|
+
#
|
|
183
|
+
# @return [Hash, nil] +nil+ when the traceparent is missing or invalid,
|
|
184
|
+
# otherwise a hash with:
|
|
185
|
+
# - +:trace_id+, +:span_id+, +:level+ for continuing the trace
|
|
186
|
+
# - +:external_trace_id+, +:external_trace_flags+, +:external_state+
|
|
187
|
+
# for re-emitting the W3C context downstream
|
|
188
|
+
#
|
|
189
|
+
def parse_w3c_trace_context(traceparent, tracestate = nil)
|
|
190
|
+
return nil unless traceparent.is_a?(String)
|
|
191
|
+
|
|
192
|
+
carrier = { 'traceparent' => traceparent, 'tracestate' => tracestate.is_a?(String) ? tracestate : nil }
|
|
193
|
+
extracted = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator.extract(
|
|
194
|
+
carrier, context: OpenTelemetry::Context.empty
|
|
195
|
+
)
|
|
196
|
+
span_context = OpenTelemetry::Trace.current_span(extracted).context
|
|
197
|
+
return nil unless span_context.valid?
|
|
198
|
+
|
|
199
|
+
sampled = span_context.trace_flags.sampled?
|
|
200
|
+
instana_state = span_context.tracestate.value('in')&.match(/\A(?<trace>[0-9a-f]+);(?<span>[0-9a-f]+)\z/)
|
|
201
|
+
|
|
202
|
+
{
|
|
203
|
+
trace_id: header_to_id(instana_state ? instana_state[:trace] : span_context.hex_trace_id[16..]),
|
|
204
|
+
span_id: header_to_id(instana_state ? instana_state[:span] : span_context.hex_span_id),
|
|
205
|
+
level: sampled ? 1 : 0,
|
|
206
|
+
external_trace_id: span_context.hex_trace_id,
|
|
207
|
+
external_trace_flags: sampled ? '01' : '00',
|
|
208
|
+
external_state: tracestate
|
|
209
|
+
}
|
|
210
|
+
end
|
|
211
|
+
|
|
174
212
|
def timeout_timestamp
|
|
175
213
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
176
214
|
end
|
|
@@ -229,6 +267,35 @@ module Instana
|
|
|
229
267
|
|
|
230
268
|
klass.name.sub('Net::HTTP', '').gsub(/([A-Z])/, ' \1').strip
|
|
231
269
|
end
|
|
270
|
+
|
|
271
|
+
# Build the W3C trace-context message attributes for an AWS message
|
|
272
|
+
# (SQS or SNS). Returns a hash suitable for merging into
|
|
273
|
+
# +params[:message_attributes]+.
|
|
274
|
+
#
|
|
275
|
+
# @param span_context [Instana::SpanContext]
|
|
276
|
+
# @return [Hash]
|
|
277
|
+
#
|
|
278
|
+
def aws_message_attributes_w3c(span_context)
|
|
279
|
+
{
|
|
280
|
+
'traceparent' => { data_type: 'String', string_value: span_context.trace_parent_header },
|
|
281
|
+
'tracestate' => { data_type: 'String', string_value: span_context.trace_state_header }
|
|
282
|
+
}
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Build the Instana proprietary message attributes for an AWS message
|
|
286
|
+
# (SQS or SNS). Returns a hash suitable for merging into
|
|
287
|
+
# +params[:message_attributes]+.
|
|
288
|
+
#
|
|
289
|
+
# @param span_context [Instana::SpanContext]
|
|
290
|
+
# @return [Hash]
|
|
291
|
+
#
|
|
292
|
+
def aws_message_attributes_instana(span_context)
|
|
293
|
+
{
|
|
294
|
+
'X_INSTANA_T' => { data_type: 'String', string_value: span_context.trace_id },
|
|
295
|
+
'X_INSTANA_S' => { data_type: 'String', string_value: span_context.span_id },
|
|
296
|
+
'X_INSTANA_L' => { data_type: 'String', string_value: span_context.level.to_s }
|
|
297
|
+
}
|
|
298
|
+
end
|
|
232
299
|
end
|
|
233
300
|
end
|
|
234
301
|
end
|
data/lib/instana/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: instana
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Giacomo Lombardo
|
|
@@ -416,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
416
416
|
- !ruby/object:Gem::Version
|
|
417
417
|
version: '0'
|
|
418
418
|
requirements: []
|
|
419
|
-
rubygems_version: 4.0.
|
|
419
|
+
rubygems_version: 4.0.23
|
|
420
420
|
specification_version: 4
|
|
421
421
|
summary: Ruby Distributed Tracing & Metrics Sensor for Instana
|
|
422
422
|
test_files: []
|