instana 2.7.1 → 2.8.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.
@@ -0,0 +1,403 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright IBM Corp. 2026
4
+
5
+ require 'socket'
6
+ require 'opentelemetry/semantic_conventions'
7
+ require_relative '../../util'
8
+
9
+ module Instana
10
+ module Exporter
11
+ module Otlp
12
+ # Resource represents a resource, which captures identifying information about the entities
13
+ # for which telemetry (metrics or traces) is reported.
14
+ # This follows OpenTelemetry semantic conventions for resource attributes
15
+ class Resource
16
+ PROC_SELF_CGROUP = '/proc/self/cgroup'
17
+ DOCKER_ENV_FILE = '/.dockerenv'
18
+ PODMAN_CONTAINERENV = '/run/.containerenv'
19
+ # Linux-only stable machine-id paths (systemd and D-Bus fallback).
20
+ # These files do not exist on macOS or Windows; host_id returns nil there.
21
+ MACHINE_ID_PATHS = %w[/etc/machine-id /var/lib/dbus/machine-id].freeze
22
+ # cloud.resource_id is not yet in the installed semconv gem version
23
+ CLOUD_RESOURCE_ID = 'cloud.resource_id'
24
+
25
+ class << self
26
+ private :new
27
+
28
+ # Returns a newly created {Resource} with the specified attributes
29
+ #
30
+ # @param [Hash{String => String, Numeric, Boolean}] attributes Hash of key-value pairs to be used
31
+ # as attributes for this resource
32
+ # @return [Resource]
33
+ def create(attributes = {})
34
+ frozen_attributes = attributes.each_with_object({}) do |(k, v), memo|
35
+ memo[k.freeze] = v.freeze
36
+ end.freeze
37
+
38
+ new(frozen_attributes)
39
+ end
40
+
41
+ # Returns the default resource with standard attributes
42
+ #
43
+ # @return [Resource]
44
+ def default
45
+ @default ||= create(OpenTelemetry::SemanticConventions::Resource::SERVICE_NAME => 'ruby-service')
46
+ .merge(process)
47
+ .merge(telemetry_sdk)
48
+ .merge(service_name_from_env)
49
+ .merge(optional_attributes)
50
+ .merge(container_attributes)
51
+ .merge(faas_attributes)
52
+ end
53
+
54
+ # Get the global resource instance (singleton pattern)
55
+ # This method provides backward compatibility with the previous API
56
+ #
57
+ # @return [Hash] Resource attributes as a hash
58
+ def instance
59
+ @instance ||= default.attributes
60
+ end
61
+
62
+ # Reset the resource instance (useful for testing)
63
+ # This method provides backward compatibility with the previous API
64
+ def reset!
65
+ @instance = nil
66
+ @default = nil
67
+ end
68
+
69
+ # Returns telemetry SDK resource attributes
70
+ #
71
+ # @return [Resource]
72
+ def telemetry_sdk
73
+ create(
74
+ OpenTelemetry::SemanticConventions::Resource::TELEMETRY_SDK_NAME => 'instana',
75
+ OpenTelemetry::SemanticConventions::Resource::TELEMETRY_SDK_LANGUAGE => 'ruby',
76
+ OpenTelemetry::SemanticConventions::Resource::TELEMETRY_SDK_VERSION => ::Instana::VERSION
77
+ )
78
+ end
79
+
80
+ # Returns process resource attributes
81
+ #
82
+ # @return [Resource]
83
+ def process
84
+ create(
85
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_PID => Process.pid,
86
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_COMMAND => $PROGRAM_NAME,
87
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_EXECUTABLE_NAME => File.basename($PROGRAM_NAME),
88
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_RUNTIME_NAME => RUBY_ENGINE,
89
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_RUNTIME_VERSION => RUBY_VERSION,
90
+ OpenTelemetry::SemanticConventions::Resource::PROCESS_RUNTIME_DESCRIPTION => RUBY_DESCRIPTION
91
+ )
92
+ end
93
+
94
+ private
95
+
96
+ # Returns service name from environment variables
97
+ #
98
+ # @return [Resource]
99
+ def service_name_from_env
100
+ service_name = ENV.fetch('OTEL_SERVICE_NAME', nil) ||
101
+ ENV.fetch('INSTANA_SERVICE_NAME', nil) ||
102
+ ::Instana::Util.get_app_name
103
+
104
+ return create({}) unless service_name
105
+
106
+ create(OpenTelemetry::SemanticConventions::Resource::SERVICE_NAME => service_name)
107
+ end
108
+
109
+ # Returns optional resource attributes:
110
+ # os.type, host.name, host.arch, host.id, service.version, service.instance.id
111
+ #
112
+ # service.instance.id priority (v2 spec §General Resource Attributes):
113
+ # container.id → k8s.pod.uid → host.id → hostname:pid
114
+ #
115
+ # @return [Resource]
116
+ def optional_attributes
117
+ attrs = {}
118
+
119
+ # os.type — Required per v2 spec
120
+ attrs[OpenTelemetry::SemanticConventions::Resource::OS_TYPE] = detect_os_type
121
+
122
+ host = hostname
123
+
124
+ # host.name — Recommended (Conditional) per v2 spec
125
+ attrs[OpenTelemetry::SemanticConventions::Resource::HOST_NAME] = host if host && host != 'unknown'
126
+
127
+ # host.arch
128
+ arch = host_architecture
129
+ attrs[OpenTelemetry::SemanticConventions::Resource::HOST_ARCH] = arch if arch
130
+
131
+ # host.id — Recommended per v2 spec; stable machine identifier
132
+ hid = host_id
133
+ attrs[OpenTelemetry::SemanticConventions::Resource::HOST_ID] = hid if hid
134
+
135
+ # service.version
136
+ version = ENV.fetch('OTEL_SERVICE_VERSION', nil) ||
137
+ ENV.fetch('INSTANA_SERVICE_VERSION', nil) ||
138
+ detect_app_version
139
+ attrs[OpenTelemetry::SemanticConventions::Resource::SERVICE_VERSION] = version if version
140
+
141
+ # service.instance.id — priority: container.id > k8s.pod.uid > host.id > hostname:pid
142
+ instance_id = extract_container_id ||
143
+ ENV.fetch('MY_POD_UID', nil) ||
144
+ hid ||
145
+ "#{host}:#{Process.pid}"
146
+ attrs[OpenTelemetry::SemanticConventions::Resource::SERVICE_INSTANCE_ID] = instance_id
147
+
148
+ create(attrs)
149
+ end
150
+
151
+ # Returns container and cloud platform resource attributes.
152
+ # AWS Lambda is intentionally excluded here — it is a FaaS platform,
153
+ # not a container runtime. See faas_attributes for Lambda/Cloud Run.
154
+ #
155
+ # @return [Resource]
156
+ def container_attributes
157
+ attrs = {}
158
+
159
+ add_docker_or_podman_attributes(attrs)
160
+ add_kubernetes_attributes(attrs)
161
+ add_aws_ecs_attributes(attrs)
162
+
163
+ create(attrs)
164
+ end
165
+
166
+ # Returns FaaS (Function-as-a-Service) platform resource attributes.
167
+ # Kept separate from container_attributes because Lambda and Cloud Run
168
+ # are serverless runtimes, not container runtimes.
169
+ #
170
+ # @return [Resource]
171
+ def faas_attributes
172
+ attrs = {}
173
+
174
+ add_aws_lambda_attributes(attrs)
175
+ add_cloud_run_attributes(attrs)
176
+
177
+ create(attrs)
178
+ end
179
+
180
+ # Sets container.runtime and container.id attributes when a container
181
+ # engine is detected. Only runs on Linux since all sentinel paths are
182
+ # Linux-specific.
183
+ def add_docker_or_podman_attributes(attrs)
184
+ return unless linux?
185
+
186
+ engine = extract_container_engine
187
+ attrs[OpenTelemetry::SemanticConventions::Resource::CONTAINER_RUNTIME] = engine if engine
188
+
189
+ container_id = extract_container_id
190
+ attrs[OpenTelemetry::SemanticConventions::Resource::CONTAINER_ID] = container_id if container_id
191
+ end
192
+
193
+ # Detects the container engine by inspecting Linux sentinel files.
194
+ # Returns 'podman', 'docker', or nil if no container environment is found.
195
+ #
196
+ # @return [String, nil]
197
+ def extract_container_engine
198
+ if File.exist?(PODMAN_CONTAINERENV)
199
+ 'podman'
200
+ elsif File.exist?(DOCKER_ENV_FILE) || File.exist?(PROC_SELF_CGROUP)
201
+ 'docker'
202
+ end
203
+ end
204
+
205
+ def add_kubernetes_attributes(attrs)
206
+ return unless ENV.fetch('KUBERNETES_SERVICE_HOST', nil)
207
+
208
+ attrs[OpenTelemetry::SemanticConventions::Resource::K8S_POD_NAME] = ENV.fetch('HOSTNAME', nil)
209
+
210
+ pod_uid = ENV.fetch('MY_POD_UID', nil)
211
+ attrs[OpenTelemetry::SemanticConventions::Resource::K8S_POD_UID] = pod_uid if pod_uid
212
+
213
+ ns = ENV.fetch('KUBERNETES_NAMESPACE', nil)
214
+ attrs[OpenTelemetry::SemanticConventions::Resource::K8S_NAMESPACE_NAME] = ns if ns
215
+ end
216
+
217
+ def add_aws_ecs_attributes(attrs)
218
+ return unless ENV.fetch('ECS_CONTAINER_METADATA_URI', nil) || ENV.fetch('ECS_CONTAINER_METADATA_URI_V4', nil)
219
+
220
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PROVIDER] = 'aws'
221
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PLATFORM] = 'aws_ecs'
222
+ end
223
+
224
+ def add_aws_lambda_attributes(attrs)
225
+ lambda_name = ENV.fetch('AWS_LAMBDA_FUNCTION_NAME', nil)
226
+ return unless lambda_name
227
+
228
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PROVIDER] = 'aws'
229
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PLATFORM] = 'aws_lambda'
230
+ attrs[OpenTelemetry::SemanticConventions::Resource::FAAS_NAME] = lambda_name
231
+
232
+ version = ENV.fetch('AWS_LAMBDA_FUNCTION_VERSION', nil)
233
+ attrs[OpenTelemetry::SemanticConventions::Resource::FAAS_VERSION] = version if version
234
+
235
+ arn = ENV.fetch('AWS_LAMBDA_FUNCTION_ARN', nil)
236
+ attrs.merge!(parse_lambda_arn(arn)) if arn
237
+ end
238
+
239
+ def add_cloud_run_attributes(attrs)
240
+ service = ENV.fetch('K_SERVICE', nil)
241
+ return unless service
242
+
243
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PROVIDER] = 'gcp'
244
+ attrs[OpenTelemetry::SemanticConventions::Resource::CLOUD_PLATFORM] = 'gcp_cloud_run'
245
+ attrs[OpenTelemetry::SemanticConventions::Resource::FAAS_NAME] = service
246
+
247
+ revision = ENV.fetch('K_REVISION', nil)
248
+ attrs[OpenTelemetry::SemanticConventions::Resource::FAAS_VERSION] = revision if revision
249
+ end
250
+
251
+ # Returns true when the current OS is Linux.
252
+ #
253
+ # @return [Boolean]
254
+ def linux?
255
+ detect_os_type == 'linux'
256
+ end
257
+
258
+ # Detect the OS type string per OTel semconv os.type values.
259
+ # Returns one of: "linux", "darwin", "windows", or the raw RbConfig string.
260
+ #
261
+ # @return [String]
262
+ def detect_os_type
263
+ raw = RbConfig::CONFIG['host_os'].to_s.downcase
264
+ case raw
265
+ when /linux/ then 'linux'
266
+ when /darwin/ then 'darwin'
267
+ when /mingw|mswin|cygwin/ then 'windows'
268
+ else raw
269
+ end
270
+ end
271
+
272
+ # Returns a stable machine-level identifier.
273
+ # Reads /etc/machine-id (Linux systemd standard) or
274
+ # /var/lib/dbus/machine-id as fallback. Returns nil on macOS/Windows.
275
+ #
276
+ # @return [String, nil]
277
+ def host_id
278
+ path = MACHINE_ID_PATHS.find { |machine_id_path| File.exist?(machine_id_path) }
279
+ return nil unless path
280
+
281
+ id = File.read(path).strip
282
+ return id unless id.empty?
283
+
284
+ nil
285
+ rescue StandardError
286
+ nil
287
+ end
288
+
289
+ # Parses a Lambda ARN and returns a hash of cloud.* resource attributes.
290
+ #
291
+ # @param arn [String] e.g. "arn:aws:lambda:us-east-1:123456789012:function:my-fn"
292
+ # @return [Hash]
293
+ def parse_lambda_arn(arn)
294
+ return {} if arn.nil? || arn.empty?
295
+
296
+ parts = arn.split(':')
297
+ result = {}
298
+ result[OpenTelemetry::SemanticConventions::Resource::CLOUD_REGION] = parts[3] if parts[3] && !parts[3].empty?
299
+ result[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = parts[4] if parts[4] && !parts[4].empty?
300
+ result[CLOUD_RESOURCE_ID] = arn
301
+ result
302
+ rescue StandardError
303
+ {}
304
+ end
305
+
306
+ # Get hostname
307
+ #
308
+ # @return [String] Hostname
309
+ def hostname
310
+ Socket.gethostname
311
+ rescue StandardError
312
+ 'unknown'
313
+ end
314
+
315
+ # Get host architecture
316
+ #
317
+ # @return [String] Host architecture
318
+ def host_architecture
319
+ RbConfig::CONFIG['host_cpu']
320
+ end
321
+
322
+ # Extract container ID from cgroup file
323
+ #
324
+ # @return [String, nil] Container ID
325
+ def extract_container_id
326
+ return nil unless File.exist?(PROC_SELF_CGROUP)
327
+
328
+ line = File.readlines(PROC_SELF_CGROUP).find do |l|
329
+ l.match?(%r{/docker/([a-f0-9]{64})})
330
+ end
331
+
332
+ return nil unless line
333
+
334
+ match = line.match(%r{/docker/([a-f0-9]{64})})
335
+ match[1]
336
+ rescue StandardError
337
+ nil
338
+ end
339
+
340
+ # Detect application version from various sources
341
+ #
342
+ # @return [String, nil] Application version
343
+ def detect_app_version
344
+ # Try to get version from Rails
345
+ if defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
346
+ app_class = ::Rails.application.class
347
+ return app_class::VERSION if app_class.const_defined?(:VERSION)
348
+ end
349
+
350
+ # Try to get version from Gemfile.lock
351
+ if File.exist?('Gemfile.lock')
352
+ lockfile = File.read('Gemfile.lock')
353
+ # Look for the main gem version (first gem in the file)
354
+ match = lockfile.match(/^\s{4}(\S+)\s+\(([^)]+)\)/)
355
+ return match[2] if match
356
+ end
357
+
358
+ nil
359
+ rescue StandardError
360
+ nil
361
+ end
362
+ end
363
+
364
+ # @api private
365
+ # The constructor is private and only for use internally by the class.
366
+ # Users should use the {create} factory method to obtain a {Resource}
367
+ # instance.
368
+ #
369
+ # @param [Hash<String, String>] frozen_attributes Frozen-hash of frozen-string
370
+ # key-value pairs to be used as attributes for this resource
371
+ # @return [Resource]
372
+ def initialize(frozen_attributes)
373
+ @attributes = frozen_attributes
374
+ end
375
+
376
+ # Returns an enumerator for attributes of this {Resource}
377
+ #
378
+ # @return [Enumerator]
379
+ def attribute_enumerator
380
+ @attribute_enumerator ||= attributes.to_enum
381
+ end
382
+
383
+ # Returns a new, merged {Resource} by merging the current {Resource} with
384
+ # the other {Resource}. In case of a collision, the other {Resource}
385
+ # takes precedence
386
+ #
387
+ # @param [Resource] other The other resource to merge
388
+ # @return [Resource] A new resource formed by merging the current resource
389
+ # with other
390
+ def merge(other)
391
+ return self unless other.is_a?(Resource)
392
+
393
+ self.class.send(:new, attributes.merge(other.send(:attributes)).freeze)
394
+ end
395
+
396
+ # Returns the attributes hash for this resource
397
+ #
398
+ # @return [Hash] The frozen attributes hash
399
+ attr_reader :attributes
400
+ end
401
+ end
402
+ end
403
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright IBM Corp. 2026
4
+
5
+ require_relative 'base_converter'
6
+ require 'opentelemetry/semconv/incubating/rpc'
7
+ require 'opentelemetry/semconv/incubating/code'
8
+ require 'opentelemetry/semconv/server'
9
+
10
+ module Instana
11
+ module Exporter
12
+ module Otlp
13
+ # Converter for RPC spans (gRPC, ActionCable) to OTLP format
14
+ class RpcConverter < BaseConverter
15
+ # Build OTel-compliant span name for RPC spans
16
+ #
17
+ # Formulas per SPAN_NAME_PATTERNS.txt Section 4:
18
+ # gRPC → "{package.Service/Method}" (leading "/" stripped per OTel spec)
19
+ # ActionCable → "{ChannelClass#action}" (call string used as-is)
20
+ #
21
+ # @return [String] The span name
22
+ def span_name
23
+ rpc_data = span[:data]&.[](:rpc) || {}
24
+
25
+ if rpc_data[:flavor] == :actioncable
26
+ rpc_data[:call].to_s
27
+ else
28
+ # Strip the mandatory leading slash per gRPC/OTel spec
29
+ rpc_data[:call].to_s.delete_prefix('/')
30
+ end.then { |n| n.empty? ? super : n }
31
+ end
32
+
33
+ def convert_attributes
34
+ attributes = {}
35
+
36
+ rpc_data = span[:data]&.[](:rpc)
37
+ return attributes unless rpc_data
38
+
39
+ # Check if this is an ActionCable span
40
+ if rpc_data[:flavor] == :actioncable
41
+ convert_action_cable_attributes(attributes, rpc_data)
42
+ else
43
+ convert_grpc_attributes(attributes, rpc_data)
44
+ end
45
+
46
+ attributes
47
+ end
48
+
49
+ private
50
+
51
+ # Convert gRPC span attributes
52
+ def convert_grpc_attributes(attributes, rpc_data)
53
+ # RPC system
54
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM, 'grpc')
55
+
56
+ # RPC service and method
57
+ if rpc_data[:call]
58
+ service, method = parse_grpc_call(rpc_data[:call])
59
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_SERVICE, service)
60
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_METHOD, method)
61
+ end
62
+
63
+ # Network peer
64
+ add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, rpc_data[:host])
65
+ add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, rpc_data.dig(:peer, :address))
66
+
67
+ # gRPC-specific attributes
68
+ add_attribute(attributes, 'rpc.grpc.call_type', rpc_data[:call_type])
69
+ end
70
+
71
+ # Convert ActionCable span attributes
72
+ def convert_action_cable_attributes(attributes, rpc_data)
73
+ # RPC system
74
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM, 'actioncable')
75
+
76
+ # ActionCable-specific attributes
77
+ add_attribute(attributes, 'rails.actioncable.channel', rpc_data[:call])
78
+ add_attribute(attributes, 'rails.actioncable.call_type', rpc_data[:call_type])
79
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_SERVICE, span[:data]&.[](:service) || span[:service])
80
+
81
+ # Extract channel class and action from the call attribute
82
+ # Format can be either "ChannelClass" (for transmit) or "ChannelClass#action" (for action dispatch)
83
+ if rpc_data[:call]
84
+ call_parts = rpc_data[:call].to_s.split('#')
85
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CODE::CODE_NAMESPACE, call_parts[0])
86
+ add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CODE::CODE_FUNCTION, call_parts[1]) if call_parts[1]
87
+ end
88
+
89
+ # Network peer
90
+ add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, rpc_data[:host])
91
+ end
92
+
93
+ def parse_grpc_call(call)
94
+ parts = call.to_s.split('/')
95
+ return [nil, nil] if parts.size < 3
96
+
97
+ [parts[1], parts[2]]
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -9,7 +9,13 @@ module Instana
9
9
  end
10
10
 
11
11
  def process
12
- @instana_trace_context ||= ::Instana.tracer.tracing? ? ::Instana.tracer.current_span.context : {}
12
+ # Wrapped in non_recording_span by the channel callbacks below, so it
13
+ # must be a SpanContext.
14
+ @instana_trace_context ||= if ::Instana.tracer.tracing?
15
+ ::Instana.tracer.current_span.context
16
+ else
17
+ OpenTelemetry::Trace::SpanContext::INVALID
18
+ end
13
19
  super
14
20
  end
15
21
  end
@@ -58,7 +58,7 @@ module Instana
58
58
  kvs = { rpc: {} }
59
59
  metadata = active_call.metadata
60
60
 
61
- incoming_context = {}
61
+ incoming_context = nil
62
62
  if metadata.key?('x-instana-t')
63
63
  incoming_context = SpanContext.new(trace_id: ::Instana::Util.header_to_id(metadata['x-instana-t']),
64
64
  span_id: metadata.key?('x-instana-s') ? ::Instana::Util.header_to_id(metadata['x-instana-s']) : nil,
@@ -57,7 +57,7 @@ module Instana
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
+ kv_payload[:http][:header] = extra_headers unless extra_headers && extra_headers.empty?
61
61
  response
62
62
  rescue => e
63
63
  current_span&.record_exception(e)
@@ -34,6 +34,7 @@ module Instana
34
34
  raise
35
35
  ensure
36
36
  finalize_trace(current_span, kvs, headers, trace_context) if ::Instana.tracer.tracing?
37
+ OpenTelemetry::Context.detach(@trace_token) if @trace_token
37
38
  end
38
39
 
39
40
  private
@@ -123,7 +124,6 @@ module Instana
123
124
  def finalize_trace(current_span, kvs, headers, trace_context)
124
125
  set_response_headers(headers, trace_context) if headers
125
126
  current_span.add_attributes(kvs)
126
- OpenTelemetry::Context.detach(@trace_token) if @trace_token
127
127
  current_span.finish
128
128
  end
129
129
 
@@ -68,7 +68,10 @@ module Instana
68
68
 
69
69
  def self.should_sample?(trace_id:, parent_context:, links:, name:, kind:, attributes:) # rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument:
70
70
  parent_span_context = OpenTelemetry::Trace.current_span(parent_context).context
71
- tracestate = parent_span_context&.tracestate
71
+ # Parents wrapped in non_recording_span can expose a non-SpanContext
72
+ # #context; the new span's SpanContext needs a Tracestate, never nil.
73
+ tracestate = parent_span_context.tracestate if parent_span_context.respond_to?(:tracestate)
74
+ tracestate ||= OpenTelemetry::Trace::Tracestate::DEFAULT
72
75
  Result.new(decision: :__record_only__, tracestate: tracestate)
73
76
  end
74
77
  end
@@ -323,7 +323,9 @@ module Instana
323
323
  # with_parent=current context, start_timestamp=current time.
324
324
  #
325
325
  def start_span(name, with_parent: nil, attributes: nil, links: nil, start_timestamp: ::Instana::Util.now_in_ms, kind: nil) # rubocop:disable Metrics/ParameterLists
326
- return Instana::Trace.non_recording_span(with_parent) if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
326
+ # The placeholder's #context is read back as the parent by the next span
327
+ # start, so it must be a SpanContext (INVALID when there is no parent).
328
+ return Instana::Trace.non_recording_span(OpenTelemetry::Trace.current_span(with_parent).context) if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
327
329
 
328
330
  with_parent ||= OpenTelemetry::Context.current
329
331
  name ||= 'empty'
@@ -2,6 +2,6 @@
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
4
  module Instana
5
- VERSION = "2.7.1"
5
+ VERSION = "2.8.0"
6
6
  VERSION_FULL = "instana-#{VERSION}"
7
7
  end
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.7.1
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Giacomo Lombardo
@@ -93,6 +93,20 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rack
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
96
110
  - !ruby/object:Gem::Dependency
97
111
  name: base64
98
112
  requirement: !ruby/object:Gem::Requirement
@@ -191,6 +205,34 @@ dependencies:
191
205
  - - ">="
192
206
  - !ruby/object:Gem::Version
193
207
  version: '0'
208
+ - !ruby/object:Gem::Dependency
209
+ name: opentelemetry-semantic_conventions
210
+ requirement: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ type: :runtime
216
+ prerelease: false
217
+ version_requirements: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: opentelemetry-exporter-otlp
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ type: :runtime
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
194
236
  - !ruby/object:Gem::Dependency
195
237
  name: cgi
196
238
  requirement: !ruby/object:Gem::Requirement
@@ -277,6 +319,18 @@ files:
277
319
  - lib/instana/backend/serverless_agent.rb
278
320
  - lib/instana/base.rb
279
321
  - lib/instana/config.rb
322
+ - lib/instana/exporter/otlp/aws_converter.rb
323
+ - lib/instana/exporter/otlp/background_job_converter.rb
324
+ - lib/instana/exporter/otlp/base_converter.rb
325
+ - lib/instana/exporter/otlp/converter_factory.rb
326
+ - lib/instana/exporter/otlp/custom_converter.rb
327
+ - lib/instana/exporter/otlp/database_converter.rb
328
+ - lib/instana/exporter/otlp/graphql_converter.rb
329
+ - lib/instana/exporter/otlp/http_converter.rb
330
+ - lib/instana/exporter/otlp/messaging_converter.rb
331
+ - lib/instana/exporter/otlp/rails_converter.rb
332
+ - lib/instana/exporter/otlp/resource.rb
333
+ - lib/instana/exporter/otlp/rpc_converter.rb
280
334
  - lib/instana/frameworks/cuba.rb
281
335
  - lib/instana/frameworks/rails.rb
282
336
  - lib/instana/frameworks/roda.rb
@@ -362,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
362
416
  - !ruby/object:Gem::Version
363
417
  version: '0'
364
418
  requirements: []
365
- rubygems_version: 4.0.14
419
+ rubygems_version: 4.0.18
366
420
  specification_version: 4
367
421
  summary: Ruby Distributed Tracing & Metrics Sensor for Instana
368
422
  test_files: []