datadog 2.43.0 → 2.45.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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +136 -132
  4. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
  5. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
  6. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +19 -20
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
  9. data/ext/datadog_profiling_native_extension/collectors_stack.h +1 -1
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +146 -109
  11. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -2
  12. data/ext/datadog_profiling_native_extension/extconf.rb +6 -2
  13. data/ext/datadog_profiling_native_extension/heap_recorder.c +2 -2
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +122 -53
  15. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -2
  16. data/ext/datadog_profiling_native_extension/profiling.c +22 -23
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.c +3 -1
  18. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -0
  19. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +0 -2
  20. data/ext/datadog_profiling_native_extension/stack_recorder.c +10 -28
  21. data/ext/datadog_profiling_native_extension/stack_recorder.h +0 -1
  22. data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
  23. data/ext/datadog_profiling_native_extension/time_helpers.h +13 -14
  24. data/ext/libdatadog_api/di.c +8 -3
  25. data/ext/libdatadog_api/extconf.rb +1 -1
  26. data/ext/libdatadog_api/feature_flags.c +8 -0
  27. data/ext/libdatadog_api/init.c +3 -1
  28. data/ext/libdatadog_api/otel_thread_context.c +38 -17
  29. data/ext/libdatadog_api/trace_exporter.c +77 -11
  30. data/ext/libdatadog_extconf_helpers.rb +14 -9
  31. data/lib/datadog/ai_guard/component.rb +17 -8
  32. data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
  33. data/lib/datadog/ai_guard/configuration.rb +13 -0
  34. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +48 -55
  35. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
  36. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
  37. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
  38. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
  39. data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
  40. data/lib/datadog/ai_guard/evaluation/content_part.rb +12 -0
  41. data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
  42. data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
  43. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +6 -6
  44. data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
  45. data/lib/datadog/ai_guard/evaluation/request.rb +4 -60
  46. data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
  47. data/lib/datadog/ai_guard/evaluation/result.rb +11 -18
  48. data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
  49. data/lib/datadog/ai_guard/evaluation.rb +25 -11
  50. data/lib/datadog/ai_guard/ext.rb +1 -0
  51. data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +6 -4
  52. data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
  53. data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
  54. data/lib/datadog/ai_guard/redaction/result.rb +29 -0
  55. data/lib/datadog/ai_guard/redaction.rb +80 -0
  56. data/lib/datadog/ai_guard.rb +58 -57
  57. data/lib/datadog/core/configuration/components.rb +9 -1
  58. data/lib/datadog/core/configuration/settings.rb +5 -2
  59. data/lib/datadog/core/configuration/supported_configurations.rb +8 -0
  60. data/lib/datadog/core/remote/client/capabilities.rb +10 -4
  61. data/lib/datadog/core/remote/component.rb +9 -2
  62. data/lib/datadog/core/remote/worker.rb +8 -0
  63. data/lib/datadog/di/instrumenter.rb +1 -1
  64. data/lib/datadog/di/probe_manager.rb +10 -5
  65. data/lib/datadog/di/proc_responder.rb +1 -1
  66. data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
  67. data/lib/datadog/open_feature/agentless/parser.rb +43 -0
  68. data/lib/datadog/open_feature/agentless/response.rb +19 -0
  69. data/lib/datadog/open_feature/agentless/transport.rb +103 -0
  70. data/lib/datadog/open_feature/component.rb +57 -1
  71. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
  72. data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
  73. data/lib/datadog/open_feature/configuration/source.rb +43 -0
  74. data/lib/datadog/open_feature/configuration.rb +118 -0
  75. data/lib/datadog/open_feature/native_evaluator.rb +1 -14
  76. data/lib/datadog/open_feature/remote.rb +5 -5
  77. data/lib/datadog/opentelemetry/signal_configuration.rb +13 -9
  78. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +7 -2
  79. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -7
  80. data/lib/datadog/profiling/component.rb +2 -3
  81. data/lib/datadog/profiling/exporter.rb +7 -5
  82. data/lib/datadog/symbol_database/extractor.rb +84 -102
  83. data/lib/datadog/tracing/component.rb +3 -1
  84. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  85. data/lib/datadog/tracing/configuration/settings.rb +9 -2
  86. data/lib/datadog/tracing/context.rb +24 -2
  87. data/lib/datadog/tracing/context_provider.rb +9 -5
  88. data/lib/datadog/tracing/contrib/grape/endpoint.rb +32 -5
  89. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +6 -3
  90. data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -0
  91. data/lib/datadog/tracing/metadata/ext.rb +3 -0
  92. data/lib/datadog/tracing/otel_thread_context.rb +76 -11
  93. data/lib/datadog/tracing/tracer.rb +15 -2
  94. data/lib/datadog/tracing/transport/native.rb +23 -22
  95. data/lib/datadog/tracing/transport/trace_formatter.rb +13 -3
  96. data/lib/datadog/tracing/transport/traces.rb +1 -1
  97. data/lib/datadog/version.rb +1 -1
  98. metadata +23 -7
  99. data/lib/datadog/ai_guard/evaluation/content_builder.rb +0 -31
@@ -22,24 +22,24 @@
22
22
  typedef enum { ACTION_WAIT, ACTION_RUN, ACTION_STOP } action;
23
23
 
24
24
  // Contains state for a single CpuAndWallTimeWorker instance
25
- typedef struct {
25
+ struct idle_sampling_loop_state {
26
26
  pthread_mutex_t wakeup_mutex;
27
27
  pthread_cond_t wakeup;
28
28
  action requested_action;
29
29
  void (*run_action_function)(void);
30
- } idle_sampling_loop_state;
30
+ };
31
31
 
32
32
  static VALUE _native_new(VALUE klass);
33
33
  static void reset_state(idle_sampling_loop_state *state);
34
- static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance, VALUE thread_context_collector_instance);
34
+ static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance, VALUE cpu_and_wall_time_worker_instance);
35
35
  static VALUE idle_sampling_loop_body(VALUE self_instance);
36
- static VALUE idle_sampling_loop_ensure(VALUE thread_context_collector_instance);
36
+ static VALUE idle_sampling_loop_ensure(VALUE cpu_and_wall_time_worker_instance);
37
37
  static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance);
38
38
  static void *run_idle_sampling_loop(void *state_ptr);
39
39
  static void interrupt_idle_sampling_loop(void *state_ptr);
40
40
  static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance);
41
41
  static VALUE _native_idle_sampling_helper_request_action(DDTRACE_UNUSED VALUE self, VALUE self_instance);
42
- static void *request_testing_action(void *self_instance_ptr);
42
+ static void *request_testing_action(void *state_ptr);
43
43
  static void grab_gvl_and_run_testing_action(void);
44
44
  static void *run_testing_action(DDTRACE_UNUSED void *unused);
45
45
 
@@ -112,8 +112,8 @@ static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
112
112
  return Qtrue;
113
113
  }
114
114
 
115
- static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance, VALUE thread_context_collector_instance) {
116
- return rb_ensure(idle_sampling_loop_body, self_instance, idle_sampling_loop_ensure, thread_context_collector_instance);
115
+ static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance, VALUE cpu_and_wall_time_worker_instance) {
116
+ return rb_ensure(idle_sampling_loop_body, self_instance, idle_sampling_loop_ensure, cpu_and_wall_time_worker_instance);
117
117
  }
118
118
 
119
119
  static VALUE idle_sampling_loop_body(VALUE self_instance) {
@@ -128,9 +128,8 @@ static VALUE idle_sampling_loop_body(VALUE self_instance) {
128
128
  return Qtrue;
129
129
  }
130
130
 
131
- static VALUE idle_sampling_loop_ensure(VALUE thread_context_collector_instance) {
132
- thread_context_collector_profiler_internal_thread_done(thread_context_collector_instance);
133
- return Qnil;
131
+ static VALUE idle_sampling_loop_ensure(VALUE cpu_and_wall_time_worker_instance) {
132
+ return rb_funcall(cpu_and_wall_time_worker_instance, rb_intern("_native_profiler_internal_thread_done"), 0);
134
133
  }
135
134
 
136
135
  static void *run_idle_sampling_loop(void *state_ptr) {
@@ -216,15 +215,14 @@ static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
216
215
  return Qtrue;
217
216
  }
218
217
 
219
- // Assumption: Function gets called without the global VM lock
220
- void idle_sampling_helper_request_action(VALUE self_instance, void (*run_action_function)(void)) {
218
+ idle_sampling_loop_state *idle_sampling_helper_get_state(VALUE self_instance) {
221
219
  idle_sampling_loop_state *state;
222
- if (!rb_typeddata_is_kind_of(self_instance, &idle_sampling_helper_typed_data)) {
223
- grab_gvl_and_raise(rb_eTypeError, "Wrong argument for idle_sampling_helper_request_action");
224
- }
225
- // This should never fail when the above check passes
226
220
  TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
221
+ return state;
222
+ }
227
223
 
224
+ // Called without the GVL, so we access native state directly: touching the Ruby self_instance is unsafe during GC compaction.
225
+ void idle_sampling_helper_request_action(idle_sampling_loop_state *state, void (*run_action_function)(void)) {
228
226
  ENFORCE_SUCCESS_NO_GVL(pthread_mutex_lock(&state->wakeup_mutex));
229
227
  if (state->requested_action == ACTION_WAIT) {
230
228
  state->requested_action = ACTION_RUN;
@@ -239,13 +237,14 @@ void idle_sampling_helper_request_action(VALUE self_instance, void (*run_action_
239
237
  // Because the idle_sampling_helper_request_action is built to be called without the global VM lock, here we release it
240
238
  // to be able to call that API.
241
239
  static VALUE _native_idle_sampling_helper_request_action(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
242
- rb_thread_call_without_gvl(request_testing_action, (void *) self_instance, NULL, NULL);
240
+ idle_sampling_loop_state *state = idle_sampling_helper_get_state(self_instance);
241
+ rb_thread_call_without_gvl(request_testing_action, state, NULL, NULL);
242
+ RB_GC_GUARD(self_instance);
243
243
  return Qtrue;
244
244
  }
245
245
 
246
- static void *request_testing_action(void *self_instance_ptr) {
247
- VALUE self_instance = (VALUE) self_instance_ptr;
248
- idle_sampling_helper_request_action(self_instance, grab_gvl_and_run_testing_action);
246
+ static void *request_testing_action(void *state_ptr) {
247
+ idle_sampling_helper_request_action(state_ptr, grab_gvl_and_run_testing_action);
249
248
  return NULL;
250
249
  }
251
250
 
@@ -1,3 +1,7 @@
1
1
  #pragma once
2
2
 
3
- void idle_sampling_helper_request_action(VALUE self_instance, void (*run_action_function)(void));
3
+ typedef struct idle_sampling_loop_state idle_sampling_loop_state;
4
+
5
+ // Must be called with the GVL held; keep self_instance alive while using the returned pointer.
6
+ idle_sampling_loop_state *idle_sampling_helper_get_state(VALUE self_instance);
7
+ void idle_sampling_helper_request_action(idle_sampling_loop_state *state, void (*run_action_function)(void));
@@ -641,9 +641,10 @@ void record_placeholder_stack(
641
641
  );
642
642
  }
643
643
 
644
+ // Also called from a signal handler or during GC; check callers' safety requirements before changing this function.
644
645
  bool prepare_sample_thread(VALUE thread, sampling_buffer *buffer) {
645
- // Since this can get called from inside a signal handler, we don't want to touch the buffer if
646
- // the thread was actually in the middle of marking it.
646
+ // While the signal handler checks if there's GC going on, it's actually possible for `sampling_buffer_mark` to
647
+ // still run outside of GC (see comments on that function) and thus we guard for it here.
647
648
  if (buffer->is_marking) return false;
648
649
 
649
650
  buffer->pending_sample = true;
@@ -705,12 +706,11 @@ void sampling_buffer_mark(sampling_buffer *buffer) {
705
706
  }
706
707
 
707
708
  buffer->is_marking = true;
708
- // Tell the compiler it's not allowed to reorder the `is_marking` flag with the iteration below.
709
- //
710
- // Specifically, in the middle of `sampling_buffer_mark` a signal handler may execute and call
711
- // `prepare_sample_thread` to add a new sample to the buffer. This flag is here to prevent that BUT we need to
712
- // make sure the signal handler actually sees the flag being set.
709
+ // The sampling buffer isn't supposed to be touched during GC. Yet, marking can happen outside of GC -- in particular
710
+ // ObjectSpace.dump/dump_all and reachable_objects_from invoke mark callbacks outside GC to enumerate references.
711
+ // Thus we keep this flag to tell the signal handler "hey you're still not allowed to touch the buffer at this time".
713
712
  //
713
+ // The fences ensure the compiler doesn't reorder the flags and a signal handler observes them
714
714
  // See https://github.com/ruby/ruby/pull/11036 for a similar change made to the Ruby VM with more context.
715
715
  atomic_signal_fence(memory_order_seq_cst);
716
716
 
@@ -13,7 +13,7 @@ typedef struct {
13
13
  uint16_t max_frames;
14
14
  frame_info *stack_buffer;
15
15
  bool pending_sample;
16
- bool is_marking; // Used to avoid recording a sample when marking
16
+ bool is_marking; // Used to avoid recording a sample when marking (marking can happen outside of GC as well)
17
17
  int pending_sample_result;
18
18
  } sampling_buffer;
19
19