datadog 2.0.0 → 2.2.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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -2
  3. data/README.md +1 -1
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +19 -1
  5. data/ext/datadog_profiling_native_extension/collectors_stack.c +41 -0
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +1 -1
  7. data/ext/datadog_profiling_native_extension/crashtracker.c +1 -1
  8. data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
  9. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +47 -1
  10. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
  11. data/ext/datadog_profiling_native_extension/stack_recorder.c +13 -6
  12. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
  13. data/lib/datadog/appsec/configuration/settings.rb +5 -0
  14. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -1
  15. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
  16. data/lib/datadog/appsec/extensions.rb +1 -0
  17. data/lib/datadog/core/configuration/components.rb +6 -3
  18. data/lib/datadog/core/configuration/ext.rb +1 -0
  19. data/lib/datadog/core/configuration/option.rb +21 -14
  20. data/lib/datadog/core/configuration/options.rb +5 -1
  21. data/lib/datadog/core/configuration/settings.rb +68 -5
  22. data/lib/datadog/core/configuration.rb +3 -17
  23. data/lib/datadog/core/deprecations.rb +58 -0
  24. data/lib/datadog/core/environment/ext.rb +2 -0
  25. data/lib/datadog/core/environment/yjit.rb +5 -0
  26. data/lib/datadog/core/runtime/ext.rb +2 -0
  27. data/lib/datadog/core/runtime/metrics.rb +6 -0
  28. data/lib/datadog/core/telemetry/component.rb +107 -0
  29. data/lib/datadog/core/telemetry/event.rb +124 -31
  30. data/lib/datadog/core/telemetry/ext.rb +2 -0
  31. data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
  32. data/lib/datadog/core/telemetry/metric.rb +167 -0
  33. data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
  34. data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
  35. data/lib/datadog/core/telemetry/request.rb +1 -1
  36. data/lib/datadog/core/telemetry/worker.rb +173 -0
  37. data/lib/datadog/core/utils/only_once_successful.rb +76 -0
  38. data/lib/datadog/core.rb +2 -19
  39. data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
  40. data/lib/datadog/opentelemetry/sdk/span_processor.rb +5 -2
  41. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -5
  42. data/lib/datadog/profiling/component.rb +18 -1
  43. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
  44. data/lib/datadog/profiling.rb +1 -0
  45. data/lib/datadog/tracing/configuration/ext.rb +7 -0
  46. data/lib/datadog/tracing/configuration/settings.rb +52 -3
  47. data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
  48. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
  49. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
  50. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
  51. data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
  52. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
  53. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
  54. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
  55. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  56. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  57. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  58. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  59. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  60. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  61. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  62. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  63. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  64. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  65. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
  66. data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
  67. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
  68. data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
  69. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
  70. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
  71. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
  72. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
  73. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
  74. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
  75. data/lib/datadog/tracing/contrib/analytics.rb +5 -0
  76. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
  77. data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
  78. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
  79. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +25 -0
  80. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
  81. data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
  82. data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
  83. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
  84. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
  85. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
  86. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
  87. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
  88. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
  89. data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
  90. data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
  91. data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
  92. data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
  93. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  94. data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
  95. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  96. data/lib/datadog/tracing/distributed/propagation.rb +39 -4
  97. data/lib/datadog/tracing/distributed/trace_context.rb +5 -3
  98. data/lib/datadog/tracing/metadata/ext.rb +1 -0
  99. data/lib/datadog/tracing/span_operation.rb +3 -2
  100. data/lib/datadog/tracing/trace_operation.rb +7 -3
  101. data/lib/datadog/tracing/trace_segment.rb +4 -1
  102. data/lib/datadog/tracing/tracer.rb +9 -2
  103. data/lib/datadog/tracing.rb +5 -1
  104. data/lib/datadog/version.rb +2 -2
  105. metadata +21 -8
  106. data/lib/datadog/core/telemetry/client.rb +0 -95
  107. data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
@@ -92,25 +92,38 @@ module Datadog
92
92
 
93
93
  seen_files << file_path
94
94
 
95
- _, found_library = libraries_by_path.find { |library_path, _| file_path.start_with?(library_path) }
96
- seen_libraries << found_library if found_library
95
+ # NOTE: Don't use .find, it allocates a lot more memory (see commit that added this note for details)
96
+ libraries_by_path.any? do |library_path, library|
97
+ seen_libraries << library if file_path.start_with?(library_path)
98
+ end
97
99
  end
98
100
  end
99
101
 
100
102
  # Represents metadata we have for a ruby gem
103
+ #
104
+ # Important note: This class gets encoded to JSON with the built-in JSON gem. But, we've found that in some
105
+ # buggy cases, some Ruby gems monkey patch the built-in JSON gem and forget to call #to_json, and instead
106
+ # encode this class instance-field-by-instance-field.
107
+ #
108
+ # Thus, this class was setup to match the JSON output. Take this into consideration if you are adding new
109
+ # fields. (Also, we have a spec for this)
101
110
  class Library
102
- attr_reader :kind, :name, :version, :path
111
+ attr_reader :kind, :name, :version
103
112
 
104
113
  def initialize(kind:, name:, version:, path:)
105
114
  @kind = kind.freeze
106
115
  @name = name.dup.freeze
107
116
  @version = version.to_s.dup.freeze
108
- @path = path.dup.freeze
117
+ @paths = [path.dup.freeze].freeze
109
118
  freeze
110
119
  end
111
120
 
112
121
  def to_json(arg = nil)
113
- { kind: @kind, name: @name, version: @version, paths: [@path] }.to_json(arg)
122
+ { kind: @kind, name: @name, version: @version, paths: @paths }.to_json(arg)
123
+ end
124
+
125
+ def path
126
+ @paths.first
114
127
  end
115
128
  end
116
129
  end
@@ -75,6 +75,10 @@ module Datadog
75
75
  crashtracker = build_crashtracker(settings, transport)
76
76
  profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler, optional_crashtracker: crashtracker)
77
77
 
78
+ if dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
79
+ Datadog::Profiling::Ext::DirMonkeyPatches.apply!
80
+ end
81
+
78
82
  [profiler, { profiling_enabled: true }]
79
83
  end
80
84
 
@@ -397,8 +401,12 @@ module Datadog
397
401
 
398
402
  # See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
399
403
  private_class_method def self.incompatible_passenger_version?
404
+ first_compatible_version = Gem::Version.new('6.0.19')
405
+
400
406
  if Gem.loaded_specs['passenger']
401
- Gem.loaded_specs['passenger'].version < Gem::Version.new('6.0.19')
407
+ Gem.loaded_specs['passenger'].version < first_compatible_version
408
+ elsif defined?(PhusionPassenger::VERSION_STRING)
409
+ Gem::Version.new(PhusionPassenger::VERSION_STRING) < first_compatible_version
402
410
  else
403
411
  true
404
412
  end
@@ -445,6 +453,15 @@ module Datadog
445
453
  libmysqlclient_version < Gem::Version.new('5.0.0') &&
446
454
  header_version >= Gem::Version.new('10.0.0'))
447
455
  end
456
+
457
+ private_class_method def self.dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
458
+ return false if no_signals_workaround_enabled
459
+
460
+ # NOTE: In the future this method will evolve to check for Ruby versions affected and not apply the workaround
461
+ # when it's not needed but currently all known Ruby versions are affected.
462
+
463
+ settings.profiling.advanced.dir_interruption_workaround_enabled
464
+ end
448
465
  end
449
466
  end
450
467
  end
@@ -0,0 +1,410 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Profiling
5
+ # Monkey patches needed for profiler features and compatibility
6
+ module Ext
7
+ # All Ruby versions as of this writing have bugs in the dir class implementation, causing issues such as
8
+ # https://github.com/DataDog/dd-trace-rb/issues/3450 .
9
+ # See also https://bugs.ruby-lang.org/issues/20586 for more details.
10
+ #
11
+ # This monkey patch for the Ruby `Dir` class works around these bugs for affected Ruby versions by temporarily
12
+ # blocking the profiler from interrupting system calls.
13
+ #
14
+ # A lot of these APIs do very similar things -- they're provided by Ruby as helpers so users don't need to keep
15
+ # reimplementing them but share the same underlying buggy code. And so our monkey patches are a bit repetitive
16
+ # as well.
17
+ # We don't DRY out this file to have minimal overhead.
18
+ #
19
+ # These monkey patches are applied by the profiler when the "dir_interruption_workaround_enabled" setting is
20
+ # enabled. See the profiling settings for more detail.
21
+ module DirMonkeyPatches
22
+ def self.apply!
23
+ ::Dir.singleton_class.prepend(Datadog::Profiling::Ext::DirClassMonkeyPatches)
24
+ ::Dir.prepend(Datadog::Profiling::Ext::DirInstanceMonkeyPatches)
25
+
26
+ true
27
+ end
28
+ end
29
+
30
+ if RUBY_VERSION.start_with?('2.')
31
+ # Monkey patches for Dir.singleton_class (Ruby 2 version). See DirMonkeyPatches above for more details.
32
+ module DirClassMonkeyPatches
33
+ def [](*args, &block)
34
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
35
+ super
36
+ ensure
37
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
38
+ end
39
+
40
+ def children(*args, &block)
41
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
42
+ super
43
+ ensure
44
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
45
+ end
46
+
47
+ # NOTE: When wrapping methods that yield, it's OK if the `yield` raises an exception while signals are
48
+ # enabled. This is because:
49
+ # * We can call `_native_resume_signals` many times in a row, both because it's idempotent, as well as it's
50
+ # very low overhead (see benchmarks/profiler_hold_resume_interruptions.rb)
51
+ # * When an exception is being raised, the iteration will stop anyway, so there's no longer a concern of a
52
+ # signal causing Ruby to return an incorrect value
53
+ def each_child(*args, &block)
54
+ if block
55
+ begin
56
+ # <-- Begin critical region
57
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
58
+ super do |entry_name|
59
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
60
+ # <-- We're safe now while running customer code
61
+ yield entry_name
62
+ # <-- We'll go back to the Dir internals, critical region again
63
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
64
+ end
65
+ ensure
66
+ # <-- End critical region
67
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
68
+ end
69
+ else
70
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
71
+ # other branch once it gets going.
72
+ super
73
+ end
74
+ end
75
+
76
+ def empty?(*args, &block)
77
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
78
+ super
79
+ ensure
80
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
81
+ end
82
+
83
+ def entries(*args, &block)
84
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
85
+ super
86
+ ensure
87
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
88
+ end
89
+
90
+ # See note on methods that yield above.
91
+ def foreach(*args, &block)
92
+ if block
93
+ begin
94
+ # <-- Begin critical region
95
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
96
+ super do |entry_name|
97
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
98
+ # <-- We're safe now while running customer code
99
+ yield entry_name
100
+ # <-- We'll go back to the Dir internals, critical region again
101
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
102
+ end
103
+ ensure
104
+ # <-- End critical region
105
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
106
+ end
107
+ else
108
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
109
+ # other branch once it gets going.
110
+ super
111
+ end
112
+ end
113
+
114
+ # See note on methods that yield above.
115
+ def glob(*args, &block)
116
+ if block
117
+ begin
118
+ # <-- Begin critical region
119
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
120
+ super do |entry_name|
121
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
122
+ # <-- We're safe now while running customer code
123
+ yield entry_name
124
+ # <-- We'll go back to the Dir internals, critical region again
125
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
126
+ end
127
+ ensure
128
+ # <-- End critical region
129
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
130
+ end
131
+ else
132
+ begin
133
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
134
+ super
135
+ ensure
136
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
137
+ end
138
+ end
139
+ end
140
+
141
+ def home(*args, &block)
142
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
143
+ super
144
+ ensure
145
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
146
+ end
147
+ end
148
+ else
149
+ # Monkey patches for Dir.singleton_class (Ruby 3 version). See DirMonkeyPatches above for more details.
150
+ module DirClassMonkeyPatches
151
+ def [](*args, **kwargs, &block)
152
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
153
+ super
154
+ ensure
155
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
156
+ end
157
+
158
+ def children(*args, **kwargs, &block)
159
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
160
+ super
161
+ ensure
162
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
163
+ end
164
+
165
+ # See note on methods that yield above.
166
+ def each_child(*args, **kwargs, &block)
167
+ if block
168
+ begin
169
+ # <-- Begin critical region
170
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
171
+ super do |entry_name|
172
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
173
+ # <-- We're safe now while running customer code
174
+ yield entry_name
175
+ # <-- We'll go back to the Dir internals, critical region again
176
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
177
+ end
178
+ ensure
179
+ # <-- End critical region
180
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
181
+ end
182
+ else
183
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
184
+ # other branch once it gets going.
185
+ super
186
+ end
187
+ end
188
+
189
+ def empty?(*args, **kwargs, &block)
190
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
191
+ super
192
+ ensure
193
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
194
+ end
195
+
196
+ def entries(*args, **kwargs, &block)
197
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
198
+ super
199
+ ensure
200
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
201
+ end
202
+
203
+ # See note on methods that yield above.
204
+ def foreach(*args, **kwargs, &block)
205
+ if block
206
+ begin
207
+ # <-- Begin critical region
208
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
209
+ super do |entry_name|
210
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
211
+ # <-- We're safe now while running customer code
212
+ yield entry_name
213
+ # <-- We'll go back to the Dir internals, critical region again
214
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
215
+ end
216
+ ensure
217
+ # <-- End critical region
218
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
219
+ end
220
+ else
221
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
222
+ # other branch once it gets going.
223
+ super
224
+ end
225
+ end
226
+
227
+ # See note on methods that yield above.
228
+ def glob(*args, **kwargs, &block)
229
+ if block
230
+ begin
231
+ # <-- Begin critical region
232
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
233
+ super do |entry_name|
234
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
235
+ # <-- We're safe now while running customer code
236
+ yield entry_name
237
+ # <-- We'll go back to the Dir internals, critical region again
238
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
239
+ end
240
+ ensure
241
+ # <-- End critical region
242
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
243
+ end
244
+ else
245
+ begin
246
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
247
+ super
248
+ ensure
249
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
250
+ end
251
+ end
252
+ end
253
+
254
+ def home(*args, **kwargs, &block)
255
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
256
+ super
257
+ ensure
258
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
259
+ end
260
+ end
261
+ end
262
+
263
+ if RUBY_VERSION.start_with?('2.')
264
+ # Monkey patches for Dir (Ruby 2 version). See DirMonkeyPatches above for more details.
265
+ module DirInstanceMonkeyPatches
266
+ # See note on methods that yield above.
267
+ def each(*args, &block)
268
+ if block
269
+ begin
270
+ # <-- Begin critical region
271
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
272
+ super do |entry_name|
273
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
274
+ # <-- We're safe now while running customer code
275
+ yield entry_name
276
+ # <-- We'll go back to the Dir internals, critical region again
277
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
278
+ end
279
+ ensure
280
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals # <-- End critical region
281
+ end
282
+ else
283
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
284
+ # other branch once it gets going.
285
+ super
286
+ end
287
+ end
288
+
289
+ unless RUBY_VERSION.start_with?('2.5.') # This is Ruby 2.6+
290
+ # See note on methods that yield above.
291
+ def each_child(*args, &block)
292
+ if block
293
+ begin
294
+ # <-- Begin critical region
295
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
296
+ super do |entry_name|
297
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
298
+ # <-- We're safe now while running customer code
299
+ yield entry_name
300
+ # <-- We'll go back to the Dir internals, critical region again
301
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
302
+ end
303
+ ensure
304
+ # <-- End critical region
305
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
306
+ end
307
+ else
308
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
309
+ # other branch once it gets going.
310
+ super
311
+ end
312
+ end
313
+
314
+ def children(*args, &block)
315
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
316
+ super
317
+ ensure
318
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
319
+ end
320
+ end
321
+
322
+ def tell(*args, &block)
323
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
324
+ super
325
+ ensure
326
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
327
+ end
328
+
329
+ def pos(*args, &block)
330
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
331
+ super
332
+ ensure
333
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
334
+ end
335
+ end
336
+ else
337
+ # Monkey patches for Dir (Ruby 3 version). See DirMonkeyPatches above for more details.
338
+ module DirInstanceMonkeyPatches
339
+ # See note on methods that yield above.
340
+ def each(*args, **kwargs, &block)
341
+ if block
342
+ begin
343
+ # <-- Begin critical region
344
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
345
+ super do |entry_name|
346
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
347
+ # <-- We're safe now while running customer code
348
+ yield entry_name
349
+ # <-- We'll go back to the Dir internals, critical region again
350
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
351
+ end
352
+ ensure
353
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals # <-- End critical region
354
+ end
355
+ else
356
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
357
+ # other branch once it gets going.
358
+ super
359
+ end
360
+ end
361
+
362
+ # See note on methods that yield above.
363
+ def each_child(*args, **kwargs, &block)
364
+ if block
365
+ begin
366
+ # <-- Begin critical region
367
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
368
+ super do |entry_name|
369
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
370
+ # <-- We're safe now while running customer code
371
+ yield entry_name
372
+ # <-- We'll go back to the Dir internals, critical region again
373
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
374
+ end
375
+ ensure
376
+ # <-- End critical region
377
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
378
+ end
379
+ else
380
+ # This returns an enumerator. We don't want/need to intercede here, the enumerator will eventually call the
381
+ # other branch once it gets going.
382
+ super
383
+ end
384
+ end
385
+
386
+ def children(*args, **kwargs, &block)
387
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
388
+ super
389
+ ensure
390
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
391
+ end
392
+
393
+ def tell(*args, **kwargs, &block)
394
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
395
+ super
396
+ ensure
397
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
398
+ end
399
+
400
+ def pos(*args, **kwargs, &block)
401
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
402
+ super
403
+ ensure
404
+ Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_resume_signals
405
+ end
406
+ end
407
+ end
408
+ end
409
+ end
410
+ end
@@ -136,6 +136,7 @@ module Datadog
136
136
  return false unless supported?
137
137
 
138
138
  require_relative 'profiling/ext/forking'
139
+ require_relative 'profiling/ext/dir_monkey_patches'
139
140
  require_relative 'profiling/collectors/info'
140
141
  require_relative 'profiling/collectors/code_provenance'
141
142
  require_relative 'profiling/collectors/cpu_and_wall_time_worker'
@@ -9,6 +9,7 @@ module Datadog
9
9
  # e.g. Env vars, default values, enums, etc...
10
10
  module Ext
11
11
  ENV_ENABLED = 'DD_TRACE_ENABLED'
12
+ ENV_OTEL_TRACES_EXPORTER = 'OTEL_TRACES_EXPORTER'
12
13
  ENV_HEADER_TAGS = 'DD_TRACE_HEADER_TAGS'
13
14
  ENV_TRACE_ID_128_BIT_GENERATION_ENABLED = 'DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED'
14
15
 
@@ -39,10 +40,14 @@ module Datadog
39
40
  # W3C Trace Context
40
41
  PROPAGATION_STYLE_TRACE_CONTEXT = 'tracecontext'
41
42
 
43
+ PROPAGATION_STYLE_SUPPORTED = [PROPAGATION_STYLE_DATADOG, PROPAGATION_STYLE_B3_MULTI_HEADER,
44
+ PROPAGATION_STYLE_B3_SINGLE_HEADER, PROPAGATION_STYLE_TRACE_CONTEXT].freeze
45
+
42
46
  # Sets both extract and inject propagation style tho the provided value.
43
47
  # Has lower precedence than `DD_TRACE_PROPAGATION_STYLE_INJECT` or
44
48
  # `DD_TRACE_PROPAGATION_STYLE_EXTRACT`.
45
49
  ENV_PROPAGATION_STYLE = 'DD_TRACE_PROPAGATION_STYLE'
50
+ ENV_OTEL_PROPAGATION_STYLE = 'OTEL_PROPAGATORS'
46
51
 
47
52
  ENV_PROPAGATION_STYLE_INJECT = 'DD_TRACE_PROPAGATION_STYLE_INJECT'
48
53
 
@@ -68,6 +73,8 @@ module Datadog
68
73
  ENV_SAMPLE_RATE = 'DD_TRACE_SAMPLE_RATE'
69
74
  ENV_RATE_LIMIT = 'DD_TRACE_RATE_LIMIT'
70
75
  ENV_RULES = 'DD_TRACE_SAMPLING_RULES'
76
+ ENV_OTEL_TRACES_SAMPLER = 'OTEL_TRACES_SAMPLER'
77
+ OTEL_TRACES_SAMPLER_ARG = 'OTEL_TRACES_SAMPLER_ARG'
71
78
 
72
79
  # @public_api
73
80
  module Span
@@ -13,6 +13,8 @@ module Datadog
13
13
  # rubocop:disable Metrics/BlockLength
14
14
  # rubocop:disable Metrics/MethodLength
15
15
  # rubocop:disable Layout/LineLength
16
+ # rubocop:disable Metrics/CyclomaticComplexity
17
+ # rubocop:disable Metrics/PerceivedComplexity
16
18
  module Settings
17
19
  def self.extended(base)
18
20
  base.class_eval do
@@ -89,7 +91,7 @@ module Datadog
89
91
  # @return [Array<String>]
90
92
  option :propagation_style do |o|
91
93
  o.type :array
92
- o.env Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE
94
+ o.env [Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE, Configuration::Ext::Distributed::ENV_OTEL_PROPAGATION_STYLE]
93
95
  o.default []
94
96
  o.after_set do |styles|
95
97
  next if styles.empty?
@@ -97,6 +99,14 @@ module Datadog
97
99
  # Make values case-insensitive
98
100
  styles.map!(&:downcase)
99
101
 
102
+ styles.select! do |s|
103
+ if Configuration::Ext::Distributed::PROPAGATION_STYLE_SUPPORTED.include?(s)
104
+ true
105
+ else
106
+ Datadog.logger.warn("Unsupported propagation style: #{s}")
107
+ false
108
+ end
109
+ end
100
110
  set_option(:propagation_style_extract, styles)
101
111
  set_option(:propagation_style_inject, styles)
102
112
  end
@@ -121,9 +131,23 @@ module Datadog
121
131
  # @default `DD_TRACE_ENABLED` environment variable, otherwise `true`
122
132
  # @return [Boolean]
123
133
  option :enabled do |o|
124
- o.env Tracing::Configuration::Ext::ENV_ENABLED
134
+ o.env [Tracing::Configuration::Ext::ENV_ENABLED, Tracing::Configuration::Ext::ENV_OTEL_TRACES_EXPORTER]
125
135
  o.default true
126
136
  o.type :bool
137
+ o.env_parser do |value|
138
+ value = value&.downcase
139
+ # Tracing is disabled when OTEL_TRACES_EXPORTER is none or
140
+ # DD_TRACE_ENABLED is 0 or false.
141
+ if ['none', 'false', '0'].include?(value)
142
+ false
143
+ # Tracing is enabled when DD_TRACE_ENABLED is true or 1
144
+ elsif ['true', '1'].include?(value)
145
+ true
146
+ else
147
+ Datadog.logger.warn("Unsupported value for exporting datadog traces: #{value}. Traces will be sent to Datadog.")
148
+ nil
149
+ end
150
+ end
127
151
  end
128
152
 
129
153
  # Comma-separated, case-insensitive list of header names that are reported in incoming and outgoing HTTP requests.
@@ -245,7 +269,30 @@ module Datadog
245
269
  # @return [Float, nil]
246
270
  option :default_rate do |o|
247
271
  o.type :float, nilable: true
248
- o.env Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE
272
+ o.env [Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE, Tracing::Configuration::Ext::Sampling::ENV_OTEL_TRACES_SAMPLER]
273
+ o.env_parser do |value|
274
+ # Parse the value as a float
275
+ next if value.nil?
276
+
277
+ value = value&.downcase
278
+ if ['always_on', 'always_off', 'traceidratio'].include?(value)
279
+ Datadog.logger.warn("The value '#{value}' is not yet supported. 'parentbased_#{value}' will be used instead.")
280
+ value = "parentbased_#{value}"
281
+ end
282
+ # OTEL_TRACES_SAMPLER can be set to always_on, always_off, traceidratio, and/or parentbased value.
283
+ # These values are mapped to a sample rate.
284
+ # DD_TRACE_SAMPLE_RATE sets the sample rate to float.
285
+ case value
286
+ when 'parentbased_always_on'
287
+ 1.0
288
+ when 'parentbased_always_off'
289
+ 0.0
290
+ when 'parentbased_traceidratio'
291
+ ENV.fetch(Tracing::Configuration::Ext::Sampling::OTEL_TRACES_SAMPLER_ARG, 1.0).to_f
292
+ else
293
+ value.to_f
294
+ end
295
+ end
249
296
  end
250
297
 
251
298
  # Rate limit for number of spans per second.
@@ -417,6 +464,8 @@ module Datadog
417
464
  # rubocop:enable Metrics/BlockLength
418
465
  # rubocop:enable Metrics/MethodLength
419
466
  # rubocop:enable Layout/LineLength
467
+ # rubocop:enable Metrics/CyclomaticComplexity
468
+ # rubocop:enable Metrics/PerceivedComplexity
420
469
  end
421
470
  end
422
471
  end
@@ -46,7 +46,7 @@ module Datadog
46
46
  module ClassMethods
47
47
  include Contrib::ActionCable::Event::ClassMethods
48
48
 
49
- def subscription(*args)
49
+ def subscription(*args, **kwargs)
50
50
  super.tap do |subscription|
51
51
  subscription.before_trace { ensure_clean_context! }
52
52
  end
@@ -34,7 +34,7 @@ module Datadog
34
34
  Tracing::Metadata::Ext::AppTypes::TYPE_WEB
35
35
  end
36
36
 
37
- def process(span, _event, _id, payload)
37
+ def on_start(span, _event, _id, payload)
38
38
  channel = payload[:broadcasting] # Channel has high cardinality
39
39
  span.service = configuration[:service_name] if configuration[:service_name]
40
40
  span.type = span_type
@@ -33,7 +33,7 @@ module Datadog
33
33
  Tracing::Metadata::Ext::AppTypes::TYPE_WEB
34
34
  end
35
35
 
36
- def process(span, _event, _id, payload)
36
+ def on_start(span, _event, _id, payload)
37
37
  channel_class = payload[:channel_class]
38
38
  action = payload[:action]
39
39
 
@@ -33,7 +33,7 @@ module Datadog
33
33
  Tracing::Metadata::Ext::AppTypes::TYPE_WEB
34
34
  end
35
35
 
36
- def process(span, _event, _id, payload)
36
+ def on_start(span, _event, _id, payload)
37
37
  channel_class = payload[:channel_class]
38
38
 
39
39
  span.service = configuration[:service_name] if configuration[:service_name]