datadog 2.41.0 → 2.42.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -2
  3. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +110 -61
  5. data/ext/datadog_profiling_native_extension/collectors_stack.c +11 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +141 -103
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +7 -3
  8. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -10
  9. data/ext/datadog_profiling_native_extension/extconf.rb +52 -93
  10. data/ext/datadog_profiling_native_extension/heap_recorder.c +338 -255
  11. data/ext/datadog_profiling_native_extension/heap_recorder.h +46 -31
  12. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -24
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +509 -440
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +15 -3
  15. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  16. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -79
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.h +0 -7
  18. data/ext/datadog_profiling_native_extension/stack_recorder.c +93 -61
  19. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -4
  20. data/ext/libdatadog_api/datadog_ruby_common.h +0 -10
  21. data/ext/libdatadog_api/di.c +10 -0
  22. data/ext/libdatadog_api/extconf.rb +3 -0
  23. data/ext/libdatadog_api/init.c +2 -0
  24. data/ext/libdatadog_api/otel_thread_context.c +232 -0
  25. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  26. data/ext/libdatadog_extconf_helpers.rb +1 -1
  27. data/lib/datadog/appsec/assets/blocked.html +1 -108
  28. data/lib/datadog/core/configuration/components.rb +1 -0
  29. data/lib/datadog/core/crashtracking/component.rb +5 -1
  30. data/lib/datadog/data_streams/pathway_context.rb +20 -22
  31. data/lib/datadog/data_streams/processor.rb +31 -0
  32. data/lib/datadog/di/instrumenter.rb +41 -1
  33. data/lib/datadog/di/logger.rb +2 -2
  34. data/lib/datadog/di/probe.rb +9 -1
  35. data/lib/datadog/di/probe_notification_builder.rb +1 -0
  36. data/lib/datadog/di/remote.rb +3 -3
  37. data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
  38. data/lib/datadog/open_feature/exposures/event.rb +10 -3
  39. data/lib/datadog/open_feature/ext.rb +19 -0
  40. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
  41. data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
  42. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
  43. data/lib/datadog/open_feature/native_evaluator.rb +33 -6
  44. data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
  45. data/lib/datadog/open_feature/provider.rb +11 -2
  46. data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
  47. data/lib/datadog/opentelemetry/trace.rb +3 -0
  48. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -0
  49. data/lib/datadog/profiling/collectors/thread_context.rb +0 -4
  50. data/lib/datadog/profiling/component.rb +8 -16
  51. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  52. data/lib/datadog/tracing/distributed/baggage.rb +0 -1
  53. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  54. data/lib/datadog/tracing/distributed/propagation.rb +3 -0
  55. data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
  56. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  57. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  58. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  59. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  60. data/lib/datadog/tracing/otel_thread_context.rb +30 -0
  61. data/lib/datadog/tracing/remote.rb +195 -27
  62. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  63. data/lib/datadog/tracing/trace_digest.rb +22 -4
  64. data/lib/datadog/tracing/trace_operation.rb +22 -10
  65. data/lib/datadog/tracing/tracer.rb +5 -5
  66. data/lib/datadog/version.rb +1 -1
  67. metadata +14 -8
  68. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
@@ -80,9 +80,9 @@ void heap_recorder_set_size_enabled(heap_recorder *heap_recorder, bool size_enab
80
80
  // Controls how many recordings will be ignored before committing a heap allocation and
81
81
  // the weight of the committed heap allocation.
82
82
  //
83
- // A value of 1 will effectively track all objects that are passed through
84
- // start/end_heap_allocation_recording pairs. A value of 10 will only track every 10th
85
- // object passed through such calls and its effective weight for the purposes of heap
83
+ // A value of 1 will effectively track all objects that are passed to
84
+ // `heap_recorder_record_allocation`. A value of 10 will only track every 10th
85
+ // object passed to it and its effective weight for the purposes of heap
86
86
  // profiling will be multiplied by 10.
87
87
  //
88
88
  // NOTE: Default is 1, i.e., track all heap allocation recordings.
@@ -94,45 +94,47 @@ void heap_recorder_set_sample_rate(heap_recorder *heap_recorder, int sample_rate
94
94
  // WARN: Assumes this gets called before profiler is reinitialized on the fork
95
95
  void heap_recorder_after_fork(heap_recorder *heap_recorder);
96
96
 
97
- // Start a heap allocation recording on the heap recorder for a new object.
97
+ // Record a heap allocation on the heap recorder.
98
98
  //
99
- // This heap allocation recording needs to be ended via ::end_heap_allocation_recording
100
- // before it will become fully committed and able to be iterated on.
99
+ // The recording is added to a pending list, and only becomes fully tracked and able to be iterated on once
100
+ // `heap_recorder_commit_recordings_may_lose_gvl` gets to it.
101
101
  //
102
- // @param new_obj
102
+ // @param new_object
103
103
  // The newly allocated Ruby object/value.
104
104
  // @param weight
105
105
  // The sampling weight of this object.
106
- //
107
- // WARN: It needs to be paired with a ::end_heap_allocation_recording call.
108
- // Returns needs_after_allocation: true whenever the pending_recordings buffer goes from empty to non-empty and thus
109
- // a after_sample callback is required to flush it
110
- bool start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class);
111
-
112
- // End a previously started heap allocation recording on the heap recorder.
113
- //
114
- // It is at this point that an allocated object will become fully tracked and able to be iterated on.
115
- //
116
- // @param locations The stacktrace representing the location of the allocation.
117
- //
118
- // WARN: It is illegal to call this without previously having called ::start_heap_allocation_recording.
119
- // WARN: This method rescues exceptions with `rb_protect`, returning the exception state integer for the caller to handle.
120
- __attribute__((warn_unused_result))
121
- int end_heap_allocation_recording_with_rb_protect(heap_recorder *heap_recorder, ddog_prof_Slice_Location locations);
106
+ // @param alloc_class
107
+ // The class of the newly allocated object.
108
+ // @param locations
109
+ // The stacktrace representing the location of the allocation.
110
+ // @param needs_commit
111
+ // Out: set to whether there are pending recordings, and thus a `heap_recorder_commit_recordings_may_lose_gvl`
112
+ // callback is needed to commit them. Note that we answer this on every call, including the ones where we don't
113
+ // record anything: asking again is how we recover if a commit gets skipped for any reason.
114
+ //
115
+ // WARN: This gets called from inside the RUBY_INTERNAL_EVENT_NEWOBJ tracepoint, so it neither allocates in the Ruby
116
+ // heap nor releases the GVL (https://github.com/DataDog/dd-trace-rb/pull/4240).
117
+ void heap_recorder_record_allocation(
118
+ heap_recorder *heap_recorder,
119
+ VALUE new_object,
120
+ unsigned int weight,
121
+ ddog_CharSlice alloc_class,
122
+ ddog_prof_Slice_Location locations,
123
+ bool *needs_commit
124
+ );
122
125
 
123
126
  // Update the heap recorder, **checking young objects only**. The idea here is to align with GC: most young objects never
124
127
  // survive enough GC generations, and thus periodically running this method reduces memory usage (we get rid of
125
128
  // these objects quicker) and hopefully reduces tail latency (because there's less objects at serialization time to check).
126
129
  void heap_recorder_update_young_objects(heap_recorder *heap_recorder);
127
130
 
128
- // Finalize any pending heap allocation recordings by getting their object IDs.
131
+ // Commit any pending heap allocation recordings by taking a weak reference to their objects.
129
132
  // This should be called via a postponed job, after the on_newobj_event has completed.
130
- // Raises an exception if a fatal error occurs (e.g., bignum object ID detected).
131
- void heap_recorder_finalize_pending_recordings(heap_recorder *heap_recorder);
133
+ void heap_recorder_commit_recordings_may_lose_gvl(heap_recorder *heap_recorder);
132
134
 
133
- // Mark pending recordings to prevent GC from collecting the objects
134
- // while they're waiting for the recordings to be finalized.
135
- void heap_recorder_mark_pending_recordings(heap_recorder *heap_recorder);
135
+ // Mark the Ruby objects the heap recorder holds on to: the objects of any pending recordings (so that GC does not
136
+ // collect them while they're waiting to be committed) and the weak map itself.
137
+ void heap_recorder_mark(heap_recorder *heap_recorder);
136
138
 
137
139
  // Update the heap recorder to reflect the latest state of the VM and prepare internal structures
138
140
  // for efficient iteration.
@@ -179,10 +181,23 @@ VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder);
179
181
  // troubleshoot issues such as unexpected test failures.
180
182
  VALUE heap_recorder_testonly_debug(heap_recorder *heap_recorder);
181
183
 
182
- // Check if a given object_id is being tracked or not
183
- VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VALUE obj_id);
184
+ // Check if a given record_id is being tracked or not
185
+ VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, long record_id);
186
+
187
+ // Returns the record id being used to track the given (still alive) object, or nil if it's not being tracked (which
188
+ // includes the case where heap profiling is disabled). This lets tests hold on to a record id and keep asking about
189
+ // it after the object itself is gone.
190
+ // NOTE: This is a linear scan over the tracked objects; fine for the small numbers tests track.
191
+ VALUE heap_recorder_testonly_record_id_for(heap_recorder *heap_recorder, VALUE obj);
184
192
 
185
193
  // Used to ensure that a GC actually triggers an update of the objects
186
194
  void heap_recorder_testonly_reset_last_update(heap_recorder *heap_recorder);
187
195
 
196
+ // Exhausts the usable record ids, so that all subsequent heap recordings raise (the id keeps being incremented, so
197
+ // there's no going back). Used to test that our callers correctly handle a heap recorder that raises in the middle of
198
+ // recording a sample.
199
+ //
200
+ // WARN: This should only be used for testing.
201
+ void heap_recorder_testonly_exhaust_record_ids(heap_recorder *heap_recorder);
202
+
188
203
  void heap_recorder_testonly_benchmark_intern(heap_recorder *heap_recorder, ddog_CharSlice string, int times, bool use_all);
@@ -9,9 +9,6 @@ module Datadog
9
9
  # Can be set to force rubygems to fail gem installation when profiling extension could not be built
10
10
  ENV_FAIL_INSTALL_IF_MISSING_EXTENSION = "DD_PROFILING_FAIL_INSTALL_IF_MISSING_EXTENSION"
11
11
 
12
- # The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on datadog-ruby_core_source
13
- CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?("2.6", "2.7", "3.0.", "3.1.", "3.2.")
14
-
15
12
  def self.fail_install_if_missing_extension?
16
13
  ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == "true"
17
14
  end
@@ -35,7 +32,6 @@ module Datadog
35
32
  on_macos? ||
36
33
  on_unknown_os? ||
37
34
  on_unsupported_cpu_arch? ||
38
- expected_to_use_mjit_but_mjit_is_disabled? ||
39
35
  libdatadog_not_available? ||
40
36
  libdatadog_not_usable?
41
37
  end
@@ -97,13 +93,6 @@ module Datadog
97
93
  suggested: CONTACT_SUPPORT,
98
94
  )
99
95
 
100
- # Validation for this check is done in extconf.rb because it relies on mkmf
101
- COMPILATION_BROKEN = explain_issue(
102
- "compilation of the Ruby VM just-in-time header failed.",
103
- "Your C compiler or Ruby VM just-in-time compiler seem to be broken.",
104
- suggested: CONTACT_SUPPORT,
105
- )
106
-
107
96
  # Validation for this check is done in extconf.rb because it relies on mkmf
108
97
  COMPILER_ATOMIC_MISSING = explain_issue(
109
98
  "your C compiler is missing support for the <stdatomic.h> header.",
@@ -187,19 +176,6 @@ module Datadog
187
176
  architecture_not_supported unless RUBY_PLATFORM.start_with?("x86_64", "aarch64", "arm64")
188
177
  end
189
178
 
190
- # On some Rubies, we require the mjit header to be present. If Ruby was installed without MJIT support, we also skip
191
- # building the extension.
192
- private_class_method def self.expected_to_use_mjit_but_mjit_is_disabled?
193
- ruby_without_mjit = explain_issue(
194
- "your Ruby has been compiled without JIT support (--disable-jit-support).",
195
- "The profiling native extension requires a Ruby compiled with JIT support,",
196
- "even if the JIT is not in use by the application itself.",
197
- suggested: CONTACT_SUPPORT,
198
- )
199
-
200
- ruby_without_mjit if CAN_USE_MJIT_HEADER && RbConfig::CONFIG["MJIT_SUPPORT"] != "yes"
201
- end
202
-
203
179
  private_class_method def self.libdatadog_not_available?
204
180
  Datadog::LibdatadogExtconfHelpers.try_loading_libdatadog do |exception|
205
181
  explain_issue(