instana 1.195.4 → 1.197.0.pre1

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 (82) 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 +57 -0
  10. data/lib/instana/backend/host_agent_activation_observer.rb +87 -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 +84 -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 +7 -21
  18. data/lib/instana/logger_delegator.rb +31 -0
  19. data/lib/instana/{opentracing → open_tracing}/carrier.rb +0 -0
  20. data/lib/instana/open_tracing/instana_tracer.rb +99 -0
  21. data/lib/instana/secrets.rb +6 -2
  22. data/lib/instana/setup.rb +20 -11
  23. data/lib/instana/snapshot/deltable.rb +25 -0
  24. data/lib/instana/snapshot/docker_container.rb +151 -0
  25. data/lib/instana/snapshot/fargate_container.rb +88 -0
  26. data/lib/instana/snapshot/fargate_process.rb +67 -0
  27. data/lib/instana/snapshot/fargate_task.rb +72 -0
  28. data/lib/instana/snapshot/ruby_process.rb +48 -0
  29. data/lib/instana/tracer.rb +25 -143
  30. data/lib/instana/tracing/processor.rb +4 -22
  31. data/lib/instana/tracing/span.rb +26 -35
  32. data/lib/instana/tracing/span_context.rb +1 -1
  33. data/lib/instana/util.rb +4 -67
  34. data/lib/instana/version.rb +1 -1
  35. data/lib/opentracing.rb +26 -3
  36. data/test/backend/agent_test.rb +54 -0
  37. data/test/backend/gc_snapshot_test.rb +11 -0
  38. data/test/backend/host_agent_activation_observer_test.rb +65 -0
  39. data/test/backend/host_agent_lookup_test.rb +78 -0
  40. data/test/backend/host_agent_reporting_observer_test.rb +192 -0
  41. data/test/backend/host_agent_test.rb +32 -0
  42. data/test/backend/process_info_test.rb +63 -0
  43. data/test/backend/request_client_test.rb +61 -0
  44. data/test/backend/serverless_agent_test.rb +73 -0
  45. data/test/config_test.rb +10 -0
  46. data/test/instana_test.rb +11 -4
  47. data/test/instrumentation/rack_instrumented_request_test.rb +3 -2
  48. data/test/instrumentation/rack_test.rb +2 -14
  49. data/test/secrets_test.rb +41 -22
  50. data/test/snapshot/deltable_test.rb +17 -0
  51. data/test/snapshot/docker_container_test.rb +82 -0
  52. data/test/snapshot/fargate_container_test.rb +82 -0
  53. data/test/snapshot/fargate_process_test.rb +35 -0
  54. data/test/snapshot/fargate_task_test.rb +49 -0
  55. data/test/snapshot/ruby_process_test.rb +14 -0
  56. data/test/support/mock_timer.rb +20 -0
  57. data/test/test_helper.rb +15 -3
  58. data/test/tracing/custom_test.rb +1 -3
  59. data/test/tracing/id_management_test.rb +4 -0
  60. data/test/tracing/opentracing_test.rb +15 -2
  61. data/test/tracing/processor_test.rb +58 -0
  62. data/test/tracing/span_context_test.rb +22 -0
  63. data/test/tracing/span_test.rb +127 -0
  64. data/test/tracing/tracer_async_test.rb +29 -0
  65. data/test/tracing/tracer_test.rb +82 -16
  66. data/test/util_test.rb +10 -0
  67. metadata +72 -45
  68. data/lib/instana/agent.rb +0 -508
  69. data/lib/instana/agent/helpers.rb +0 -87
  70. data/lib/instana/agent/hooks.rb +0 -44
  71. data/lib/instana/agent/tasks.rb +0 -51
  72. data/lib/instana/collector.rb +0 -119
  73. data/lib/instana/collectors/gc.rb +0 -60
  74. data/lib/instana/collectors/memory.rb +0 -37
  75. data/lib/instana/collectors/thread.rb +0 -33
  76. data/lib/instana/eum/eum-test.js.erb +0 -17
  77. data/lib/instana/eum/eum.js.erb +0 -17
  78. data/lib/instana/helpers.rb +0 -47
  79. data/lib/instana/opentracing/tracer.rb +0 -21
  80. data/lib/instana/thread_local.rb +0 -18
  81. data/lib/oj_check.rb +0 -19
  82. data/test/agent/agent_test.rb +0 -151
@@ -6,6 +6,10 @@ require 'cgi'
6
6
 
7
7
  module Instana
8
8
  class Secrets
9
+ def initialize(logger: ::Instana.logger)
10
+ @logger = logger
11
+ end
12
+
9
13
  def remove_from_query(str, secret_values = Instana.agent.secret_values)
10
14
  return str unless secret_values
11
15
 
@@ -37,8 +41,8 @@ module Instana
37
41
  when 'regex'
38
42
  ->(expected, actual) { !Regexp.new(expected).match(actual).nil? }
39
43
  else
40
- ::Instana.logger.warn("Matcher #{name} is not supported.")
41
- lambda { false }
44
+ @logger.warn("Matcher #{name} is not supported.")
45
+ ->(_e, _a) { false }
42
46
  end
43
47
  end
44
48
  end
data/lib/instana/setup.rb CHANGED
@@ -1,30 +1,39 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
- require 'oj_check'
4
+ require 'instana/logger_delegator'
5
5
 
6
6
  require "instana/base"
7
7
  require "instana/config"
8
- require "instana/agent"
9
- require "instana/collector"
10
8
  require "instana/secrets"
11
9
  require "instana/tracer"
12
10
  require "instana/tracing/processor"
13
11
 
14
12
  require 'instana/activator'
15
13
 
14
+ require 'instana/backend/request_client'
15
+ require 'instana/backend/gc_snapshot'
16
+ require 'instana/backend/process_info'
17
+
18
+ require 'instana/snapshot/deltable'
19
+ require 'instana/snapshot/ruby_process'
20
+ require 'instana/snapshot/fargate_process'
21
+ require 'instana/snapshot/fargate_task'
22
+ require 'instana/snapshot/fargate_container'
23
+ require 'instana/snapshot/docker_container'
24
+
25
+ require 'instana/backend/host_agent_lookup'
26
+ require 'instana/backend/host_agent_activation_observer'
27
+ require 'instana/backend/host_agent_reporting_observer'
28
+
29
+ require 'instana/backend/host_agent'
30
+ require 'instana/backend/serverless_agent'
31
+ require 'instana/backend/agent'
32
+
16
33
  ::Instana.setup
17
34
  ::Instana.agent.setup
18
35
  ::Instana::Activator.start
19
36
 
20
- # Register the metric collectors
21
- unless RUBY_PLATFORM == 'java'.freeze
22
- require 'instana/collectors/gc'
23
- end
24
-
25
- require 'instana/collectors/memory'
26
- require 'instana/collectors/thread'
27
-
28
37
  # Require supported OpenTracing interfaces
29
38
  require "opentracing"
30
39
 
@@ -0,0 +1,25 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # @since 1.197.0
7
+ module Deltable
8
+ def delta(key, *rest, compute:, obj:, path: [key, *rest])
9
+ val = obj[key]
10
+ return val if val == nil
11
+
12
+ if rest.empty?
13
+ @__delta ||= Hash.new(0)
14
+ cache_key = path.join('.')
15
+ old = @__delta[cache_key]
16
+ @__delta[cache_key] = val
17
+
18
+ return compute.call(old, val)
19
+ end
20
+
21
+ delta(*rest, compute: compute, obj: val, path: path)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,151 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Snapshot
6
+ # Describes a Docker container visible to the current process
7
+ # @since 1.197.0
8
+ class DockerContainer
9
+ include Deltable
10
+ ID = 'com.instana.plugin.docker'.freeze
11
+
12
+ def initialize(container, metadata_uri: ENV['ECS_CONTAINER_METADATA_URI'])
13
+ @container = container
14
+ @metadata_uri = URI(metadata_uri)
15
+ @client = Backend::RequestClient.new(@metadata_uri.host, @metadata_uri.port, use_ssl: @metadata_uri.scheme == "https")
16
+ end
17
+
18
+ def entity_id
19
+ "#{@container['Labels']['com.amazonaws.ecs.task-arn']}::#{@container['Name']}"
20
+ end
21
+
22
+ def data
23
+ metrics = lookup('/task/stats').fetch(@container['DockerId'], {})
24
+
25
+ container_metrics(metrics)
26
+ .merge(container_metadata)
27
+ end
28
+
29
+ def snapshot
30
+ {
31
+ name: ID,
32
+ entityId: entity_id,
33
+ data: data
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ def container_metadata
40
+ {
41
+ Id: @container['DockerId'],
42
+ Created: @container['CreatedAt'],
43
+ Started: @container['StartedAt'],
44
+ Image: @container['Image'],
45
+ Labels: @container['Labels'],
46
+ Ports: @container['Ports'],
47
+ NetworkMode: @container['Networks'].first['NetworkMode']
48
+ }
49
+ end
50
+
51
+ def container_metrics(metrics)
52
+ return {} if metrics.empty?
53
+
54
+ {
55
+ memory: memory_stats(metrics),
56
+ blkio: blkio_stats(metrics),
57
+ cpu: cpu_stats(metrics),
58
+ network: network_stats(metrics)
59
+ }.compact
60
+ end
61
+
62
+ def memory_stats(metrics)
63
+ identity = ->(_old, new) { new }
64
+
65
+ {
66
+ active_anon: delta('memory_stats', 'stats', 'active_anon', compute: identity, obj: metrics),
67
+ active_file: delta('memory_stats', 'stats', 'active_file', compute: identity, obj: metrics),
68
+ inactive_anon: delta('memory_stats', 'stats', 'inactive_anon', compute: identity, obj: metrics),
69
+ inactive_file: delta('memory_stats', 'stats', 'inactive_file', compute: identity, obj: metrics),
70
+ total_cache: delta('memory_stats', 'stats', 'total_cache', compute: identity, obj: metrics),
71
+ total_rss: delta('memory_stats', 'stats', 'total_rss', compute: identity, obj: metrics),
72
+ usage: delta('memory_stats', 'usage', compute: identity, obj: metrics),
73
+ max_usage: delta('memory_stats', 'max_usage', compute: identity, obj: metrics),
74
+ limit: delta('memory_stats', 'limit', compute: identity, obj: metrics)
75
+ }
76
+ end
77
+
78
+ def blkio_stats(metrics)
79
+ delta = ->(old, new) { new - old }
80
+ bytes = {
81
+ 'block_bytes' => metrics['blkio_stats']['io_service_bytes_recursive'].map { |r| [r['op'], r['value']] }.to_h
82
+ }
83
+
84
+ {
85
+ blk_read: delta('block_bytes', 'Read', compute: delta, obj: bytes),
86
+ blk_write: delta('block_bytes', 'Write', compute: delta, obj: bytes)
87
+ }
88
+ end
89
+
90
+ def cpu_stats(metrics)
91
+ delta = ->(old, new) { new - old }
92
+ identity = ->(_old, new) { new }
93
+
94
+ cpu_system_delta = delta('cpu_stats', 'system_cpu_usage', compute: delta, obj: metrics).to_f
95
+ online_cpus = delta('cpu_stats', 'online_cpus', compute: identity, obj: metrics) || 1
96
+
97
+ {
98
+ total_usage: (delta('cpu_stats', 'cpu_usage', 'total_usage', compute: delta, obj: metrics) / cpu_system_delta) * online_cpus,
99
+ user_usage: (delta('cpu_stats', 'cpu_usage', 'usage_in_usermode', compute: delta, obj: metrics) / cpu_system_delta) * online_cpus,
100
+ system_usage: (delta('cpu_stats', 'cpu_usage', 'usage_in_kernelmode', compute: delta, obj: metrics) / cpu_system_delta) * online_cpus,
101
+ throttling_count: delta('cpu_stats', 'throttling_data', 'periods', compute: delta, obj: metrics),
102
+ throttling_time: delta('cpu_stats', 'throttling_data', 'throttled_time', compute: delta, obj: metrics)
103
+ }
104
+ end
105
+
106
+ def network_stats(metrics)
107
+ delta = ->(old, new) { new - old }
108
+ return nil unless metrics['networks']
109
+
110
+ interfaces = metrics['networks'].keys
111
+ payload = {
112
+ rx: {
113
+ bytes: 0,
114
+ dropped: 0,
115
+ errors: 0,
116
+ packet: 0
117
+ },
118
+ tx: {
119
+ bytes: 0,
120
+ dropped: 0,
121
+ errors: 0,
122
+ packet: 0
123
+ }
124
+ }
125
+
126
+ interfaces.each do |interface|
127
+ payload[:rx][:bytes] += delta('networks', interface, 'rx_bytes', compute: delta, obj: metrics)
128
+ payload[:rx][:dropped] += delta('networks', interface, 'rx_dropped', compute: delta, obj: metrics)
129
+ payload[:rx][:errors] += delta('networks', interface, 'rx_errors', compute: delta, obj: metrics)
130
+ payload[:rx][:packet] += delta('networks', interface, 'rx_packets', compute: delta, obj: metrics)
131
+
132
+ payload[:tx][:bytes] += delta('networks', interface, 'tx_bytes', compute: delta, obj: metrics)
133
+ payload[:tx][:dropped] += delta('networks', interface, 'tx_packets', compute: delta, obj: metrics)
134
+ payload[:tx][:errors] += delta('networks', interface, 'tx_errors', compute: delta, obj: metrics)
135
+ payload[:tx][:packet] += delta('networks', interface, 'tx_dropped', compute: delta, obj: metrics)
136
+ end
137
+
138
+ payload
139
+ end
140
+
141
+ def lookup(resource)
142
+ path = @metadata_uri.path + resource
143
+ response = @client.send_request('GET', path)
144
+
145
+ raise "Unable to get `#{path}`. Got `#{response.code}`." unless response.ok?
146
+
147
+ response.json
148
+ end
149
+ end
150
+ end
151
+ end
@@ -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