instana 1.195.2 → 1.197.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.
Files changed (88) 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 +60 -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 +73 -0
  15. data/lib/instana/backend/serverless_agent.rb +118 -0
  16. data/lib/instana/base.rb +8 -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/setup.rb +20 -11
  27. data/lib/instana/snapshot/deltable.rb +25 -0
  28. data/lib/instana/snapshot/docker_container.rb +151 -0
  29. data/lib/instana/snapshot/fargate_container.rb +88 -0
  30. data/lib/instana/snapshot/fargate_process.rb +67 -0
  31. data/lib/instana/snapshot/fargate_task.rb +72 -0
  32. data/lib/instana/snapshot/lambda_function.rb +36 -0
  33. data/lib/instana/snapshot/ruby_process.rb +48 -0
  34. data/lib/instana/tracer.rb +25 -143
  35. data/lib/instana/tracing/processor.rb +14 -22
  36. data/lib/instana/tracing/span.rb +31 -34
  37. data/lib/instana/tracing/span_context.rb +15 -10
  38. data/lib/instana/util.rb +8 -69
  39. data/lib/instana/version.rb +1 -1
  40. data/lib/opentracing.rb +26 -3
  41. data/test/backend/agent_test.rb +54 -0
  42. data/test/backend/gc_snapshot_test.rb +11 -0
  43. data/test/backend/host_agent_activation_observer_test.rb +72 -0
  44. data/test/backend/host_agent_lookup_test.rb +78 -0
  45. data/test/backend/host_agent_reporting_observer_test.rb +192 -0
  46. data/test/backend/host_agent_test.rb +47 -0
  47. data/test/backend/process_info_test.rb +63 -0
  48. data/test/backend/request_client_test.rb +39 -0
  49. data/test/backend/serverless_agent_test.rb +73 -0
  50. data/test/config_test.rb +10 -0
  51. data/test/instana_test.rb +11 -4
  52. data/test/instrumentation/excon_test.rb +15 -1
  53. data/test/instrumentation/rack_instrumented_request_test.rb +5 -2
  54. data/test/instrumentation/rack_test.rb +2 -14
  55. data/test/secrets_test.rb +41 -22
  56. data/test/snapshot/deltable_test.rb +17 -0
  57. data/test/snapshot/docker_container_test.rb +82 -0
  58. data/test/snapshot/fargate_container_test.rb +82 -0
  59. data/test/snapshot/fargate_process_test.rb +35 -0
  60. data/test/snapshot/fargate_task_test.rb +49 -0
  61. data/test/snapshot/ruby_process_test.rb +14 -0
  62. data/test/support/mock_timer.rb +20 -0
  63. data/test/test_helper.rb +16 -4
  64. data/test/tracing/custom_test.rb +1 -3
  65. data/test/tracing/id_management_test.rb +4 -0
  66. data/test/tracing/opentracing_test.rb +15 -2
  67. data/test/tracing/processor_test.rb +58 -0
  68. data/test/tracing/span_context_test.rb +21 -0
  69. data/test/tracing/span_test.rb +136 -0
  70. data/test/tracing/tracer_async_test.rb +29 -0
  71. data/test/tracing/tracer_test.rb +82 -16
  72. data/test/util_test.rb +10 -0
  73. metadata +71 -43
  74. data/lib/instana/agent.rb +0 -508
  75. data/lib/instana/agent/helpers.rb +0 -87
  76. data/lib/instana/agent/hooks.rb +0 -44
  77. data/lib/instana/agent/tasks.rb +0 -51
  78. data/lib/instana/collector.rb +0 -119
  79. data/lib/instana/collectors/gc.rb +0 -60
  80. data/lib/instana/collectors/memory.rb +0 -37
  81. data/lib/instana/collectors/thread.rb +0 -33
  82. data/lib/instana/eum/eum-test.js.erb +0 -17
  83. data/lib/instana/eum/eum.js.erb +0 -17
  84. data/lib/instana/helpers.rb +0 -47
  85. data/lib/instana/opentracing/tracer.rb +0 -21
  86. data/lib/instana/thread_local.rb +0 -18
  87. data/lib/oj_check.rb +0 -19
  88. data/test/agent/agent_test.rb +0 -151
@@ -0,0 +1,88 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # Describes a Fargate container visible to the current process
7
+ # @since 1.197.0
8
+ class FargateContainer
9
+ ID = 'com.instana.plugin.aws.ecs.container'.freeze
10
+
11
+ def initialize(container, metadata_uri: ENV['ECS_CONTAINER_METADATA_URI'])
12
+ @container = container
13
+ @metadata_uri = URI(metadata_uri)
14
+ @client = Backend::RequestClient.new(@metadata_uri.host, @metadata_uri.port, use_ssl: @metadata_uri.scheme == "https")
15
+ end
16
+
17
+ def entity_id
18
+ "#{@container['Labels']['com.amazonaws.ecs.task-arn']}::#{@container['Name']}"
19
+ end
20
+
21
+ def data
22
+ payload = {
23
+ dockerId: @container['DockerId'],
24
+ dockerName: @container['DockerName'],
25
+ containerName: @container['Name'],
26
+ image: @container['Image'],
27
+ imageId: @container['ImageID'],
28
+ taskArn: @container['Labels']['com.amazonaws.ecs.task-arn'],
29
+ taskDefinition: @container['Labels']['com.amazonaws.ecs.task-definition-data.family'],
30
+ taskDefinitionVersion: @container['Labels']['com.amazonaws.ecs.task-definition-data.version'],
31
+ clusterArn: @container['Labels']['com.amazonaws.ecs.cluster'],
32
+ desiredStatus: @container['DesiredStatus'],
33
+ knownStatus: @container['KnownStatus'],
34
+ ports: @container['Ports'],
35
+ limits: {
36
+ cpu: @container['Limits']['CPU'],
37
+ memory: @container['Limits']['Memory']
38
+ },
39
+ createdAt: @container['CreatedAt'],
40
+ startedAt: @container['StartedAt']
41
+ }
42
+
43
+ if current_container?
44
+ payload[:instrumented] = true
45
+ payload[:runtime] = 'ruby'
46
+ end
47
+
48
+ payload
49
+ end
50
+
51
+ def snapshot
52
+ {
53
+ name: ID,
54
+ entityId: entity_id,
55
+ data: data
56
+ }
57
+ end
58
+
59
+ def source
60
+ return unless current_container?
61
+
62
+ {
63
+ hl: true,
64
+ cp: 'aws',
65
+ e: entity_id
66
+ }
67
+ end
68
+
69
+ private
70
+
71
+ def current_container?
72
+ return @current_container if @current_container
73
+
74
+ current_conatiner_response = current_conatiner
75
+ @current_container = @container['DockerName'] == current_conatiner_response['DockerName']
76
+ end
77
+
78
+ def current_conatiner
79
+ path = @metadata_uri.path
80
+ response = @client.send_request('GET', path)
81
+
82
+ raise "Unable to get `#{path}`. Got `#{response.code}`." unless response.ok?
83
+
84
+ response.json
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,67 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # Describes the current process in terms of its existence inside of a Fargate container
7
+ # @since 1.197.0
8
+ class FargateProcess
9
+ ID = 'com.instana.plugin.process'.freeze
10
+
11
+ def initialize(metadata_uri: ENV['ECS_CONTAINER_METADATA_URI'])
12
+ @metadata_uri = URI(metadata_uri)
13
+ @client = Backend::RequestClient.new(@metadata_uri.host, @metadata_uri.port, use_ssl: @metadata_uri.scheme == "https")
14
+ @start_time = Time.now
15
+ end
16
+
17
+ def entity_id
18
+ Process.pid.to_s
19
+ end
20
+
21
+ def data
22
+ proc_table = Sys::ProcTable.ps(pid: Process.pid)
23
+ process = Backend::ProcessInfo.new(proc_table)
24
+
25
+ {
26
+ pid: process.pid.to_i,
27
+ env: ENV.to_h,
28
+ exec: process.name,
29
+ args: process.arguments,
30
+ user: process.uid,
31
+ group: process.gid,
32
+ start: @start_time.to_i * 1000,
33
+ containerType: 'docker',
34
+ container: container_id,
35
+ "com.instana.plugin.host.name": task_id
36
+ }
37
+ end
38
+
39
+ def snapshot
40
+ {
41
+ name: ID,
42
+ entityId: entity_id,
43
+ data: data
44
+ }
45
+ end
46
+
47
+ private
48
+
49
+ def lookup(resource = nil)
50
+ path = resource ? @metadata_uri.path + resource : @metadata_uri.path
51
+ response = @client.send_request('GET', path)
52
+
53
+ raise "Unable to get `#{path}`. Got `#{response.code}`." unless response.ok?
54
+
55
+ response.json
56
+ end
57
+
58
+ def container_id
59
+ @container_id ||= lookup['DockerId']
60
+ end
61
+
62
+ def task_id
63
+ @task_id ||= lookup('/task')['TaskARN']
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,72 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # Describes the current process in terms of its existence inside of a Fargate task
7
+ # @since 1.197.0
8
+ class FargateTask
9
+ ID = 'com.instana.plugin.aws.ecs.task'.freeze
10
+
11
+ def initialize(metadata_uri: ENV['ECS_CONTAINER_METADATA_URI'])
12
+ @metadata_uri = URI(metadata_uri)
13
+ @client = Backend::RequestClient.new(@metadata_uri.host, @metadata_uri.port, use_ssl: @metadata_uri.scheme == "https")
14
+ end
15
+
16
+ def entity_id
17
+ task_metadata['TaskARN']
18
+ end
19
+ alias host_name entity_id
20
+
21
+ def data
22
+ {
23
+ taskArn: task_metadata['TaskARN'],
24
+ clusterArn: task_metadata['Cluster'],
25
+ taskDefinition: task_metadata['Family'],
26
+ taskDefinitionVersion: task_metadata['Revision'],
27
+ availabilityZone: task_metadata['AvailabilityZone'],
28
+ desiredStatus: task_metadata['DesiredStatus'],
29
+ knownStatus: task_metadata['KnownStatus'],
30
+ pullStartedAt: task_metadata['PullStartedAt'],
31
+ pullStoppedAt: task_metadata['PullStoppedAt'],
32
+ instanaZone: instana_zone,
33
+ tags: instana_tags
34
+ }.compact
35
+ end
36
+
37
+ def snapshot
38
+ {
39
+ name: ID,
40
+ entityId: entity_id,
41
+ data: data
42
+ }
43
+ end
44
+
45
+ private
46
+
47
+ def task_metadata
48
+ lookup('/task')
49
+ end
50
+
51
+ def instana_zone
52
+ ENV['INSTANA_ZONE']
53
+ end
54
+
55
+ def instana_tags
56
+ ENV.fetch('INSTANA_TAGS', '')
57
+ .split(/,/)
58
+ .map { |t| t.include?('=') ? t.split('=', 2) : [t, nil] }
59
+ .to_h
60
+ end
61
+
62
+ def lookup(resource)
63
+ path = @metadata_uri.path + resource
64
+ response = @client.send_request('GET', path)
65
+
66
+ raise "Unable to get `#{path}`. Got `#{response.code}`." unless response.ok?
67
+
68
+ response.json
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,36 @@
1
+ module Instana
2
+ module Backend
3
+ # @since 1.198.0
4
+ class LambdaFunction
5
+ ID = "com.instana.plugin.aws.lambda".freeze
6
+
7
+ def entity_id
8
+ Thread.current[:instana_function_arn]
9
+ end
10
+
11
+ def data
12
+ {}
13
+ end
14
+
15
+ def snapshot
16
+ {
17
+ name: ID,
18
+ entityId: entity_id,
19
+ data: data
20
+ }
21
+ end
22
+
23
+ def source
24
+ {
25
+
26
+ }
27
+ end
28
+
29
+ def host_name
30
+ entity_id
31
+ end
32
+
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # Describes the current Ruby process
7
+ # @since 1.197.0
8
+ class RubyProcess
9
+ ID = 'com.instana.plugin.ruby'.freeze
10
+
11
+ def initialize(pid: Process.pid)
12
+ @pid = pid
13
+ end
14
+
15
+ def entity_id
16
+ @pid.to_s
17
+ end
18
+
19
+ def data
20
+ metrics_data.merge(Util.take_snapshot)
21
+ end
22
+
23
+ def snapshot
24
+ {
25
+ name: ID,
26
+ entityId: entity_id,
27
+ data: data
28
+ }
29
+ end
30
+
31
+ private
32
+
33
+ def metrics_data
34
+ proc_table = Sys::ProcTable.ps(pid: Process.pid)
35
+ process = Backend::ProcessInfo.new(proc_table)
36
+
37
+ {
38
+ pid: @pid,
39
+ name: Util.get_app_name,
40
+ exec_args: process.arguments,
41
+ gc: Backend::GCSnapshot.instance.report,
42
+ thread: {count: ::Thread.list.count},
43
+ memory: {rss_size: proc_table.rss / 1024} # Bytes to Kilobytes
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,16 +1,11 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
- require "instana/thread_local"
5
4
  require "instana/tracing/span"
6
5
  require "instana/tracing/span_context"
7
6
 
8
7
  module Instana
9
8
  class Tracer
10
- extend ::Instana::ThreadLocal
11
-
12
- thread_local :current_span
13
-
14
9
  # Support ::Instana::Tracer.xxx call style for the instantiated tracer
15
10
  class << self
16
11
  def method_missing(method, *args, &block)
@@ -22,6 +17,22 @@ module Instana
22
17
  end
23
18
  end
24
19
 
20
+ def initialize(logger: Instana.logger)
21
+ @current_span = Concurrent::ThreadLocalVar.new
22
+ @logger = logger
23
+ end
24
+
25
+ # @return [Instana::Span, NilClass] the current active span or nil if we are not tracing
26
+ def current_span
27
+ @current_span.value
28
+ end
29
+
30
+ # @param [Instana::Span, NilClas] v the new current span
31
+ # Set the value of the current span
32
+ def current_span=(v)
33
+ @current_span.value = v
34
+ end
35
+
25
36
  #######################################
26
37
  # Tracing blocks API methods
27
38
  #######################################
@@ -85,7 +96,6 @@ module Instana
85
96
  #
86
97
  def log_start_or_continue(name, kvs = {}, incoming_context = nil)
87
98
  return if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
88
- ::Instana.logger.debug { "#{__method__} passed a block. Use `start_or_continue` instead!" } if block_given?
89
99
 
90
100
  # Handle the potential variations on `incoming_context`
91
101
  if incoming_context
@@ -125,11 +135,11 @@ module Instana
125
135
  def log_entry(name, kvs = nil, start_time = ::Instana::Util.now_in_ms, child_of = nil)
126
136
  return unless self.current_span || child_of
127
137
 
128
- if child_of && (child_of.is_a?(::Instana::Span) || child_of.is_a?(::Instana::SpanContext))
129
- new_span = Span.new(name, parent_ctx: child_of, start_time: start_time)
130
- else
131
- new_span = Span.new(name, parent_ctx: self.current_span, start_time: start_time)
132
- end
138
+ new_span = if child_of.is_a?(::Instana::Span) || child_of.is_a?(::Instana::SpanContext)
139
+ Span.new(name, parent_ctx: child_of, start_time: start_time)
140
+ else
141
+ Span.new(name, parent_ctx: self.current_span, start_time: start_time)
142
+ end
133
143
  new_span.set_tags(kvs) if kvs
134
144
  self.current_span = new_span
135
145
  end
@@ -163,10 +173,8 @@ module Instana
163
173
  def log_exit(name, kvs = {})
164
174
  return unless self.current_span
165
175
 
166
- if ENV.key?('INSTANA_DEBUG') || ENV.key?('INSTANA_TEST')
167
- unless self.current_span.name == name
168
- ::Instana.logger.debug "Span mismatch: Attempt to exit #{name} span but #{self.current_span.name} is active."
169
- end
176
+ if self.current_span.name != name
177
+ @logger.warn "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
170
178
  end
171
179
 
172
180
  self.current_span.set_tags(kvs)
@@ -191,10 +199,8 @@ module Instana
191
199
  def log_end(name, kvs = {}, end_time = ::Instana::Util.now_in_ms)
192
200
  return unless self.current_span
193
201
 
194
- if ENV.key?('INSTANA_DEBUG') || ENV.key?('INSTANA_TEST')
195
- unless self.current_span.name == name
196
- ::Instana.logger.debug "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
197
- end
202
+ if self.current_span.name != name
203
+ @logger.warn "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
198
204
  end
199
205
 
200
206
  self.current_span.set_tags(kvs)
@@ -252,88 +258,6 @@ module Instana
252
258
  span.close
253
259
  end
254
260
 
255
- ###########################################################################
256
- # OpenTracing Support
257
- ###########################################################################
258
-
259
- # Start a new span
260
- #
261
- # @param operation_name [String] The name of the operation represented by the span
262
- # @param child_of [Span] A span to be used as the ChildOf reference
263
- # @param start_time [Time] the start time of the span
264
- # @param tags [Hash] Starting tags for the span
265
- #
266
- # @return [Span]
267
- #
268
- def start_span(operation_name, child_of: nil, start_time: ::Instana::Util.now_in_ms, tags: nil)
269
- if child_of && (child_of.is_a?(::Instana::Span) || child_of.is_a?(::Instana::SpanContext))
270
- new_span = Span.new(operation_name, parent_ctx: child_of, start_time: start_time)
271
- else
272
- new_span = Span.new(operation_name, start_time: start_time)
273
- end
274
- new_span.set_tags(tags) if tags
275
- new_span
276
- end
277
-
278
- # Start a new span which is the child of the current span
279
- #
280
- # @param operation_name [String] The name of the operation represented by the span
281
- # @param child_of [Span] A span to be used as the ChildOf reference
282
- # @param start_time [Time] the start time of the span
283
- # @param tags [Hash] Starting tags for the span
284
- #
285
- # @return [Span]
286
- #
287
- def start_active_span(operation_name, child_of: self.current_span, start_time: ::Instana::Util.now_in_ms, tags: nil)
288
- self.current_span = start_span(operation_name, child_of: child_of, start_time: start_time, tags: tags)
289
- end
290
-
291
- # Returns the currently active span
292
- #
293
- # @return [Span]
294
- #
295
- def active_span
296
- self.current_span
297
- end
298
-
299
- # Inject a span into the given carrier
300
- #
301
- # @param span_context [SpanContext]
302
- # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
303
- # @param carrier [Carrier]
304
- #
305
- def inject(span_context, format, carrier)
306
- case format
307
- when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
308
- ::Instana.logger.debug 'Unsupported inject format'
309
- when OpenTracing::FORMAT_RACK
310
- carrier['X-Instana-T'] = ::Instana::Util.id_to_header(span_context.trace_id)
311
- carrier['X-Instana-S'] = ::Instana::Util.id_to_header(span_context.span_id)
312
- else
313
- ::Instana.logger.debug 'Unknown inject format'
314
- end
315
- end
316
-
317
- # Extract a span from a carrier
318
- #
319
- # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
320
- # @param carrier [Carrier]
321
- #
322
- # @return [SpanContext]
323
- #
324
- def extract(format, carrier)
325
- case format
326
- when OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY
327
- ::Instana.logger.debug 'Unsupported extract format'
328
- when OpenTracing::FORMAT_RACK
329
- ::Instana::SpanContext.new(::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_T']),
330
- ::Instana::Util.header_to_id(carrier['HTTP_X_INSTANA_S']))
331
- else
332
- ::Instana.logger.debug 'Unknown inject format'
333
- nil
334
- end
335
- end
336
-
337
261
  ###########################################################################
338
262
  # Helper methods
339
263
  ###########################################################################
@@ -374,48 +298,6 @@ module Instana
374
298
  self.current_span.context
375
299
  end
376
300
 
377
- # Take the current trace_id and convert it to a header compatible
378
- # format.
379
- #
380
- # @return [String] a hexadecimal representation of the current trace ID
381
- #
382
- def trace_id_header
383
- if self.current_span
384
- self.current_span.context.trace_id_header
385
- else
386
- ""
387
- end
388
- end
389
-
390
- # Take the current span_id and convert it to a header compatible
391
- # formate.
392
- #
393
- # @return [String] a hexadecimal representation of the current span ID
394
- #
395
- def span_id_header
396
- if self.current_span
397
- self.current_span.context.span_id_header
398
- else
399
- ""
400
- end
401
- end
402
-
403
- # Returns the trace ID for the active trace (if there is one),
404
- # otherwise nil.
405
- #
406
- def trace_id
407
- self.current_span ? self.current_span.id : nil
408
- ::Instana.logger.debug("tracer.trace_id will deprecated in a future version.")
409
- end
410
-
411
- # Returns the current [Span] ID for the active trace (if there is one),
412
- # otherwise nil.
413
- #
414
- def span_id
415
- self.current_span ? self.current_span.span_id : nil
416
- ::Instana.logger.debug("tracer.span_id will deprecated in a future version.")
417
- end
418
-
419
301
  # Used in the test suite, this resets the tracer to non-tracing state.
420
302
  #
421
303
  def clear!