instana 1.195.2 → 1.197.0

Sign up to get free protection for your applications and to get access to all the features.
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!