instana 2.1.0 → 2.2.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/instrumentation/instrumented_request.rb +2 -0
- data/lib/instana/instrumentation/net-http.rb +2 -1
- data/lib/instana/instrumentation/rack.rb +86 -66
- data/lib/instana/trace/span_context.rb +10 -2
- data/lib/instana/trace/tracer.rb +0 -21
- data/lib/instana/util.rb +13 -0
- data/lib/instana/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a940d6791ca18a45f73ca949de0268cb4195ca269991d78683d1d89c3801919
|
|
4
|
+
data.tar.gz: c4a79bc94556b873ca0d2cb3cbe2b988914e2579d6fd124bbf4925142316dd85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0c11ead2a6eb5e7cf4811a44b0edb6af0edbed588e712a080b5de07a704fbd28b91474e593b6342537459fe69cc0fcc60dfb83c18618e8e4ca5babea5096d6b
|
|
7
|
+
data.tar.gz: 5a22a83d6a6f930df189a914116398b372976d95f76ce86ae63b18c2f014eb4aa170a5415f5b6feb2f69b63bc9aff511d16e2d5e5bfb2682c369a0299cb5d2d3
|
|
@@ -122,6 +122,7 @@ module Instana
|
|
|
122
122
|
long_instana_id: long_instana_id? ? sanitized_t : nil,
|
|
123
123
|
external_trace_id: external_trace_id,
|
|
124
124
|
external_state: @env['HTTP_TRACESTATE'],
|
|
125
|
+
external_trace_flags: context_from_trace_parent[:external_trace_flags],
|
|
125
126
|
from_w3c: false
|
|
126
127
|
}.reject { |_, v| v.nil? }
|
|
127
128
|
end
|
|
@@ -140,6 +141,7 @@ module Instana
|
|
|
140
141
|
external_state: @env['HTTP_TRACESTATE'],
|
|
141
142
|
trace_id: trace_id,
|
|
142
143
|
span_id: span_id,
|
|
144
|
+
external_trace_flags: matches['flags'],
|
|
143
145
|
from_w3c: true
|
|
144
146
|
}
|
|
145
147
|
end
|
|
@@ -56,7 +56,8 @@ module Instana
|
|
|
56
56
|
# without a backtrace (no exception)
|
|
57
57
|
current_span.record_exception(nil)
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
extra_headers = ::Instana::Util.extra_header_tags(response)&.merge(::Instana::Util.extra_header_tags(request))
|
|
60
|
+
kv_payload[:http][:header] = extra_headers unless extra_headers&.empty?
|
|
60
61
|
response
|
|
61
62
|
rescue => e
|
|
62
63
|
current_span&.record_exception(e)
|
|
@@ -10,7 +10,7 @@ module Instana
|
|
|
10
10
|
@app = app
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def call(env)
|
|
13
|
+
def call(env)
|
|
14
14
|
req = InstrumentedRequest.new(env)
|
|
15
15
|
kvs = {
|
|
16
16
|
http: req.request_tags
|
|
@@ -26,75 +26,14 @@ module Instana
|
|
|
26
26
|
@trace_token = OpenTelemetry::Context.attach(trace_ctx)
|
|
27
27
|
status, headers, response = @app.call(env)
|
|
28
28
|
|
|
29
|
-
if ::Instana.tracer.tracing?
|
|
30
|
-
|
|
31
|
-
current_span[:crid] = req.correlation_data[:id]
|
|
32
|
-
current_span[:crtp] = req.correlation_data[:type]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
if !req.instana_ancestor.empty? && req.continuing_from_trace_parent?
|
|
36
|
-
current_span[:ia] = req.instana_ancestor
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
if req.continuing_from_trace_parent?
|
|
40
|
-
current_span[:tp] = true
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
if req.external_trace_id?
|
|
44
|
-
current_span[:lt] = req.external_trace_id
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
if req.synthetic?
|
|
48
|
-
current_span[:sy] = true
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# In case some previous middleware returned a string status, make sure that we're dealing with
|
|
52
|
-
# an integer. In Ruby nil.to_i, "asdfasdf".to_i will always return 0 from Ruby versions 1.8.7 and newer.
|
|
53
|
-
# So if an 0 status is reported here, it indicates some other issue (e.g. no status from previous middleware)
|
|
54
|
-
# See Rack Spec: https://www.rubydoc.info/github/rack/rack/file/SPEC#label-The+Status
|
|
55
|
-
kvs[:http][:status] = status.to_i
|
|
56
|
-
|
|
57
|
-
if status.to_i >= 500
|
|
58
|
-
# Because of the 5xx response, we flag this span as errored but
|
|
59
|
-
# without a backtrace (no exception)
|
|
60
|
-
::Instana.tracer.log_error(nil)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# If the framework instrumentation provides a path template,
|
|
64
|
-
# pass it into the span here.
|
|
65
|
-
# See: https://www.instana.com/docs/tracing/custom-best-practices/#path-templates-visual-grouping-of-http-endpoints
|
|
66
|
-
kvs[:http][:path_tpl] = env['INSTANA_HTTP_PATH_TEMPLATE'] if env['INSTANA_HTTP_PATH_TEMPLATE']
|
|
67
|
-
|
|
68
|
-
# Save the span context before the trace ends so we can place
|
|
69
|
-
# them in the response headers in the ensure block
|
|
70
|
-
trace_context = ::Instana.tracer.current_span.context
|
|
71
|
-
end
|
|
72
|
-
|
|
29
|
+
trace_context = process_span_tags(req, current_span, kvs, status, env) if ::Instana.tracer.tracing?
|
|
30
|
+
merge_response_headers(kvs, headers)
|
|
73
31
|
[status, headers, response]
|
|
74
32
|
rescue Exception => e
|
|
75
33
|
current_span.record_exception(e) if ::Instana.tracer.tracing?
|
|
76
34
|
raise
|
|
77
35
|
ensure
|
|
78
|
-
if ::Instana.tracer.tracing?
|
|
79
|
-
if headers
|
|
80
|
-
# Set response headers; encode as hex string
|
|
81
|
-
if trace_context.active?
|
|
82
|
-
headers['X-Instana-T'] = trace_context.trace_id_header
|
|
83
|
-
headers['X-Instana-S'] = trace_context.span_id_header
|
|
84
|
-
headers['X-Instana-L'] = '1'
|
|
85
|
-
|
|
86
|
-
headers['Tracestate'] = trace_context.trace_state_header
|
|
87
|
-
else
|
|
88
|
-
headers['X-Instana-L'] = '0'
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
headers['Traceparent'] = trace_context.trace_parent_header
|
|
92
|
-
headers['Server-Timing'] = "intid;desc=#{trace_context.trace_id_header}"
|
|
93
|
-
end
|
|
94
|
-
current_span.set_tags(kvs)
|
|
95
|
-
OpenTelemetry::Context.detach(@trace_token) if @trace_token
|
|
96
|
-
current_span.finish
|
|
97
|
-
end
|
|
36
|
+
finalize_trace(current_span, kvs, headers, trace_context) if ::Instana.tracer.tracing?
|
|
98
37
|
end
|
|
99
38
|
|
|
100
39
|
private
|
|
@@ -112,7 +51,8 @@ module Instana
|
|
|
112
51
|
level: incoming_context[:level],
|
|
113
52
|
baggage: {
|
|
114
53
|
external_trace_id: incoming_context[:external_trace_id],
|
|
115
|
-
external_state: incoming_context[:external_state]
|
|
54
|
+
external_state: incoming_context[:external_state],
|
|
55
|
+
external_trace_flags: incoming_context[:external_trace_flags]
|
|
116
56
|
}
|
|
117
57
|
)
|
|
118
58
|
end
|
|
@@ -121,5 +61,85 @@ module Instana
|
|
|
121
61
|
end
|
|
122
62
|
parent_context
|
|
123
63
|
end
|
|
64
|
+
|
|
65
|
+
def process_span_tags(req, current_span, kvs, status, env)
|
|
66
|
+
add_correlation_data(req, current_span)
|
|
67
|
+
add_trace_parent_data(req, current_span)
|
|
68
|
+
add_status_and_error(kvs, status)
|
|
69
|
+
add_path_template(kvs, env)
|
|
70
|
+
|
|
71
|
+
# Save the span context before the trace ends so we can place
|
|
72
|
+
# them in the response headers in the ensure block
|
|
73
|
+
::Instana.tracer.current_span.context
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def add_correlation_data(req, current_span)
|
|
77
|
+
return if req.correlation_data.empty?
|
|
78
|
+
|
|
79
|
+
current_span[:crid] = req.correlation_data[:id]
|
|
80
|
+
current_span[:crtp] = req.correlation_data[:type]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def add_trace_parent_data(req, current_span)
|
|
84
|
+
if !req.instana_ancestor.empty? && req.continuing_from_trace_parent?
|
|
85
|
+
current_span[:ia] = req.instana_ancestor
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
current_span[:tp] = true if req.continuing_from_trace_parent?
|
|
89
|
+
current_span[:lt] = req.external_trace_id if req.external_trace_id?
|
|
90
|
+
current_span[:sy] = true if req.synthetic?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def add_status_and_error(kvs, status)
|
|
94
|
+
# In case some previous middleware returned a string status, make sure that we're dealing with
|
|
95
|
+
# an integer. In Ruby nil.to_i, "asdfasdf".to_i will always return 0 from Ruby versions 1.8.7 and newer.
|
|
96
|
+
# So if an 0 status is reported here, it indicates some other issue (e.g. no status from previous middleware)
|
|
97
|
+
# See Rack Spec: https://www.rubydoc.info/github/rack/rack/file/SPEC#label-The+Status
|
|
98
|
+
kvs[:http][:status] = status.to_i
|
|
99
|
+
|
|
100
|
+
return unless status.to_i >= 500
|
|
101
|
+
|
|
102
|
+
# Because of the 5xx response, we flag this span as errored but
|
|
103
|
+
# without a backtrace (no exception)
|
|
104
|
+
::Instana.tracer.log_error(nil)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def add_path_template(kvs, env)
|
|
108
|
+
# If the framework instrumentation provides a path template,
|
|
109
|
+
# pass it into the span here.
|
|
110
|
+
# See: https://www.instana.com/docs/tracing/custom-best-practices/#path-templates-visual-grouping-of-http-endpoints
|
|
111
|
+
kvs[:http][:path_tpl] = env['INSTANA_HTTP_PATH_TEMPLATE'] if env['INSTANA_HTTP_PATH_TEMPLATE']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def merge_response_headers(kvs, headers)
|
|
115
|
+
extra_response_headers = ::Instana::Util.extra_header_tags(headers)
|
|
116
|
+
if kvs[:http][:header].nil?
|
|
117
|
+
kvs[:http][:header] = extra_response_headers
|
|
118
|
+
else
|
|
119
|
+
kvs[:http][:header].merge!(extra_response_headers)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def finalize_trace(current_span, kvs, headers, trace_context)
|
|
124
|
+
set_response_headers(headers, trace_context) if headers
|
|
125
|
+
current_span.set_tags(kvs)
|
|
126
|
+
OpenTelemetry::Context.detach(@trace_token) if @trace_token
|
|
127
|
+
current_span.finish
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def set_response_headers(headers, trace_context)
|
|
131
|
+
# Set response headers; encode as hex string
|
|
132
|
+
if trace_context.active?
|
|
133
|
+
headers['X-Instana-T'] = trace_context.trace_id_header
|
|
134
|
+
headers['X-Instana-S'] = trace_context.span_id_header
|
|
135
|
+
headers['X-Instana-L'] = '1'
|
|
136
|
+
headers['Tracestate'] = trace_context.trace_state_header
|
|
137
|
+
else
|
|
138
|
+
headers['X-Instana-L'] = '0'
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
headers['Traceparent'] = trace_context.trace_parent_header
|
|
142
|
+
headers['Server-Timing'] = "intid;desc=#{trace_context.trace_id_header}"
|
|
143
|
+
end
|
|
124
144
|
end
|
|
125
145
|
end
|
|
@@ -42,8 +42,16 @@ module Instana
|
|
|
42
42
|
def trace_parent_header
|
|
43
43
|
trace = (@baggage[:external_trace_id] || trace_id_header).rjust(32, '0')
|
|
44
44
|
parent = span_id_header.rjust(16, '0')
|
|
45
|
-
flags = @
|
|
46
|
-
|
|
45
|
+
flags = if @baggage[:external_trace_flags]
|
|
46
|
+
# Parse external flags as 8-bit hex, clear LSB, then set LSB based on level
|
|
47
|
+
external_flags = @baggage[:external_trace_flags].to_i(16) & 0xFE # Clear LSB
|
|
48
|
+
combined_flags = external_flags | (@level == 1 ? 1 : 0) # Set LSB based on level
|
|
49
|
+
combined_flags = [combined_flags, 0xFF].min # Cap at 8-bit max
|
|
50
|
+
format('%02x', combined_flags)
|
|
51
|
+
else
|
|
52
|
+
@level == 1 ? "03" : "02"
|
|
53
|
+
end
|
|
54
|
+
flags = "03" if flags > "03"
|
|
47
55
|
"00-#{trace}-#{parent}-#{flags}"
|
|
48
56
|
end
|
|
49
57
|
|
data/lib/instana/trace/tracer.rb
CHANGED
|
@@ -307,27 +307,6 @@ module Instana
|
|
|
307
307
|
self.current_span = nil
|
|
308
308
|
end
|
|
309
309
|
|
|
310
|
-
# Creates a span that is active during the execution of the provided block.
|
|
311
|
-
# The span is automatically closed when the block completes, whether it completes
|
|
312
|
-
# normally or with an exception.
|
|
313
|
-
#
|
|
314
|
-
# @param name [String, Symbol] the name of the span to create
|
|
315
|
-
# @param attributes [Hash, nil] optional attributes to set on the span
|
|
316
|
-
# @param links [Array<Link>, nil] optional links to associate with the span
|
|
317
|
-
# @param start_timestamp [Integer, nil] optional start time for the span in milliseconds
|
|
318
|
-
# @param kind [Symbol, nil] optional span kind (e.g., :internal, :client, :server)
|
|
319
|
-
#
|
|
320
|
-
# @return [Object] the return value of the block
|
|
321
|
-
#
|
|
322
|
-
# @note This method is a wrapper around the parent class implementation and
|
|
323
|
-
# will only create a span if the Instana agent is ready and tracing is enabled.
|
|
324
|
-
#
|
|
325
|
-
def in_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
|
|
326
|
-
return if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
|
|
327
|
-
|
|
328
|
-
super
|
|
329
|
-
end
|
|
330
|
-
|
|
331
310
|
# Starts a new span with the given parameters.
|
|
332
311
|
#
|
|
333
312
|
# @param name [String, Symbol] the name of the span to create (defaults to 'empty' if nil)
|
data/lib/instana/util.rb
CHANGED
|
@@ -181,6 +181,19 @@ module Instana
|
|
|
181
181
|
timeout -= (timeout_timestamp - start_time)
|
|
182
182
|
timeout.positive? ? timeout : 0
|
|
183
183
|
end
|
|
184
|
+
|
|
185
|
+
def extra_header_tags(req_res_headers)
|
|
186
|
+
return {} if req_res_headers.nil?
|
|
187
|
+
return nil unless ::Instana.agent.extra_headers
|
|
188
|
+
|
|
189
|
+
headers = {}
|
|
190
|
+
|
|
191
|
+
::Instana.agent.extra_headers.each do |custom_header|
|
|
192
|
+
headers[custom_header.to_sym] = req_res_headers[custom_header] if req_res_headers.key?(custom_header)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
headers
|
|
196
|
+
end
|
|
184
197
|
end
|
|
185
198
|
end
|
|
186
199
|
end
|
data/lib/instana/version.rb
CHANGED