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
@@ -198,4 +198,33 @@ class TracerAsyncTest < Minitest::Test
198
198
  assert_equal 3, fourth_span[:data][:sdk][:custom][:tags][:entry_kv]
199
199
  assert_equal 3, fourth_span[:data][:sdk][:custom][:tags][:exit_kv]
200
200
  end
201
+
202
+ def test_async_helpers
203
+ clear_all!
204
+ ::Instana.tracer.log_start_or_continue(:rack)
205
+
206
+ span = ::Instana.tracer.log_async_entry(:async, {})
207
+ ::Instana.tracer.log_async_info({a: 1}, span)
208
+ ::Instana.tracer.log_async_error(StandardError.new('Error'), span)
209
+ ::Instana.tracer.log_async_exit(nil, {}, span)
210
+
211
+ spans = ::Instana.processor.queued_spans
212
+ span, = spans
213
+
214
+ assert_equal({a: 1}, span[:data][:sdk][:custom][:tags])
215
+ assert_equal(1, span[:ec])
216
+ end
217
+
218
+ def test_async_helpers_tag_exit
219
+ clear_all!
220
+ ::Instana.tracer.log_start_or_continue(:rack)
221
+
222
+ span = ::Instana.tracer.log_async_entry(:async, {})
223
+ ::Instana.tracer.log_async_exit(nil, {a: 1}, span)
224
+
225
+ spans = ::Instana.processor.queued_spans
226
+ span, = spans
227
+
228
+ assert_equal({a: 1}, span[:data][:sdk][:custom][:tags])
229
+ end
201
230
  end
@@ -22,7 +22,6 @@ class TracerTest < Minitest::Test
22
22
  ::Instana.config[:tracing][:enabled] = true
23
23
  end
24
24
 
25
-
26
25
  def test_basic_trace_block
27
26
  clear_all!
28
27
 
@@ -44,9 +43,7 @@ class TracerTest < Minitest::Test
44
43
  assert first_span.key?(:data)
45
44
  assert_equal 1, first_span[:data][:one]
46
45
  assert first_span.key?(:f)
47
- assert first_span[:f].key?(:e)
48
- assert first_span[:f].key?(:h)
49
- assert_equal ::Instana.agent.agent_uuid, first_span[:f][:h]
46
+ assert_equal ::Instana.agent.source, first_span[:f]
50
47
  end
51
48
 
52
49
  def test_exotic_tag_types
@@ -75,9 +72,7 @@ class TracerTest < Minitest::Test
75
72
  assert first_span[:data].key?(:ipaddr)
76
73
  assert first_span[:data][:ipaddr].is_a?(String)
77
74
  assert first_span.key?(:f)
78
- assert first_span[:f].key?(:e)
79
- assert first_span[:f].key?(:h)
80
- assert_equal ::Instana.agent.agent_uuid, first_span[:f][:h]
75
+ assert_equal ::Instana.agent.source, first_span[:f]
81
76
  end
82
77
 
83
78
  def test_errors_are_properly_propagated
@@ -105,9 +100,7 @@ class TracerTest < Minitest::Test
105
100
  assert first_span.key?(:data)
106
101
  assert_equal 1, first_span[:data][:one]
107
102
  assert first_span.key?(:f)
108
- assert first_span[:f].key?(:e)
109
- assert first_span[:f].key?(:h)
110
- assert_equal ::Instana.agent.agent_uuid, first_span[:f][:h]
103
+ assert_equal ::Instana.agent.source, first_span[:f]
111
104
  assert_equal first_span[:error], true
112
105
  assert_equal first_span[:ec], 1
113
106
  end
@@ -222,9 +215,7 @@ class TracerTest < Minitest::Test
222
215
  assert_equal rack_span[:data][:close_one], 1
223
216
 
224
217
  assert rack_span.key?(:f)
225
- assert rack_span[:f].key?(:e)
226
- assert rack_span[:f].key?(:h)
227
- assert_equal ::Instana.agent.agent_uuid, rack_span[:f][:h]
218
+ assert_equal ::Instana.agent.source, rack_span[:f]
228
219
 
229
220
  assert_equal sdk_span[:n], :sdk
230
221
  assert_equal sdk_span[:data][:sdk][:name], :sub_task
@@ -239,7 +230,9 @@ class TracerTest < Minitest::Test
239
230
  exception_raised = false
240
231
  begin
241
232
  ::Instana.tracer.start_or_continue_trace(:test_trace, {:one => 1}) do
242
- raise Exception.new("Block exception test error")
233
+ ::Instana.tracer.trace(:test_trace_two) do
234
+ raise Exception.new("Block exception test error")
235
+ end
243
236
  end
244
237
  rescue Exception
245
238
  exception_raised = true
@@ -248,9 +241,9 @@ class TracerTest < Minitest::Test
248
241
  assert exception_raised
249
242
 
250
243
  spans = ::Instana.processor.queued_spans
251
- assert_equal 1, spans.length
244
+ assert_equal 2, spans.length
252
245
 
253
- sdk_span = spans[0]
246
+ sdk_span = spans.last
254
247
 
255
248
  assert_equal sdk_span[:n], :sdk
256
249
  assert_equal sdk_span[:data][:sdk][:name], :test_trace
@@ -285,4 +278,77 @@ class TracerTest < Minitest::Test
285
278
  assert_equal sdk_span[:ec], 1
286
279
  assert_equal sdk_span.key?(:stack), false
287
280
  end
281
+
282
+ def test_nil_returns
283
+ clear_all!
284
+
285
+ refute ::Instana.tracer.tracing?
286
+ assert_nil ::Instana.tracer.log_entry(nil)
287
+ assert_nil ::Instana.tracer.log_info(nil)
288
+ assert_nil ::Instana.tracer.log_error(nil)
289
+ assert_nil ::Instana.tracer.log_exit(nil)
290
+ assert_nil ::Instana.tracer.log_end(nil)
291
+ assert_nil ::Instana.tracer.log_async_entry(nil, nil)
292
+ assert_nil ::Instana.tracer.context
293
+ end
294
+
295
+ def test_tracing_span
296
+ clear_all!
297
+
298
+ refute ::Instana.tracer.tracing_span?(:rack)
299
+ ::Instana.tracer.log_start_or_continue(:rack)
300
+ assert ::Instana.tracer.tracing_span?(:rack)
301
+ end
302
+
303
+ def test_log_exit_warn_span_name
304
+ logger = Minitest::Mock.new
305
+ logger.expect(:warn, true, [String])
306
+ subject = Instana::Tracer.new(logger: logger)
307
+
308
+ subject.log_start_or_continue(:sample)
309
+ subject.log_exit(:roda)
310
+
311
+ logger.verify
312
+ end
313
+
314
+ def test_log_end_warn_span_name
315
+ clear_all!
316
+
317
+ logger = Minitest::Mock.new
318
+ logger.expect(:warn, true, [String])
319
+ subject = Instana::Tracer.new(logger: logger)
320
+
321
+ subject.log_start_or_continue(:sample)
322
+ subject.log_end(:roda)
323
+
324
+ logger.verify
325
+ end
326
+
327
+ def test_log_entry_span
328
+ clear_all!
329
+
330
+ subject = Instana::Tracer.new
331
+ span = Instana::Span.new(:rack)
332
+
333
+ subject.log_entry(:sample, {}, ::Instana::Util.now_in_ms, span)
334
+ assert subject.tracing?
335
+ assert subject.current_span.parent, span
336
+ end
337
+
338
+ def test_log_entry_span_context
339
+ clear_all!
340
+
341
+ subject = Instana::Tracer.new
342
+ span_context = Instana::SpanContext.new('test', 'test')
343
+
344
+ subject.log_entry(:sample, {}, ::Instana::Util.now_in_ms, span_context)
345
+ assert subject.tracing?
346
+ assert subject.current_span.context, span_context
347
+ end
348
+
349
+ def test_missing_class_super
350
+ assert_raises NoMethodError do
351
+ Instana::Tracer.invalid
352
+ end
353
+ end
288
354
  end
data/test/util_test.rb ADDED
@@ -0,0 +1,10 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class UtilTest < Minitest::Test
7
+ def test_get_rb_source_error
8
+ assert_equal({ error: "Only Ruby source files are allowed. (*.rb)" }, Instana::Util.get_rb_source('invalid.txt'))
9
+ end
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.195.2
4
+ version: 1.197.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Giacomo Lombardo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-11 00:00:00.000000000 Z
11
+ date: 2021-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,47 +67,47 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: sys-proctable
70
+ name: fakefs
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 1.2.2
76
- type: :runtime
75
+ version: '0'
76
+ type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 1.2.2
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: get_process_mem
84
+ name: concurrent-ruby
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: 0.2.1
89
+ version: '1.1'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 0.2.1
96
+ version: '1.1'
97
97
  - !ruby/object:Gem::Dependency
98
- name: timers
98
+ name: sys-proctable
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 4.0.4
103
+ version: 1.2.2
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 4.0.4
110
+ version: 1.2.2
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: oj
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,20 +122,6 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: 3.0.11
125
- - !ruby/object:Gem::Dependency
126
- name: ffi
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: 1.0.11
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: 1.0.11
139
125
  description: The Instana gem is a zero configuration tool that will automatically
140
126
  collect key metrics and distributed traces from your Ruby processes. Just install
141
127
  and go.
@@ -228,23 +214,21 @@ files:
228
214
  - lib/instana/activators/sidekiq_client.rb
229
215
  - lib/instana/activators/sidekiq_worker.rb
230
216
  - lib/instana/activators/sinatra.rb
231
- - lib/instana/agent.rb
232
- - lib/instana/agent/helpers.rb
233
- - lib/instana/agent/hooks.rb
234
- - lib/instana/agent/tasks.rb
217
+ - lib/instana/backend/agent.rb
218
+ - lib/instana/backend/gc_snapshot.rb
219
+ - lib/instana/backend/host_agent.rb
220
+ - lib/instana/backend/host_agent_activation_observer.rb
221
+ - lib/instana/backend/host_agent_lookup.rb
222
+ - lib/instana/backend/host_agent_reporting_observer.rb
223
+ - lib/instana/backend/process_info.rb
224
+ - lib/instana/backend/request_client.rb
225
+ - lib/instana/backend/serverless_agent.rb
235
226
  - lib/instana/base.rb
236
- - lib/instana/collector.rb
237
- - lib/instana/collectors/gc.rb
238
- - lib/instana/collectors/memory.rb
239
- - lib/instana/collectors/thread.rb
240
227
  - lib/instana/config.rb
241
- - lib/instana/eum/eum-test.js.erb
242
- - lib/instana/eum/eum.js.erb
243
228
  - lib/instana/frameworks/cuba.rb
244
229
  - lib/instana/frameworks/rails.rb
245
230
  - lib/instana/frameworks/roda.rb
246
231
  - lib/instana/frameworks/sinatra.rb
247
- - lib/instana/helpers.rb
248
232
  - lib/instana/instrumentation/action_cable.rb
249
233
  - lib/instana/instrumentation/action_controller.rb
250
234
  - lib/instana/instrumentation/action_view.rb
@@ -266,23 +250,37 @@ files:
266
250
  - lib/instana/instrumentation/shoryuken.rb
267
251
  - lib/instana/instrumentation/sidekiq-client.rb
268
252
  - lib/instana/instrumentation/sidekiq-worker.rb
269
- - lib/instana/opentracing/carrier.rb
270
- - lib/instana/opentracing/tracer.rb
253
+ - lib/instana/logger_delegator.rb
254
+ - lib/instana/open_tracing/carrier.rb
255
+ - lib/instana/open_tracing/instana_tracer.rb
271
256
  - lib/instana/rack.rb
272
257
  - lib/instana/secrets.rb
273
258
  - lib/instana/setup.rb
274
- - lib/instana/thread_local.rb
259
+ - lib/instana/snapshot/deltable.rb
260
+ - lib/instana/snapshot/docker_container.rb
261
+ - lib/instana/snapshot/fargate_container.rb
262
+ - lib/instana/snapshot/fargate_process.rb
263
+ - lib/instana/snapshot/fargate_task.rb
264
+ - lib/instana/snapshot/lambda_function.rb
265
+ - lib/instana/snapshot/ruby_process.rb
275
266
  - lib/instana/tracer.rb
276
267
  - lib/instana/tracing/processor.rb
277
268
  - lib/instana/tracing/span.rb
278
269
  - lib/instana/tracing/span_context.rb
279
270
  - lib/instana/util.rb
280
271
  - lib/instana/version.rb
281
- - lib/oj_check.rb
282
272
  - lib/opentracing.rb
283
273
  - log/.keep
284
274
  - test/activator_test.rb
285
- - test/agent/agent_test.rb
275
+ - test/backend/agent_test.rb
276
+ - test/backend/gc_snapshot_test.rb
277
+ - test/backend/host_agent_activation_observer_test.rb
278
+ - test/backend/host_agent_lookup_test.rb
279
+ - test/backend/host_agent_reporting_observer_test.rb
280
+ - test/backend/host_agent_test.rb
281
+ - test/backend/process_info_test.rb
282
+ - test/backend/request_client_test.rb
283
+ - test/backend/serverless_agent_test.rb
286
284
  - test/benchmarks/bench_id_generation.rb
287
285
  - test/benchmarks/bench_opentracing.rb
288
286
  - test/config_test.rb
@@ -309,6 +307,12 @@ files:
309
307
  - test/instrumentation/sidekiq-client_test.rb
310
308
  - test/instrumentation/sidekiq-worker_test.rb
311
309
  - test/secrets_test.rb
310
+ - test/snapshot/deltable_test.rb
311
+ - test/snapshot/docker_container_test.rb
312
+ - test/snapshot/fargate_container_test.rb
313
+ - test/snapshot/fargate_process_test.rb
314
+ - test/snapshot/fargate_task_test.rb
315
+ - test/snapshot/ruby_process_test.rb
312
316
  - test/support/apps/active_record/active_record.rb
313
317
  - test/support/apps/grpc/boot.rb
314
318
  - test/support/apps/grpc/grpc_server.rb
@@ -324,12 +328,17 @@ files:
324
328
  - test/support/apps/sidekiq/jobs/sidekiq_job_2.rb
325
329
  - test/support/apps/sidekiq/worker.rb
326
330
  - test/support/helpers.rb
331
+ - test/support/mock_timer.rb
327
332
  - test/test_helper.rb
328
333
  - test/tracing/custom_test.rb
329
334
  - test/tracing/id_management_test.rb
330
335
  - test/tracing/opentracing_test.rb
336
+ - test/tracing/processor_test.rb
337
+ - test/tracing/span_context_test.rb
338
+ - test/tracing/span_test.rb
331
339
  - test/tracing/tracer_async_test.rb
332
340
  - test/tracing/tracer_test.rb
341
+ - test/util_test.rb
333
342
  homepage: https://www.instana.com/
334
343
  licenses:
335
344
  - MIT
@@ -360,12 +369,29 @@ summary: Ruby Distributed Tracing & Metrics Sensor for Instana
360
369
  test_files:
361
370
  - test/config_test.rb
362
371
  - test/activator_test.rb
372
+ - test/tracing/span_context_test.rb
373
+ - test/tracing/span_test.rb
363
374
  - test/tracing/id_management_test.rb
364
375
  - test/tracing/tracer_test.rb
365
376
  - test/tracing/custom_test.rb
366
377
  - test/tracing/opentracing_test.rb
367
378
  - test/tracing/tracer_async_test.rb
368
- - test/agent/agent_test.rb
379
+ - test/tracing/processor_test.rb
380
+ - test/snapshot/docker_container_test.rb
381
+ - test/snapshot/fargate_process_test.rb
382
+ - test/snapshot/deltable_test.rb
383
+ - test/snapshot/fargate_task_test.rb
384
+ - test/snapshot/ruby_process_test.rb
385
+ - test/snapshot/fargate_container_test.rb
386
+ - test/backend/host_agent_activation_observer_test.rb
387
+ - test/backend/host_agent_reporting_observer_test.rb
388
+ - test/backend/gc_snapshot_test.rb
389
+ - test/backend/host_agent_lookup_test.rb
390
+ - test/backend/serverless_agent_test.rb
391
+ - test/backend/process_info_test.rb
392
+ - test/backend/agent_test.rb
393
+ - test/backend/host_agent_test.rb
394
+ - test/backend/request_client_test.rb
369
395
  - test/secrets_test.rb
370
396
  - test/instrumentation/graphql_test.rb
371
397
  - test/instrumentation/sidekiq-client_test.rb
@@ -385,7 +411,9 @@ test_files:
385
411
  - test/instrumentation/excon_test.rb
386
412
  - test/instrumentation/grpc_test.rb
387
413
  - test/instrumentation/aws_test.rb
414
+ - test/util_test.rb
388
415
  - test/support/helpers.rb
416
+ - test/support/mock_timer.rb
389
417
  - test/support/apps/sidekiq/boot.rb
390
418
  - test/support/apps/sidekiq/jobs/sidekiq_job_2.rb
391
419
  - test/support/apps/sidekiq/jobs/sidekiq_job_1.rb
data/lib/instana/agent.rb DELETED
@@ -1,508 +0,0 @@
1
- # (c) Copyright IBM Corp. 2021
2
- # (c) Copyright Instana Inc. 2016
3
-
4
- require 'net/http'
5
- require 'socket'
6
- require 'sys/proctable'
7
- require 'timers'
8
- require 'uri'
9
- require 'thread'
10
-
11
- require 'instana/agent/helpers'
12
- require 'instana/agent/hooks'
13
- require 'instana/agent/tasks'
14
-
15
- include Sys
16
-
17
- module Instana
18
- OJ_OPTIONS = {:mode => :strict}
19
-
20
- class Agent
21
- include AgentHelpers
22
- include AgentHooks
23
- include AgentTasks
24
-
25
- attr_accessor :state
26
- attr_accessor :agent_uuid
27
- attr_accessor :process
28
- attr_accessor :collect_thread
29
- attr_accessor :thread_spawn_lock
30
- attr_accessor :extra_headers
31
- attr_reader :secret_values
32
-
33
- attr_accessor :testmode
34
-
35
- LOCALHOST = '127.0.0.1'.freeze
36
- MIME_JSON = 'application/json'.freeze
37
- DISCOVERY_PATH = 'com.instana.plugin.ruby.discovery'.freeze
38
- METRICS_PATH = "com.instana.plugin.ruby.%s"
39
- TRACES_PATH = "com.instana.plugin.ruby/traces.%s"
40
-
41
- def initialize
42
- @testmode = ENV.key?('INSTANA_TEST')
43
-
44
- # Supported two states (unannounced & announced)
45
- @state = :unannounced
46
-
47
- # Timestamp of the last successful response from
48
- # entity data reporting.
49
- @entity_last_seen = Time.now
50
-
51
- # Used to track the last time the collect timer was run.
52
- @last_collect_run = Time.now
53
-
54
- # Two timers, one for each state (unannounced & announced)
55
- @timers = ::Timers::Group.new
56
- @announce_timer = nil
57
- @pending_timer = nil
58
- @collect_timer = nil
59
-
60
- @thread_spawn_lock = Mutex.new
61
-
62
- # Detect platform flags
63
- @is_linux = (RbConfig::CONFIG['host_os'] =~ /linux/i) ? true : false
64
- @is_osx = (RUBY_PLATFORM =~ /darwin/i) ? true : false
65
-
66
- # In case we're running in Docker, have the default gateway available
67
- # to check in case we're running in bridged network mode
68
- if @is_linux && File.exist?("/sbin/ip")
69
- @default_gateway = `/sbin/ip route | awk '/default/ { print $3 }'`.chomp
70
- else
71
- @default_gateway = nil
72
- end
73
-
74
- # Re-useable HTTP client for communication with
75
- # the host agent.
76
- @httpclient = nil
77
-
78
- # Collect initial process info - repeat prior to announce
79
- # in `announce_sensor` in case of process rename, after fork etc.
80
- @process = ::Instana::Util.collect_process_info
81
-
82
- # The agent UUID returned from the host agent
83
- @agent_uuid = nil
84
-
85
- # This will hold info on the discovered agent host
86
- @discovered = nil
87
-
88
- # The agent may pass down custom headers for this sensor to capture
89
- @extra_headers = nil
90
-
91
- # The values considered sensitive and removed from http query parameters
92
- # and database connection strings
93
- @secret_values = nil
94
- end
95
-
96
- # Spawns the background thread and calls start. This method is separated
97
- # out for those who wish to control which thread the background agent will
98
- # run in.
99
- #
100
- # This method can be overridden with the following:
101
- #
102
- # module Instana
103
- # class Agent
104
- # def spawn_background_thread
105
- # # start thread
106
- # start
107
- # end
108
- # end
109
- # end
110
- #
111
- def spawn_background_thread
112
- @thread_spawn_lock.synchronize {
113
- if @collect_thread && @collect_thread.alive?
114
- ::Instana.logger.info "[instana] Collect thread already started & alive. Not spawning another."
115
- else
116
- @collect_thread = Thread.new do
117
- start
118
- end
119
- end
120
- }
121
- end
122
-
123
- # Sets up periodic timers and starts the agent in a background thread.
124
- #
125
- # There are three possible states for the agent:
126
- # - :unannounced
127
- # - :announced
128
- # - :ready
129
- def setup
130
- if ENV.key?('INSTANA_DISABLE')
131
- ::Instana.logger.info "Instana gem disabled via environment variable (INSTANA_DISABLE). Going to sit in a corner..."
132
- end
133
-
134
- # The announce timer
135
- # We attempt to announce this ruby sensor to the host agent.
136
- # In case of failure, we try again in 30 seconds.
137
- @announce_timer = @timers.now_and_every(30) do
138
- if @state == :unannounced && !ENV.key?('INSTANA_DISABLE')
139
- if host_agent_available? && announce_sensor
140
- transition_to(:announced)
141
- ::Instana.logger.debug "Announce successful. Waiting on ready. (#{@state} pid:#{Process.pid} #{@process[:name]})"
142
- end
143
- end
144
- end
145
-
146
- # The pending timer
147
- # Handles the time between successful announce and when the host agent METRICS_PATH and TRACES_PATH
148
- # no longer return 404s and are truly ready to accept data.
149
- @pending_timer = @timers.now_and_every(1) do
150
- path = sprintf(METRICS_PATH, @process[:report_pid])
151
- uri = URI.parse("http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/#{path}")
152
- req = Net::HTTP::Post.new(uri)
153
- req.body = Oj.dump({}, OJ_OPTIONS)
154
-
155
- response = make_host_agent_request(req)
156
- if response && (response.code.to_i == 200)
157
- transition_to(:ready)
158
- ::Instana.logger.info "Host agent available. We're in business. (#{@state} pid:#{Process.pid} #{@process[:name]})"
159
- end
160
- end
161
-
162
- # The collect timer
163
- # If we are in announced state, send metric data (only delta reporting)
164
- # every ::Instana.config[:collector][:interval] seconds.
165
- @collect_timer = @timers.every(::Instana.config[:collector][:interval]) do
166
- # Make sure that this block doesn't get called more often than the interval. This can
167
- # happen on high CPU load and a back up of timer runs. If we are called before `interval`
168
- # then we just skip.
169
- unless (Time.now - @last_collect_run) < ::Instana.config[:collector][:interval]
170
- @last_collect_run = Time.now
171
- if @state == :ready
172
- if !::Instana.collector.collect_and_report
173
- # If report has been failing for more than 1 minute,
174
- # fall back to unannounced state
175
- if (Time.now - @entity_last_seen) > 60
176
- ::Instana.logger.warn "Host agent offline for >1 min. Going to sit in a corner..."
177
- transition_to(:unannounced)
178
- end
179
- end
180
- ::Instana.processor.send
181
- end
182
- end
183
- end
184
- end
185
-
186
- # Starts the timer loop for the timers that were initialized
187
- # in the setup method. This is blocking and should only be
188
- # called from an already initialized background thread.
189
- #
190
- def start
191
- if !ENV.key?('INSTANA_DISABLE') && !host_agent_available?
192
- if !ENV.key?("INSTANA_QUIET")
193
- ::Instana.logger.info "Instana host agent not available. Will retry periodically. (Set env INSTANA_QUIET=1 to shut these messages off)"
194
- end
195
- end
196
-
197
- while true
198
- if @state == :unannounced
199
- @announce_timer.resume
200
- @pending_timer.pause
201
- @collect_timer.pause
202
- elsif @state == :announced
203
- @announce_timer.pause
204
- @pending_timer.resume
205
- @collect_timer.pause
206
- elsif @state == :ready
207
- @announce_timer.pause
208
- @pending_timer.pause
209
- @collect_timer.resume
210
- end
211
- @timers.wait
212
- end
213
- rescue Exception => e
214
- ::Instana.logger.warn { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
215
- ::Instana.logger.debug { e.backtrace.join("\r\n") }
216
- ensure
217
- if @state == :ready
218
- # Pause the timers so they don't fire while we are reporting traces
219
- @announce_timer.pause
220
- @pending_timer.pause
221
- @collect_timer.pause
222
-
223
- ::Instana.logger.debug { "#{Thread.current}: Agent exiting. Reporting final spans (if any)." }
224
- ::Instana.processor.send
225
- end
226
- end
227
-
228
- # Collect process ID, name and arguments to notify
229
- # the host agent.
230
- #
231
- def announce_sensor
232
- unless @discovered
233
- ::Instana.logger.debug("#{__method__} called but discovery hasn't run yet!")
234
- return false
235
- end
236
-
237
- # Always re-collect process info before announce in case the process name has been
238
- # re-written (looking at you puma!)
239
- @process = ::Instana::Util.collect_process_info
240
-
241
- announce_payload = {}
242
- announce_payload[:name] = @process[:name]
243
- announce_payload[:args] = @process[:arguments]
244
-
245
- socket = nil
246
- if @is_linux && !@testmode
247
- # We create an open socket to the host agent in case we are running in a container
248
- # and the real pid needs to be detected.
249
- socket = TCPSocket.open @discovered[:agent_host], @discovered[:agent_port]
250
-
251
- announce_payload[:fd] = socket.fileno
252
- announce_payload[:inode] = File.readlink("/proc/self/fd/#{socket.fileno}")
253
- announce_payload[:cpuSetFileContent] = get_cpuset_contents
254
-
255
- sched_pid = get_sched_pid
256
- announce_payload[:pid] = sched_pid
257
-
258
- if running_in_container?
259
- if sched_pid != Process.pid
260
- # In container: sched reveals true PID
261
- announce_payload[:pidFromParentNS] = true
262
- else
263
- # In container: sched told us nothing
264
- announce_payload[:pidFromParentNS] = false
265
- end
266
- else
267
- # Not in a container
268
- announce_payload[:pidFromParentNS] = true
269
- end
270
-
271
- else
272
- announce_payload[:pid] = Process.pid
273
- announce_payload[:pidFromParentNS] = true
274
- end
275
-
276
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{DISCOVERY_PATH}")
277
- req = Net::HTTP::Put.new(uri)
278
- req.body = Oj.dump(announce_payload, OJ_OPTIONS)
279
-
280
- #::Instana.logger.debug("Announce payload: #{announce_payload}")
281
- #::Instana.logger.debug { "Announce: http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{DISCOVERY_PATH} - payload: #{req.body}" }
282
-
283
- response = make_host_agent_request(req, open_timeout=3, read_timeout=3, debug=true)
284
-
285
- if response && (response.code.to_i == 200)
286
- data = Oj.load(response.body, OJ_OPTIONS)
287
- @process[:report_pid] = data['pid']
288
- @agent_uuid = data['agentUuid']
289
- @secret_values = data['secrets']
290
-
291
- if data.key?('extraHeaders')
292
- @extra_headers = data['extraHeaders']
293
- end
294
- true
295
- else
296
- false
297
- end
298
- rescue => e
299
- Instana.logger.info { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
300
- Instana.logger.debug { e.backtrace.join("\r\n") }
301
- return false
302
- ensure
303
- socket.close if socket && !socket.closed?
304
- end
305
-
306
- # Method to report metrics data to the host agent.
307
- #
308
- # @param paylod [Hash] The collection of metrics to report.
309
- #
310
- # @return [Boolean] true on success, false otherwise
311
- #
312
- def report_metrics(payload)
313
- if @state != :ready && !@testmode
314
- ::Instana.logger.debug "report_metrics called but agent not in ready state."
315
- return false
316
- end
317
-
318
- path = sprintf(METRICS_PATH, @process[:report_pid])
319
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{path}")
320
- req = Net::HTTP::Post.new(uri)
321
-
322
- req.body = Oj.dump(payload, OJ_OPTIONS)
323
- response = make_host_agent_request(req)
324
-
325
- if response
326
- if response.body && response.body.length > 2
327
- # The host agent returned something indicating that is has a request for us that we
328
- # need to process.
329
- handle_agent_tasks(response.body)
330
- end
331
-
332
- if response.code.to_i == 200
333
- @entity_last_seen = Time.now
334
- return true
335
- end
336
-
337
- end
338
- false
339
- rescue => e
340
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
341
- Instana.logger.debug { e.backtrace.join("\r\n") }
342
- end
343
-
344
- # Accept and report spans to the host agent.
345
- #
346
- # @param spans [Array] An array of [Span]
347
- # @return [Boolean]
348
- #
349
- def report_spans(spans)
350
- if @state != :ready && !@testmode
351
- ::Instana.logger.debug "report_spans called but agent not in ready state."
352
- return false
353
- end
354
-
355
- ::Instana.logger.debug "Reporting #{spans.length} spans"
356
-
357
- path = sprintf(TRACES_PATH, @process[:report_pid])
358
- uri = URI.parse("http://#{@discovered[:agent_host]}:#{@discovered[:agent_port]}/#{path}")
359
- req = Net::HTTP::Post.new(uri)
360
-
361
- opts = OJ_OPTIONS.merge({omit_nil: true})
362
-
363
- req.body = Oj.dump(spans, opts)
364
- response = make_host_agent_request(req)
365
-
366
- if response
367
- last_trace_response = response.code.to_i
368
-
369
- if [200, 204].include?(last_trace_response)
370
- return true
371
- end
372
- end
373
- false
374
- rescue => e
375
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
376
- Instana.logger.debug { e.backtrace.join("\r\n") }
377
- end
378
-
379
- # Check that the host agent is available and can be contacted. This will
380
- # first check localhost and if not, then attempt on the default gateway
381
- # for docker in bridged mode.
382
- #
383
- def host_agent_available?
384
- @discovered ||= run_discovery
385
-
386
- if @discovered
387
- return true
388
- end
389
- false
390
- rescue => e
391
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
392
- Instana.logger.debug { e.backtrace.join("\r\n") } unless @testmode
393
- return false
394
- end
395
-
396
- # Runs a discovery process to determine where we can contact the host agent. This is usually just
397
- # localhost but in docker can be found on the default gateway. Another option is the INSTANA_AGENT_HOST
398
- # environment variable. This also allows for manual configuration via ::Instana.config[:agent_host/port].
399
- #
400
- # @return [Hash] a hash with :agent_host, :agent_port values or empty hash
401
- #
402
- def run_discovery
403
- discovered = {}
404
-
405
- ::Instana.logger.debug { "#{__method__}: Running agent discovery..." }
406
-
407
- # Try default location or manually configured (if so)
408
- uri = URI.parse("http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/")
409
- req = Net::HTTP::Get.new(uri)
410
-
411
- ::Instana.logger.debug { "#{__method__}: Trying #{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}" }
412
-
413
- response = make_host_agent_request(req)
414
-
415
- if response && (response.code.to_i == 200)
416
- discovered[:agent_host] = ::Instana.config[:agent_host]
417
- discovered[:agent_port] = ::Instana.config[:agent_port]
418
- ::Instana.logger.debug { "#{__method__}: Found #{discovered[:agent_host]}:#{discovered[:agent_port]}" }
419
- return discovered
420
- end
421
-
422
- return nil unless @is_linux
423
-
424
- # We are potentially running on Docker in bridged networking mode.
425
- # Attempt to contact default gateway
426
- uri = URI.parse("http://#{@default_gateway}:#{::Instana.config[:agent_port]}/")
427
- req = Net::HTTP::Get.new(uri)
428
-
429
- ::Instana.logger.debug { "#{__method__}: Trying default gateway #{@default_gateway}:#{::Instana.config[:agent_port]}" }
430
-
431
- response = make_host_agent_request(req)
432
-
433
- if response && (response.code.to_i == 200)
434
- discovered[:agent_host] = @default_gateway
435
- discovered[:agent_port] = ::Instana.config[:agent_port]
436
- ::Instana.logger.debug { "#{__method__}: Found #{discovered[:agent_host]}:#{discovered[:agent_port]}" }
437
- return discovered
438
- end
439
-
440
- nil
441
- end
442
-
443
- private
444
-
445
- # Handles any/all steps required in the transtion
446
- # between states.
447
- #
448
- # @param state [Symbol] Can be 1 of 2 possible states:
449
- # `:announced`, `:unannounced`
450
- #
451
- def transition_to(state)
452
- ::Instana.logger.debug("Transitioning to #{state}")
453
- case state
454
- when :ready
455
- # announced
456
- @state = :ready
457
-
458
- # Reset the entity timer
459
- @entity_last_seen = Time.now
460
- when :announced
461
- # announce successful; set state
462
- @state = :announced
463
-
464
- # Reset the entity timer
465
- @entity_last_seen = Time.now
466
- when :unannounced
467
- @state = :unannounced
468
- # Reset our HTTP client
469
- @httpclient = nil
470
- else
471
- ::Instana.logger.debug "Uknown agent state: #{state}"
472
- end
473
- ::Instana.collector.reset_snapshot_timer!
474
- true
475
- end
476
-
477
- # Centralization of the net/http communications
478
- # with the host agent. Pass in a prepared <req>
479
- # of type Net::HTTP::Get|Put|Head
480
- #
481
- # @param req [Net::HTTP::Req] A prepared Net::HTTP request object of the type
482
- # you wish to make (Get, Put, Post etc.)
483
- #
484
- def make_host_agent_request(req, open_timeout=1, read_timeout=1, debug=false)
485
- req['Accept'] = MIME_JSON
486
- req['Content-Type'] = MIME_JSON
487
-
488
- if @state == :unannounced
489
- @httpclient = Net::HTTP.new(req.uri.hostname, req.uri.port)
490
- @httpclient.open_timeout = open_timeout
491
- @httpclient.read_timeout = read_timeout
492
- end
493
-
494
- response = @httpclient.request(req)
495
-
496
- if debug
497
- ::Instana.logger.debug "#{req.method}->#{req.uri} body:(#{req.body}) Response:#{response} body:(#{response.body})"
498
- end
499
-
500
- response
501
- rescue Errno::ECONNREFUSED
502
- return nil
503
- rescue => e
504
- Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message} (to #{req.uri})" }
505
- return nil
506
- end
507
- end
508
- end