ddtrace 0.52.0 → 0.54.2

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +174 -11
  3. data/ddtrace.gemspec +6 -3
  4. data/docs/DevelopmentGuide.md +1 -6
  5. data/docs/GettingStarted.md +109 -18
  6. data/docs/ProfilingDevelopment.md +2 -2
  7. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +86 -0
  8. data/ext/ddtrace_profiling_native_extension/clock_id.h +4 -0
  9. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +52 -0
  10. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +14 -0
  11. data/ext/ddtrace_profiling_native_extension/extconf.rb +177 -8
  12. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +35 -0
  13. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  14. data/ext/ddtrace_profiling_native_extension/profiling.c +6 -1
  15. data/lib/datadog/ci/contrib/cucumber/formatter.rb +1 -0
  16. data/lib/datadog/ci/contrib/rspec/example.rb +1 -0
  17. data/lib/datadog/ci/contrib/rspec/integration.rb +2 -2
  18. data/lib/datadog/ci/ext/environment.rb +64 -22
  19. data/lib/datadog/ci/ext/test.rb +1 -0
  20. data/lib/datadog/ci/test.rb +5 -1
  21. data/lib/datadog/contrib.rb +2 -0
  22. data/lib/datadog/core/environment/vm_cache.rb +46 -0
  23. data/lib/ddtrace/buffer.rb +28 -16
  24. data/lib/ddtrace/configuration/agent_settings_resolver.rb +131 -53
  25. data/lib/ddtrace/configuration/components.rb +1 -1
  26. data/lib/ddtrace/configuration/settings.rb +13 -3
  27. data/lib/ddtrace/context.rb +10 -2
  28. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +46 -0
  29. data/lib/ddtrace/contrib/action_cable/patcher.rb +1 -0
  30. data/lib/ddtrace/contrib/action_mailer/configuration/settings.rb +32 -0
  31. data/lib/ddtrace/contrib/action_mailer/event.rb +50 -0
  32. data/lib/ddtrace/contrib/action_mailer/events/deliver.rb +54 -0
  33. data/lib/ddtrace/contrib/action_mailer/events/process.rb +41 -0
  34. data/lib/ddtrace/contrib/action_mailer/events.rb +31 -0
  35. data/lib/ddtrace/contrib/action_mailer/ext.rb +32 -0
  36. data/lib/ddtrace/contrib/action_mailer/integration.rb +45 -0
  37. data/lib/ddtrace/contrib/action_mailer/patcher.rb +27 -0
  38. data/lib/ddtrace/contrib/active_job/configuration/settings.rb +33 -0
  39. data/lib/ddtrace/contrib/active_job/event.rb +54 -0
  40. data/lib/ddtrace/contrib/active_job/events/discard.rb +46 -0
  41. data/lib/ddtrace/contrib/active_job/events/enqueue.rb +45 -0
  42. data/lib/ddtrace/contrib/active_job/events/enqueue_at.rb +45 -0
  43. data/lib/ddtrace/contrib/active_job/events/enqueue_retry.rb +47 -0
  44. data/lib/ddtrace/contrib/active_job/events/perform.rb +45 -0
  45. data/lib/ddtrace/contrib/active_job/events/retry_stopped.rb +46 -0
  46. data/lib/ddtrace/contrib/active_job/events.rb +39 -0
  47. data/lib/ddtrace/contrib/active_job/ext.rb +32 -0
  48. data/lib/ddtrace/contrib/active_job/integration.rb +46 -0
  49. data/lib/ddtrace/contrib/active_job/log_injection.rb +21 -0
  50. data/lib/ddtrace/contrib/active_job/patcher.rb +33 -0
  51. data/lib/ddtrace/contrib/auto_instrument.rb +0 -1
  52. data/lib/ddtrace/contrib/delayed_job/plugin.rb +2 -2
  53. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +1 -1
  54. data/lib/ddtrace/contrib/mongodb/integration.rb +5 -0
  55. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +0 -1
  56. data/lib/ddtrace/contrib/rails/configuration/settings.rb +7 -0
  57. data/lib/ddtrace/contrib/rails/framework.rb +24 -1
  58. data/lib/ddtrace/contrib/rails/patcher.rb +19 -10
  59. data/lib/ddtrace/contrib/redis/instrumentation.rb +90 -0
  60. data/lib/ddtrace/contrib/redis/patcher.rb +2 -84
  61. data/lib/ddtrace/contrib/registerable.rb +0 -1
  62. data/lib/ddtrace/contrib/resque/integration.rb +1 -5
  63. data/lib/ddtrace/contrib/sidekiq/ext.rb +3 -0
  64. data/lib/ddtrace/contrib/sidekiq/integration.rb +10 -0
  65. data/lib/ddtrace/contrib/sidekiq/patcher.rb +26 -0
  66. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/heartbeat.rb +30 -0
  67. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/job_fetch.rb +30 -0
  68. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/scheduled_push.rb +29 -0
  69. data/lib/ddtrace/contrib/sinatra/env.rb +2 -1
  70. data/lib/ddtrace/contrib/sinatra/tracer.rb +15 -2
  71. data/lib/ddtrace/ext/git.rb +12 -0
  72. data/lib/ddtrace/ext/priority.rb +6 -4
  73. data/lib/ddtrace/ext/profiling.rb +8 -11
  74. data/lib/ddtrace/ext/runtime.rb +3 -0
  75. data/lib/ddtrace/ext/transport.rb +11 -0
  76. data/lib/ddtrace/metrics.rb +2 -2
  77. data/lib/ddtrace/profiling/collectors/stack.rb +112 -72
  78. data/lib/ddtrace/profiling/encoding/profile.rb +10 -2
  79. data/lib/ddtrace/profiling/events/stack.rb +13 -13
  80. data/lib/ddtrace/profiling/native_extension.rb +23 -1
  81. data/lib/ddtrace/profiling/pprof/builder.rb +8 -2
  82. data/lib/ddtrace/profiling/pprof/converter.rb +22 -9
  83. data/lib/ddtrace/profiling/pprof/stack_sample.rb +32 -9
  84. data/lib/ddtrace/profiling/pprof/template.rb +2 -2
  85. data/lib/ddtrace/profiling/scheduler.rb +20 -4
  86. data/lib/ddtrace/profiling/tasks/setup.rb +21 -13
  87. data/lib/ddtrace/profiling/trace_identifiers/ddtrace.rb +10 -9
  88. data/lib/ddtrace/profiling/trace_identifiers/helper.rb +5 -5
  89. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +8 -15
  90. data/lib/ddtrace/profiling/transport/http.rb +8 -17
  91. data/lib/ddtrace/profiling.rb +0 -2
  92. data/lib/ddtrace/runtime/metrics.rb +14 -0
  93. data/lib/ddtrace/sampler.rb +18 -8
  94. data/lib/ddtrace/sampling/rule_sampler.rb +13 -1
  95. data/lib/ddtrace/span.rb +7 -19
  96. data/lib/ddtrace/tracer.rb +1 -1
  97. data/lib/ddtrace/transport/http/adapters/net.rb +13 -3
  98. data/lib/ddtrace/transport/http/adapters/test.rb +4 -2
  99. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +23 -12
  100. data/lib/ddtrace/transport/http/builder.rb +13 -6
  101. data/lib/ddtrace/transport/http.rb +5 -11
  102. data/lib/ddtrace/utils/time.rb +11 -6
  103. data/lib/ddtrace/version.rb +2 -2
  104. data/lib/ddtrace/workers/{loop.rb → interval_loop.rb} +0 -16
  105. data/lib/ddtrace/workers/polling.rb +1 -1
  106. metadata +40 -10
  107. data/lib/ddtrace/profiling/ext/cpu.rb +0 -67
  108. data/lib/ddtrace/profiling/ext/cthread.rb +0 -156
@@ -1,5 +1,6 @@
1
1
  # typed: false
2
2
  require 'net/http'
3
+ require 'ddtrace/ext/transport'
3
4
  require 'ddtrace/transport/http/adapters/net'
4
5
 
5
6
  module Datadog
@@ -8,21 +9,29 @@ module Datadog
8
9
  module Adapters
9
10
  # Adapter for Unix sockets
10
11
  class UnixSocket < Adapters::Net
11
- DEFAULT_TIMEOUT = 1
12
-
13
12
  attr_reader \
14
- :filepath,
13
+ :filepath, # DEV(1.0): Rename to `uds_path`
15
14
  :timeout
16
15
 
17
- def initialize(filepath, options = {})
18
- @filepath = filepath
19
- @timeout = options.fetch(:timeout, DEFAULT_TIMEOUT)
16
+ alias_method :uds_path, :filepath
17
+
18
+ # @deprecated Positional parameters are deprecated. Use named parameters instead.
19
+ def initialize(uds_path = nil, **options)
20
+ @filepath = uds_path || options.fetch(:uds_path)
21
+ @timeout = options[:timeout] || Ext::Transport::UnixSocket::DEFAULT_TIMEOUT_SECONDS
22
+ end
23
+
24
+ def self.build(agent_settings)
25
+ new(
26
+ uds_path: agent_settings.uds_path,
27
+ timeout: agent_settings.timeout_seconds,
28
+ )
20
29
  end
21
30
 
22
31
  def open(&block)
23
32
  # Open connection
24
33
  connection = HTTP.new(
25
- filepath,
34
+ uds_path,
26
35
  read_timeout: timeout,
27
36
  continue_timeout: timeout
28
37
  )
@@ -31,7 +40,7 @@ module Datadog
31
40
  end
32
41
 
33
42
  def url
34
- "http+unix://#{filepath}?timeout=#{timeout}"
43
+ "http+unix://#{uds_path}?timeout=#{timeout}"
35
44
  end
36
45
 
37
46
  # Re-implements Net:HTTP with underlying Unix socket
@@ -39,19 +48,21 @@ module Datadog
39
48
  DEFAULT_TIMEOUT = 1
40
49
 
41
50
  attr_reader \
42
- :filepath,
51
+ :filepath, # DEV(1.0): Rename to `uds_path`
43
52
  :unix_socket
44
53
 
45
- def initialize(filepath, options = {})
54
+ alias_method :uds_path, :filepath
55
+
56
+ def initialize(uds_path, options = {})
46
57
  super('localhost', 80)
47
- @filepath = filepath
58
+ @filepath = uds_path
48
59
  @read_timeout = options.fetch(:read_timeout, DEFAULT_TIMEOUT)
49
60
  @continue_timeout = options.fetch(:continue_timeout, DEFAULT_TIMEOUT)
50
61
  @debug_output = options[:debug_output] if options.key?(:debug_output)
51
62
  end
52
63
 
53
64
  def connect
54
- @unix_socket = UNIXSocket.open(filepath)
65
+ @unix_socket = UNIXSocket.open(uds_path)
55
66
  @socket = ::Net::BufferedIO.new(@unix_socket).tap do |socket|
56
67
  socket.read_timeout = @read_timeout
57
68
  socket.continue_timeout = @continue_timeout
@@ -1,4 +1,5 @@
1
1
  # typed: true
2
+ require 'ddtrace/configuration/agent_settings_resolver'
2
3
  require 'ddtrace/transport/http/adapters/registry'
3
4
  require 'ddtrace/transport/http/api/map'
4
5
  require 'ddtrace/transport/http/api/instance'
@@ -33,14 +34,20 @@ module Datadog
33
34
  yield(self) if block_given?
34
35
  end
35
36
 
36
- def adapter(type, *args)
37
- @default_adapter = if type.is_a?(Symbol)
38
- registry_klass = REGISTRY.get(type)
39
- raise UnknownAdapterError, type if registry_klass.nil?
37
+ def adapter(config, *args, **kwargs)
38
+ @default_adapter = case config
39
+ when Configuration::AgentSettingsResolver::AgentSettings
40
+ registry_klass = REGISTRY.get(config.adapter)
41
+ raise UnknownAdapterError, config.adapter if registry_klass.nil?
40
42
 
41
- registry_klass.new(*args)
43
+ registry_klass.build(config)
44
+ when Symbol
45
+ registry_klass = REGISTRY.get(config)
46
+ raise UnknownAdapterError, config if registry_klass.nil?
47
+
48
+ registry_klass.new(*args, **kwargs)
42
49
  else
43
- type
50
+ config
44
51
  end
45
52
  end
46
53
 
@@ -30,13 +30,7 @@ module Datadog
30
30
  # Pass a block to override any settings.
31
31
  def default(agent_settings: Datadog::Configuration::AgentSettingsResolver::ENVIRONMENT_AGENT_SETTINGS, **options)
32
32
  new do |transport|
33
- transport.adapter(
34
- default_adapter,
35
- agent_settings.hostname,
36
- agent_settings.port,
37
- timeout: agent_settings.timeout_seconds,
38
- ssl: agent_settings.ssl
39
- )
33
+ transport.adapter(agent_settings)
40
34
  transport.headers default_headers
41
35
 
42
36
  if agent_settings.deprecated_for_removal_transport_configuration_options
@@ -80,7 +74,7 @@ module Datadog
80
74
  end
81
75
 
82
76
  def default_adapter
83
- :net_http
77
+ Ext::Transport::HTTP::ADAPTER
84
78
  end
85
79
 
86
80
  def default_hostname(logger: Datadog.logger)
@@ -111,9 +105,9 @@ module Datadog
111
105
  end
112
106
 
113
107
  # Add adapters to registry
114
- Builder::REGISTRY.set(Adapters::Net, :net_http)
115
- Builder::REGISTRY.set(Adapters::Test, :test)
116
- Builder::REGISTRY.set(Adapters::UnixSocket, :unix)
108
+ Builder::REGISTRY.set(Adapters::Net, Ext::Transport::HTTP::ADAPTER)
109
+ Builder::REGISTRY.set(Adapters::Test, Ext::Transport::Test::ADAPTER)
110
+ Builder::REGISTRY.set(Adapters::UnixSocket, Ext::Transport::UnixSocket::ADAPTER)
117
111
  end
118
112
  end
119
113
  end
@@ -7,13 +7,12 @@ module Datadog
7
7
 
8
8
  module_function
9
9
 
10
- # Current monotonic time.
11
- # Falls back to `now` if monotonic clock
12
- # is not available.
10
+ # Current monotonic time
13
11
  #
14
- # @return [Float] in seconds, since some unspecified starting point
15
- def get_time
16
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
12
+ # @param unit [Symbol] unit for the resulting value, same as ::Process#clock_gettime, defaults to :float_second
13
+ # @return [Numeric] timestamp in the requested unit, since some unspecified starting point
14
+ def get_time(unit = :float_second)
15
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
17
16
  end
18
17
 
19
18
  # Current wall time.
@@ -41,6 +40,12 @@ module Datadog
41
40
  after = get_time
42
41
  after - before
43
42
  end
43
+
44
+ def as_utc_epoch_ns(time)
45
+ # we use #to_r instead of #to_f because Float doesn't have enough precision to represent exact nanoseconds, see
46
+ # https://rubyapi.org/3.0/o/time#method-i-to_f
47
+ (time.to_r * 1_000_000_000).to_i
48
+ end
44
49
  end
45
50
  end
46
51
  end
@@ -2,8 +2,8 @@
2
2
  module Datadog
3
3
  module VERSION
4
4
  MAJOR = 0
5
- MINOR = 52
6
- PATCH = 0
5
+ MINOR = 54
6
+ PATCH = 2
7
7
  PRE = nil
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
@@ -60,15 +60,6 @@ module Datadog
60
60
  @loop_wait_time = value
61
61
  end
62
62
 
63
- def reset_loop_wait_time
64
- self.loop_wait_time = loop_base_interval
65
- end
66
-
67
- # Should the loop "back off" when there's no work?
68
- def loop_back_off?
69
- false
70
- end
71
-
72
63
  def loop_back_off!
73
64
  self.loop_wait_time = [loop_wait_time * BACK_OFF_RATIO, BACK_OFF_MAX].min
74
65
  end
@@ -106,13 +97,6 @@ module Datadog
106
97
  # There's work to do...
107
98
  # Run the task
108
99
  yield
109
-
110
- # Reset the wait interval
111
- reset_loop_wait_time if loop_back_off?
112
- elsif loop_back_off?
113
- # There's no work to do...
114
- # Back off the wait interval a bit
115
- loop_back_off!
116
100
  end
117
101
 
118
102
  # Wait for an interval, unless shutdown has been signaled.
@@ -1,6 +1,6 @@
1
1
  # typed: false
2
2
  require 'ddtrace/workers/async'
3
- require 'ddtrace/workers/loop'
3
+ require 'ddtrace/workers/interval_loop'
4
4
 
5
5
  module Datadog
6
6
  module Workers
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ddtrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.52.0
4
+ version: 0.54.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-09 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: ffi
28
+ name: debase-ruby_core_source
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - "<="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: 0.10.14
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - "<="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: 0.10.14
41
41
  description: |
42
42
  ddtrace is Datadog’s tracing client for Ruby. It is used to trace requests
43
43
  as they flow across web servers, databases and microservices so that developers
@@ -66,7 +66,13 @@ files:
66
66
  - docs/DevelopmentGuide.md
67
67
  - docs/GettingStarted.md
68
68
  - docs/ProfilingDevelopment.md
69
+ - ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md
70
+ - ext/ddtrace_profiling_native_extension/clock_id.h
71
+ - ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c
72
+ - ext/ddtrace_profiling_native_extension/clock_id_noop.c
69
73
  - ext/ddtrace_profiling_native_extension/extconf.rb
74
+ - ext/ddtrace_profiling_native_extension/private_vm_api_access.c
75
+ - ext/ddtrace_profiling_native_extension/private_vm_api_access.h
70
76
  - ext/ddtrace_profiling_native_extension/profiling.c
71
77
  - lib/datadog/ci.rb
72
78
  - lib/datadog/ci/configuration/components.rb
@@ -99,6 +105,7 @@ files:
99
105
  - lib/datadog/core/environment/socket.rb
100
106
  - lib/datadog/core/environment/thread_count.rb
101
107
  - lib/datadog/core/environment/variable_helpers.rb
108
+ - lib/datadog/core/environment/vm_cache.rb
102
109
  - lib/ddtrace.rb
103
110
  - lib/ddtrace/analytics.rb
104
111
  - lib/ddtrace/auto_instrument.rb
@@ -130,6 +137,14 @@ files:
130
137
  - lib/ddtrace/contrib/action_cable/instrumentation.rb
131
138
  - lib/ddtrace/contrib/action_cable/integration.rb
132
139
  - lib/ddtrace/contrib/action_cable/patcher.rb
140
+ - lib/ddtrace/contrib/action_mailer/configuration/settings.rb
141
+ - lib/ddtrace/contrib/action_mailer/event.rb
142
+ - lib/ddtrace/contrib/action_mailer/events.rb
143
+ - lib/ddtrace/contrib/action_mailer/events/deliver.rb
144
+ - lib/ddtrace/contrib/action_mailer/events/process.rb
145
+ - lib/ddtrace/contrib/action_mailer/ext.rb
146
+ - lib/ddtrace/contrib/action_mailer/integration.rb
147
+ - lib/ddtrace/contrib/action_mailer/patcher.rb
133
148
  - lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb
134
149
  - lib/ddtrace/contrib/action_pack/action_controller/patcher.rb
135
150
  - lib/ddtrace/contrib/action_pack/configuration/settings.rb
@@ -148,6 +163,19 @@ files:
148
163
  - lib/ddtrace/contrib/action_view/integration.rb
149
164
  - lib/ddtrace/contrib/action_view/patcher.rb
150
165
  - lib/ddtrace/contrib/action_view/utils.rb
166
+ - lib/ddtrace/contrib/active_job/configuration/settings.rb
167
+ - lib/ddtrace/contrib/active_job/event.rb
168
+ - lib/ddtrace/contrib/active_job/events.rb
169
+ - lib/ddtrace/contrib/active_job/events/discard.rb
170
+ - lib/ddtrace/contrib/active_job/events/enqueue.rb
171
+ - lib/ddtrace/contrib/active_job/events/enqueue_at.rb
172
+ - lib/ddtrace/contrib/active_job/events/enqueue_retry.rb
173
+ - lib/ddtrace/contrib/active_job/events/perform.rb
174
+ - lib/ddtrace/contrib/active_job/events/retry_stopped.rb
175
+ - lib/ddtrace/contrib/active_job/ext.rb
176
+ - lib/ddtrace/contrib/active_job/integration.rb
177
+ - lib/ddtrace/contrib/active_job/log_injection.rb
178
+ - lib/ddtrace/contrib/active_job/patcher.rb
151
179
  - lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb
152
180
  - lib/ddtrace/contrib/active_model_serializers/event.rb
153
181
  - lib/ddtrace/contrib/active_model_serializers/events.rb
@@ -352,6 +380,7 @@ files:
352
380
  - lib/ddtrace/contrib/redis/configuration/resolver.rb
353
381
  - lib/ddtrace/contrib/redis/configuration/settings.rb
354
382
  - lib/ddtrace/contrib/redis/ext.rb
383
+ - lib/ddtrace/contrib/redis/instrumentation.rb
355
384
  - lib/ddtrace/contrib/redis/integration.rb
356
385
  - lib/ddtrace/contrib/redis/patcher.rb
357
386
  - lib/ddtrace/contrib/redis/quantize.rb
@@ -392,6 +421,9 @@ files:
392
421
  - lib/ddtrace/contrib/sidekiq/ext.rb
393
422
  - lib/ddtrace/contrib/sidekiq/integration.rb
394
423
  - lib/ddtrace/contrib/sidekiq/patcher.rb
424
+ - lib/ddtrace/contrib/sidekiq/server_internal_tracer/heartbeat.rb
425
+ - lib/ddtrace/contrib/sidekiq/server_internal_tracer/job_fetch.rb
426
+ - lib/ddtrace/contrib/sidekiq/server_internal_tracer/scheduled_push.rb
395
427
  - lib/ddtrace/contrib/sidekiq/server_tracer.rb
396
428
  - lib/ddtrace/contrib/sidekiq/tracing.rb
397
429
  - lib/ddtrace/contrib/sinatra/configuration/settings.rb
@@ -480,8 +512,6 @@ files:
480
512
  - lib/ddtrace/profiling/event.rb
481
513
  - lib/ddtrace/profiling/events/stack.rb
482
514
  - lib/ddtrace/profiling/exporter.rb
483
- - lib/ddtrace/profiling/ext/cpu.rb
484
- - lib/ddtrace/profiling/ext/cthread.rb
485
515
  - lib/ddtrace/profiling/ext/forking.rb
486
516
  - lib/ddtrace/profiling/flush.rb
487
517
  - lib/ddtrace/profiling/native_extension.rb
@@ -581,7 +611,7 @@ files:
581
611
  - lib/ddtrace/worker.rb
582
612
  - lib/ddtrace/workers.rb
583
613
  - lib/ddtrace/workers/async.rb
584
- - lib/ddtrace/workers/loop.rb
614
+ - lib/ddtrace/workers/interval_loop.rb
585
615
  - lib/ddtrace/workers/polling.rb
586
616
  - lib/ddtrace/workers/queue.rb
587
617
  - lib/ddtrace/workers/runtime_metrics.rb
@@ -1,67 +0,0 @@
1
- # typed: true
2
- module Datadog
3
- module Profiling
4
- module Ext
5
- # Monkey patches Ruby's `Thread` with our `Ext::CThread` to enable CPU-time profiling
6
- module CPU
7
- # We cannot apply our CPU extension if a broken rollbar is around because that can cause customer apps to fail
8
- # with a SystemStackError: stack level too deep.
9
- #
10
- # This occurs whenever our extensions to Thread are applied BEFORE rollbar applies its own. This happens
11
- # because a loop forms: our extension tries to call Thread#initialize, but it's intercepted by rollbar, which
12
- # then tries to call the original Thread#initialize as well, but instead alls our extension, leading to stack
13
- # exhaustion.
14
- #
15
- # See https://github.com/rollbar/rollbar-gem/pull/1018 for more details on the issue
16
- ROLLBAR_INCOMPATIBLE_VERSIONS = Gem::Requirement.new('<= 3.1.1')
17
-
18
- def self.supported?
19
- unsupported_reason.nil?
20
- end
21
-
22
- def self.apply!
23
- return false unless supported?
24
-
25
- # Applying CThread to Thread will ensure any new threads
26
- # will provide a thread/clock ID for CPU timing.
27
- require 'ddtrace/profiling/ext/cthread'
28
- ::Thread.prepend(Profiling::Ext::CThread)
29
- ::Thread.singleton_class.prepend(Datadog::Profiling::Ext::WrapThreadStartFork)
30
- end
31
-
32
- def self.unsupported_reason
33
- # NOTE: Only the first matching reason is returned, so try to keep a nice order on reasons -- e.g. tell users
34
- # first that they can't use this on macOS before telling them that they have the wrong ffi version
35
-
36
- if RUBY_ENGINE == 'jruby'
37
- 'JRuby is not supported'
38
- elsif RUBY_PLATFORM.include?('darwin')
39
- 'Feature requires Linux; macOS is not supported'
40
- elsif RUBY_PLATFORM =~ /(mswin|mingw)/
41
- 'Feature requires Linux; Windows is not supported'
42
- elsif !RUBY_PLATFORM.include?('linux')
43
- "Feature requires Linux; #{RUBY_PLATFORM} is not supported"
44
- elsif Gem::Specification.find_all_by_name('rollbar', ROLLBAR_INCOMPATIBLE_VERSIONS).any?
45
- 'You have an incompatible rollbar gem version installed; ensure that you have rollbar >= 3.1.2 by ' \
46
- "adding `gem 'rollbar', '>= 3.1.2'` to your Gemfile or gems.rb file. " \
47
- 'See https://github.com/rollbar/rollbar-gem/pull/1018 for details'
48
- elsif Gem::Specification.find_all_by_name('logging').any? && logging_inherit_context_enabled?
49
- 'The `logging` gem is installed and its thread inherit context feature is enabled. ' \
50
- "Please add LOGGING_INHERIT_CONTEXT=false to your application's environment variables to disable the " \
51
- 'conflicting `logging` gem feature. ' \
52
- 'See https://github.com/TwP/logging/pull/230 for details'
53
- end
54
- end
55
-
56
- private_class_method def self.logging_inherit_context_enabled?
57
- # The logging gem provides a mechanism to disable the conflicting behavior, see
58
- # https://github.com/TwP/logging/blob/ae9872d093833b2a5a34cbe1faa4e895a81f6845/lib/logging/diagnostic_context.rb#L418
59
- # Here we check if the behavior is enabled
60
- inherit_context_configuration = ENV['LOGGING_INHERIT_CONTEXT']
61
-
62
- inherit_context_configuration.nil? || !%w[false no 0].include?(inherit_context_configuration.downcase)
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,156 +0,0 @@
1
- # typed: false
2
- require 'ffi'
3
-
4
- module Datadog
5
- module Profiling
6
- module Ext
7
- # C-struct for retrieving clock ID from pthread
8
- class CClockId < FFI::Struct
9
- layout :value, :int
10
- end
11
-
12
- # Enables interfacing with pthread via FFI
13
- module NativePthread
14
- extend FFI::Library
15
- ffi_lib ['pthread', 'libpthread.so.0']
16
- attach_function :pthread_self, [], :ulong
17
- attach_function :pthread_getcpuclockid, [:ulong, CClockId], :int
18
-
19
- # NOTE: Only returns thread ID for thread that evaluates this call.
20
- # a.k.a. evaluating `get_pthread_thread_id(thread_a)` from within
21
- # `thread_b` will return `thread_b`'s thread ID, not `thread_a`'s.
22
- def self.get_pthread_thread_id(thread)
23
- return unless ::Thread.current == thread
24
-
25
- pthread_self
26
- end
27
-
28
- def self.get_clock_id(thread, pthread_id)
29
- return unless ::Thread.current == thread && pthread_id
30
-
31
- clock = CClockId.new
32
- clock[:value] = 0
33
- pthread_getcpuclockid(pthread_id, clock).zero? ? clock[:value] : nil
34
- end
35
- end
36
-
37
- # Extension used to enable CPU-time profiling via use of pthread's `getcpuclockid`.
38
- module CThread
39
- def self.prepended(base)
40
- # Threads that have already been created, will not have resolved
41
- # a thread/clock ID. This is because these IDs can only be resolved
42
- # from within the thread's execution context, which we do not control.
43
- #
44
- # We can mitigate this for the current thread via #update_native_ids,
45
- # since we are currently running within its execution context. We cannot
46
- # do this for any other threads that may have been created already.
47
- # (This is why it's important that CThread is applied before anything else runs.)
48
- base.current.send(:update_native_ids) if base.current.is_a?(CThread)
49
- end
50
-
51
- # Process::Waiter crash workaround:
52
- #
53
- # This is a workaround for a Ruby VM segfault (usually something like
54
- # "[BUG] Segmentation fault at 0x0000000000000008") in the affected Ruby versions.
55
- # See https://bugs.ruby-lang.org/issues/17807 and the regression tests added to this module's specs for details.
56
- #
57
- # In those Ruby versions, there's a very special subclass of `Thread` called `Process::Waiter` that causes VM
58
- # crashes whenever something tries to read its instance variables. This subclass of thread only shows up when
59
- # the `Process.detach` API gets used.
60
- # In this module's specs you can find crash regression tests that include a way of reproducing it.
61
- #
62
- # The workaround is to use `defined?` to check first if the instance variable exists. This seems to be fine
63
- # with Ruby.
64
- # Note that this crash doesn't affect `@foo ||=` nor instance variable writes (after the first write ever of any
65
- # instance variable on a `Process::Waiter`, then further reads and writes to that or any other instance are OK;
66
- # it looks like there's some lazily-created structure that is missing and did not get created).
67
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') &&
68
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
69
- attr_reader :pthread_thread_id
70
- else
71
- def pthread_thread_id
72
- defined?(@pthread_thread_id) && @pthread_thread_id
73
- end
74
- end
75
-
76
- def initialize(*args)
77
- @pid = ::Process.pid
78
- @pthread_thread_id = nil
79
- @clock_id = nil
80
-
81
- # Wrap the work block with our own
82
- # so we can retrieve the native thread ID within the thread's context.
83
- wrapped_block = proc do |*t_args|
84
- # Set native thread ID & clock ID
85
- update_native_ids
86
- yield(*t_args)
87
- end
88
- wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
89
-
90
- super(*args, &wrapped_block)
91
- end
92
- ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
93
-
94
- def cpu_time(unit = :float_second)
95
- ::Process.clock_gettime(clock_id, unit) if clock_id
96
- end
97
-
98
- def cpu_time_instrumentation_installed?
99
- # If this thread was started before this module was added to Thread OR if something caused the initialize
100
- # method above not to be properly called on new threads, this instance variable is never defined (never set to
101
- # any value at all, including nil).
102
- #
103
- # Thus, we can use @clock_id as a canary to detect a thread that has missing instrumentation, because we
104
- # know that in initialize above we always set this variable to nil.
105
- defined?(@clock_id) != nil
106
- end
107
-
108
- private
109
-
110
- def clock_id
111
- update_native_ids if forked?
112
- defined?(@clock_id) && @clock_id
113
- end
114
-
115
- def forked?
116
- ::Process.pid != (@pid ||= nil)
117
- end
118
-
119
- def update_native_ids
120
- # Can only resolve if invoked from same thread
121
- return unless ::Thread.current == self
122
-
123
- @pid = ::Process.pid
124
- @pthread_thread_id = NativePthread.get_pthread_thread_id(self)
125
- @clock_id = NativePthread.get_clock_id(self, @pthread_thread_id)
126
- end
127
- end
128
-
129
- # Threads in Ruby can be started by creating a new instance of `Thread` (or a subclass) OR by calling
130
- # `start`/`fork` on `Thread` (or a subclass).
131
- #
132
- # This module intercepts calls to `start`/`fork`, ensuring that the `update_native_ids` operation is correctly
133
- # called once the new thread starts.
134
- #
135
- # Note that unlike CThread above, this module should be prepended to the `Thread`'s singleton class, not to
136
- # the class.
137
- module WrapThreadStartFork
138
- def start(*args)
139
- # Wrap the work block with our own
140
- # so we can retrieve the native thread ID within the thread's context.
141
- wrapped_block = proc do |*t_args|
142
- # Set native thread ID & clock ID
143
- ::Thread.current.send(:update_native_ids)
144
- yield(*t_args)
145
- end
146
- wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
147
-
148
- super(*args, &wrapped_block)
149
- end
150
- ruby2_keywords :start if respond_to?(:ruby2_keywords, true)
151
-
152
- alias fork start
153
- end
154
- end
155
- end
156
- end