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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0068c5ce2a6bf7c75d517562cec424a612a31d8d938fabb7651151f52b3cc5ea'
4
- data.tar.gz: cffa225ebc37b1a19a6a20d2418af57cd6e559a3635df17b5244bc2d603eaa20
3
+ metadata.gz: 58219b994af0387dcc4c672577b19c9570e487998be17d315a92902d6e1d86e6
4
+ data.tar.gz: 60e586b644f60545ebe6c7690d3ba673354d2133937b3b2bf95db04fbe8f58c4
5
5
  SHA512:
6
- metadata.gz: '0991b7a36fe13c5e4b8ebf93647f3a933087c0f92b8e94e2a3b4a8f7c8bcc24712560f4caf550328bc5390a51f59c334483e48b8be4b78236164b2d557608625'
7
- data.tar.gz: bd5ab3d0ba9f0d80a5b7c86068afb04f3889321fa5a154e43e97f89f577e244e481e0b2208a3fb76ae04452b26bcd32657ca2ea9cd6133230a7e53a8904fc52f
6
+ metadata.gz: 4d4ca8c71a1613c05e5f1fec02e5857c544013f0043d4b95e31fc900b81903ba5f3c08abd075afc4643e7761cd54a7595939ad9149575589b44b8e43722ea89a
7
+ data.tar.gz: 737447ad9f8ed3c6aef72bead3e66128b83ac1d346bc35f00ad1bd3e0b485f4cd8080faabf8817da23a788f229d32db1739e98484637fd8e70b852b415447d97
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ inherit_from: .rubocop_todo.yml
2
2
 
3
3
  require:
4
4
  - ./extras/license_header.rb
5
-
5
+
6
6
  # Remove when we remove .rubocop_todo.yml
7
7
  AllCops:
8
8
  NewCops: disable
@@ -18,4 +18,8 @@ Style/NilComparison:
18
18
  Enabled: false
19
19
 
20
20
  Style/SoleNestedConditional:
21
- Enabled: false
21
+ Enabled: false
22
+
23
+ # Ruby 2.1 compatibility
24
+ Style/SafeNavigation:
25
+ Enabled: false
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ Rake::TestTask.new(:test) do |t|
22
22
  else
23
23
  t.test_files = Dir[
24
24
  'test/*_test.rb',
25
- 'test/{agent,tracing}/*_test.rb'
25
+ 'test/{agent,tracing,backend,snapshot}/*_test.rb'
26
26
  ]
27
27
  end
28
28
  end
data/instana.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  }
26
26
 
27
27
  spec.licenses = ['MIT']
28
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test)/}) }
29
29
  spec.bindir = "exe"
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
@@ -38,13 +38,9 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "rake", "~> 10.0"
39
39
  spec.add_development_dependency "minitest", "~> 5.0"
40
40
  spec.add_development_dependency "appraisal"
41
+ spec.add_development_dependency "fakefs"
41
42
 
43
+ spec.add_runtime_dependency('concurrent-ruby', '>= 1.1')
42
44
  spec.add_runtime_dependency('sys-proctable', '>= 1.2.2')
43
- spec.add_runtime_dependency('get_process_mem', '>= 0.2.1')
44
- spec.add_runtime_dependency('timers', '>= 4.0.4')
45
45
  spec.add_runtime_dependency('oj', '>=3.0.11') unless RUBY_PLATFORM =~ /java/i
46
-
47
- # Indirect dependency
48
- # https://github.com/instana/ruby-sensor/issues/10
49
- spec.add_runtime_dependency('ffi', '>=1.0.11')
50
46
  end
data/lib/instana.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
+ require 'concurrent'
5
+ require 'sys-proctable'
6
+
4
7
  require "instana/setup"
5
8
 
6
9
  # Boot the instana agent background thread. If you wish to have greater
@@ -7,12 +7,14 @@ module Instana
7
7
  attr_reader :trace_point, :activators
8
8
 
9
9
  def start
10
+ # :nocov:
10
11
  @trace_point = TracePoint.new(:end) do
11
12
  activated = ::Instana::Activator.call
12
13
  ::Instana.logger.debug { "Activated #{activated.join(', ')}" } unless activated.empty?
13
14
  end
14
15
 
15
16
  @trace_point.enable if enabled?
17
+ # :nocov:
16
18
  end
17
19
 
18
20
  def call
@@ -0,0 +1,60 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # Wrapper class around the various transport backends
7
+ # @since 1.197.0
8
+ class Agent
9
+ attr_reader :delegate
10
+
11
+ def initialize(fargate_metadata_uri: ENV['ECS_CONTAINER_METADATA_URI'], logger: ::Instana.logger)
12
+ @delegate = nil
13
+ @logger = logger
14
+ @fargate_metadata_uri = fargate_metadata_uri
15
+ end
16
+
17
+ def setup
18
+ @delegate = if @fargate_metadata_uri && ENV.key?('INSTANA_ENDPOINT_URL')
19
+ ServerlessAgent.new(fargate_snapshots)
20
+ else
21
+ HostAgent.new
22
+ end
23
+
24
+ @delegate.setup
25
+ end
26
+
27
+ def method_missing(mth, *args, &block)
28
+ if @delegate.respond_to?(mth)
29
+ @delegate.public_send(mth, *args, &block)
30
+ else
31
+ super(mth, *args, &block)
32
+ end
33
+ end
34
+
35
+ def respond_to_missing?(mth, include_all = false)
36
+ @delegate.respond_to?(mth, include_all)
37
+ end
38
+
39
+ private
40
+
41
+ def fargate_snapshots
42
+ metadata_uri = URI(@fargate_metadata_uri)
43
+ client = Backend::RequestClient.new(metadata_uri.host, metadata_uri.port, use_ssl: metadata_uri.scheme == "https")
44
+ response = client.send_request('GET', "#{metadata_uri.path}/task")
45
+
46
+ if response.ok?
47
+ docker = response
48
+ .json['Containers']
49
+ .map { |c| [Snapshot::DockerContainer.new(c), Snapshot::FargateContainer.new(c)] }
50
+ .flatten
51
+
52
+ docker + [Snapshot::FargateProcess.new, Snapshot::RubyProcess.new, Snapshot::FargateTask.new]
53
+ else
54
+ @logger.warn("Received #{response.code} when requesting containers.")
55
+ []
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'singleton'
5
+
6
+ module Instana
7
+ module Backend
8
+ # Keeps track of garbage collector related metrics
9
+ # @since 1.197.0
10
+ class GCSnapshot
11
+ include Singleton
12
+
13
+ def initialize
14
+ ::GC::Profiler.enable
15
+
16
+ @last_major_count = 0
17
+ @last_minor_count = 0
18
+ end
19
+
20
+ def report
21
+ stats = ::GC.stat
22
+ total_time = ::GC::Profiler.total_time * 1000
23
+
24
+ ::GC::Profiler.clear
25
+
26
+ payload = {
27
+ totalTime: total_time,
28
+ heap_live: stats[:heap_live_slots] || stats[:heap_live_num],
29
+ heap_free: stats[:heap_free_slots] || stats[:heap_free_num],
30
+ minorGcs: stats[:minor_gc_count] - @last_minor_count,
31
+ majorGcs: stats[:major_gc_count] - @last_major_count
32
+ }
33
+
34
+ @last_major_count = stats[:major_gc_count]
35
+ @last_minor_count = stats[:minor_gc_count]
36
+
37
+ payload
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # @since 1.197.0
7
+ class HostAgent
8
+ def initialize(discovery: Concurrent::Atom.new(nil))
9
+ @discovery = discovery
10
+ @client = nil
11
+ end
12
+
13
+ def setup
14
+ return if ENV.key?('INSTANA_TEST')
15
+
16
+ @client = HostAgentLookup.new.call
17
+ @discovery
18
+ .with_observer(HostAgentActivationObserver.new(@client, @discovery))
19
+ .with_observer(HostAgentReportingObserver.new(@client, @discovery))
20
+ end
21
+
22
+ def spawn_background_thread
23
+ @discovery.swap { nil }
24
+ end
25
+
26
+ # @return [Boolean] true if the agent able to send spans to the backend
27
+ def ready?
28
+ ENV.key?('INSTANA_TEST') || !@discovery.value.nil?
29
+ end
30
+
31
+ # @return [Hash, NilClass] the backend friendly description of the current in process collector
32
+ def source
33
+ {
34
+ e: discovery_value['pid'],
35
+ h: discovery_value['agentUuid']
36
+ }.compact
37
+ end
38
+
39
+ # @return [Array] extra headers to include in the trace
40
+ def extra_headers
41
+ discovery_value['extraHeaders']
42
+ end
43
+
44
+ # @return [Hash] values which are removed from urls sent to the backend
45
+ def secret_values
46
+ discovery_value['secrets']
47
+ end
48
+
49
+ private
50
+
51
+ def discovery_value
52
+ v = @discovery.value
53
+ v || {}
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,87 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # Process which is responsible for initiating monitoring of a Ruby program with a local agent.
7
+ # @since 1.197.0
8
+ class HostAgentActivationObserver
9
+ DISCOVERY_URL = '/com.instana.plugin.ruby.discovery'.freeze
10
+ ENTITY_DATA_URL = '/com.instana.plugin.ruby.%i'.freeze
11
+ class DiscoveryError < StandardError; end
12
+
13
+ # @param [RequestClient] client used to make requests to the backend
14
+ # @param [Concurrent::Atom] discovery object used to store discovery response in
15
+ def initialize(client, discovery, wait_time: 60, logger: ::Instana.logger, max_wait_tries: 60, proc_table: Sys::ProcTable) # rubocop:disable Metrics/ParameterLists
16
+ @client = client
17
+ @discovery = discovery
18
+ @wait_time = wait_time
19
+ @logger = logger
20
+ @max_wait_tries = max_wait_tries
21
+ @proc_table = proc_table
22
+ end
23
+
24
+ def update(_time, _old_version, new_version)
25
+ return unless new_version.nil?
26
+
27
+ try_forever_with_backoff do
28
+ payload = discovery_payload
29
+ discovery_response = @client.send_request('PUT', DISCOVERY_URL, payload)
30
+
31
+ raise DiscoveryError, "Discovery response was #{discovery_response.code} with `#{payload}`." unless discovery_response.ok?
32
+
33
+ discovery = discovery_response.json
34
+ @logger.debug("Discovery complete (`#{discovery}`). Waiting for agent.")
35
+ wait_for_backend(discovery['pid'])
36
+ @logger.debug("Agent ready.")
37
+ @discovery.swap { discovery }
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def discovery_payload
44
+ proc_table = @proc_table.ps(pid: Process.pid)
45
+ process = ProcessInfo.new(proc_table)
46
+
47
+ payload = {
48
+ name: process.name,
49
+ args: process.arguments,
50
+ pid: process.parent_pid,
51
+ pidFromParentNS: process.from_parent_namespace,
52
+ cpuSetFileContent: process.cpuset
53
+ }
54
+
55
+ if @client.fileno && @client.inode
56
+ payload[:fd] = @client.fileno
57
+ payload[:inode] = @client.inode
58
+ end
59
+
60
+ payload.compact
61
+ end
62
+
63
+ def wait_for_backend(pid)
64
+ response = @max_wait_tries.times do
65
+ path = format(ENTITY_DATA_URL, pid)
66
+ wait_response = @client.send_request('HEAD', path)
67
+
68
+ break(wait_response) if wait_response.ok?
69
+
70
+ sleep(1)
71
+ end
72
+
73
+ raise DiscoveryError, "The backend didn't respond in time." unless response.is_a?(RequestClient::Response) && response.ok?
74
+ end
75
+
76
+ def try_forever_with_backoff
77
+ yield
78
+ rescue DiscoveryError, Net::OpenTimeout => e
79
+ @logger.error(e)
80
+ sleep(@wait_time)
81
+ retry
82
+ rescue StandardError => e
83
+ @logger.error(%(#{e}\n#{e.backtrace.join("\n")}))
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,57 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'csv'
5
+
6
+ module Instana
7
+ module Backend
8
+ # Utility class to discover the agent that a given instance of the collector
9
+ # needs to communicate with.
10
+ # @since 1.197.0
11
+ class HostAgentLookup
12
+ def initialize(host = ::Instana.config[:agent_host], port = ::Instana.config[:agent_port], destination: '00000000')
13
+ @host = host
14
+ @port = port
15
+ @destination = destination
16
+ end
17
+
18
+ # @return [RequestClient, NilClass] the request client to use to communicate with the agent or nil if no agent could be found
19
+ def call
20
+ host_listening?(@host, @port) || host_listening?(default_gateway, @port)
21
+ end
22
+
23
+ private
24
+
25
+ # @return [RequestClient, nil] the request client if it responds to '/' with a success
26
+ def host_listening?(host, port)
27
+ client = RequestClient.new(host, port)
28
+ client.send_request('GET', '/').ok? ? client : nil
29
+ rescue Net::OpenTimeout, Errno::ECONNREFUSED => _e
30
+ nil
31
+ end
32
+
33
+ # @return [String] the default gateway to attempt to connect to or the @host if a default gateway can not be identified
34
+ def default_gateway
35
+ return @host unless File.exist?('/proc/self/net/route')
36
+
37
+ routes = CSV.read(
38
+ '/proc/self/net/route',
39
+ headers: :first_row,
40
+ col_sep: "\t",
41
+ header_converters: [->(v) { v.strip }],
42
+ converters: [->(v) { v.strip }]
43
+ )
44
+
45
+ route = routes.detect { |r| r['Destination'] == @destination }
46
+ return @host unless route
47
+
48
+ route['Gateway']
49
+ .split(/([0-9A-Z]{2})/)
50
+ .reject(&:empty?)
51
+ .reverse
52
+ .map { |s| s.to_i(16) }
53
+ .join('.')
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,106 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Backend
6
+ # Process which is responsible for reporting metrics and tracing to the local agent
7
+ # @since 1.197.0
8
+ class HostAgentReportingObserver
9
+ ENTITY_DATA_URL = '/com.instana.plugin.ruby.%i'.freeze
10
+ RESPONSE_DATA_URL = '/com.instana.plugin.ruby/response.%i?messageId=%s'.freeze
11
+ TRACES_DATA_URL = "/com.instana.plugin.ruby/traces.%i".freeze
12
+
13
+ attr_reader :report_timer
14
+
15
+ # @param [RequestClient] client used to make requests to the backend
16
+ # @param [Concurrent::Atom] discovery object used to store discovery response in
17
+ def initialize(client, discovery, logger: ::Instana.logger, timer_class: Concurrent::TimerTask, processor: ::Instana.processor)
18
+ @client = client
19
+ @discovery = discovery
20
+ @logger = logger
21
+ @report_timer = timer_class.new(execution_interval: 1, run_now: true) { report_to_backend }
22
+ @nonce = Time.now
23
+ @processor = processor
24
+ end
25
+
26
+ def update(time, _old_version, new_version)
27
+ return unless time > @nonce
28
+
29
+ @nonce = time
30
+ new_version.nil? ? @report_timer.shutdown : @report_timer.execute
31
+ end
32
+
33
+ private
34
+
35
+ def report_to_backend
36
+ report_metrics if ::Instana.config[:metrics][:enabled]
37
+ report_traces if ::Instana.config[:tracing][:enabled]
38
+ rescue StandardError => e
39
+ @logger.error(%(#{e}\n#{e.backtrace.join("\n")}))
40
+ end
41
+
42
+ def report_traces
43
+ discovery = @discovery.value
44
+ return unless discovery
45
+
46
+ path = format(TRACES_DATA_URL, discovery['pid'])
47
+
48
+ @processor.send do |spans|
49
+ response = @client.send_request('POST', path, spans)
50
+
51
+ unless response.ok?
52
+ @discovery.swap { nil }
53
+ break
54
+ end
55
+
56
+ @logger.debug("Sent `#{spans.count}` spans to `#{path}` and got `#{response.code}`.")
57
+ end
58
+ end
59
+
60
+ def report_metrics
61
+ discovery = @discovery.value
62
+ return unless discovery
63
+
64
+ path = format(ENTITY_DATA_URL, discovery['pid'])
65
+ payload = metrics_payload(discovery).merge(Util.take_snapshot)
66
+ response = @client.send_request('POST', path, payload)
67
+
68
+ if response.ok?
69
+ handle_agent_tasks(response, discovery) unless response.body.empty?
70
+ else
71
+ @discovery.swap { nil }
72
+ end
73
+
74
+ @logger.debug("Sent `#{payload}` to `#{path}` and got `#{response.code}`.")
75
+ end
76
+
77
+ def handle_agent_tasks(response, discovery)
78
+ payload = response.json
79
+ payload = [payload] if payload.is_a?(Hash)
80
+ payload
81
+ .select { |t| t['action'] == 'ruby.source' }
82
+ .each do |action|
83
+ payload = ::Instana::Util.get_rb_source(action['args']['file'])
84
+ path = format(RESPONSE_DATA_URL, discovery['pid'], action['messageId'])
85
+ @client.send_request('POST', path, payload)
86
+ end
87
+ rescue StandardError => e
88
+ @logger.debug("Error processing agent task #{e.inspect}")
89
+ end
90
+
91
+ def metrics_payload(discovery)
92
+ proc_table = Sys::ProcTable.ps(pid: Process.pid)
93
+ process = ProcessInfo.new(proc_table)
94
+
95
+ {
96
+ pid: discovery['pid'],
97
+ name: Util.get_app_name,
98
+ exec_args: process.arguments,
99
+ gc: GCSnapshot.instance.report,
100
+ thread: {count: ::Thread.list.count},
101
+ memory: {rss_size: proc_table.rss / 1024} # Bytes to Kilobytes
102
+ }
103
+ end
104
+ end
105
+ end
106
+ end