datadog 2.36.0 → 2.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -1
  3. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +5 -12
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +6 -3
  5. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +17 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +219 -98
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +2 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +11 -0
  9. data/ext/datadog_profiling_native_extension/ruby_helpers.c +7 -0
  10. data/ext/libdatadog_api/di.c +76 -0
  11. data/ext/libdatadog_api/extconf.rb +6 -0
  12. data/ext/libdatadog_extconf_helpers.rb +1 -1
  13. data/lib/datadog/ai_guard/api_client.rb +6 -4
  14. data/lib/datadog/appsec/api_security/route_extractor.rb +7 -4
  15. data/lib/datadog/appsec/configuration.rb +6 -0
  16. data/lib/datadog/appsec/context.rb +4 -2
  17. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +59 -4
  18. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +59 -5
  19. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +1 -1
  20. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +4 -0
  21. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +4 -17
  22. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +21 -0
  23. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +2 -1
  24. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +60 -7
  25. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +4 -0
  26. data/lib/datadog/appsec/ext.rb +1 -0
  27. data/lib/datadog/appsec/metrics/collector.rb +18 -1
  28. data/lib/datadog/appsec/metrics/exporter.rb +9 -3
  29. data/lib/datadog/appsec/remote.rb +9 -3
  30. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  31. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  32. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  33. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  34. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  35. data/lib/datadog/core/configuration/components.rb +82 -2
  36. data/lib/datadog/core/configuration/components_state.rb +6 -1
  37. data/lib/datadog/core/configuration/settings.rb +0 -3
  38. data/lib/datadog/core/configuration/supported_configurations.rb +2 -0
  39. data/lib/datadog/core/evp.rb +11 -0
  40. data/lib/datadog/core/remote/client/capabilities.rb +34 -7
  41. data/lib/datadog/core/telemetry/event/app_started.rb +8 -1
  42. data/lib/datadog/di/base.rb +3 -1
  43. data/lib/datadog/di/code_tracker.rb +5 -2
  44. data/lib/datadog/di/component.rb +110 -36
  45. data/lib/datadog/di/error.rb +10 -0
  46. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  47. data/lib/datadog/di/instrumenter.rb +381 -165
  48. data/lib/datadog/di/probe.rb +14 -0
  49. data/lib/datadog/di/probe_file_loader.rb +8 -3
  50. data/lib/datadog/di/probe_manager.rb +67 -9
  51. data/lib/datadog/di/probe_notification_builder.rb +4 -1
  52. data/lib/datadog/di/probe_notifier_worker.rb +52 -32
  53. data/lib/datadog/di/redactor.rb +16 -1
  54. data/lib/datadog/di/remote.rb +175 -14
  55. data/lib/datadog/di/serializer.rb +12 -5
  56. data/lib/datadog/di/transport/input.rb +8 -4
  57. data/lib/datadog/di.rb +63 -0
  58. data/lib/datadog/kit/appsec/events/v2.rb +60 -2
  59. data/lib/datadog/open_feature/component.rb +29 -6
  60. data/lib/datadog/open_feature/configuration.rb +8 -0
  61. data/lib/datadog/open_feature/ext.rb +2 -0
  62. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +286 -0
  63. data/lib/datadog/open_feature/flag_evaluation/writer.rb +433 -0
  64. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +101 -0
  65. data/lib/datadog/open_feature/hooks/{flag_eval_hook.rb → flag_eval_metrics_hook.rb} +1 -1
  66. data/lib/datadog/open_feature/native_evaluator.rb +22 -0
  67. data/lib/datadog/open_feature/provider.rb +59 -27
  68. data/lib/datadog/open_feature/transport.rb +55 -1
  69. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +5 -12
  70. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +4 -11
  71. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  72. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
  73. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -3
  74. data/lib/datadog/symbol_database/component.rb +164 -47
  75. data/lib/datadog/symbol_database/configuration.rb +12 -4
  76. data/lib/datadog/symbol_database/extensions.rb +19 -0
  77. data/lib/datadog/symbol_database/extractor.rb +124 -87
  78. data/lib/datadog/symbol_database/file_hash.rb +3 -1
  79. data/lib/datadog/symbol_database/remote.rb +8 -3
  80. data/lib/datadog/symbol_database/scope_batcher.rb +7 -3
  81. data/lib/datadog/symbol_database/uploader.rb +9 -2
  82. data/lib/datadog/symbol_database.rb +22 -0
  83. data/lib/datadog/tracing/distributed/baggage.rb +2 -1
  84. data/lib/datadog/tracing/ext.rb +9 -0
  85. data/lib/datadog/tracing/remote.rb +34 -3
  86. data/lib/datadog/version.rb +1 -1
  87. data/lib/datadog.rb +1 -0
  88. metadata +19 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd8fcd94fa20eb591676abd0f96d6ef69f475f10c08e53d7e4dad1c0cab35e7c
4
- data.tar.gz: 6e3036aedb4b47ccb9d8c7ec74d070f52e755796e729d99f83c171ca1879ba59
3
+ metadata.gz: 5435fe8fe48f8cd33010ad82ee5fe6f969077a86cdcca6a96cc9d8633c89eb0e
4
+ data.tar.gz: 3681864939e4601b11bb94fa4b6647d1505efc621eae82ac9664fcc3819b34a3
5
5
  SHA512:
6
- metadata.gz: 8de4af357d5807e1855eb4dc078d291af8b601bda3fac1d44d442634dd1b241c7a6b27397095f54a9d931110b503398a43de70878e62c9525629c2b17bcbd97a
7
- data.tar.gz: 6f8acf814a862cfe261b6a3e97f40c37d0cb86b36deeadf253b14c0b17647e570eca9fca2a4d3dc86126a63d9fa5c0d83f750d495d0f6df0e1d23f43493dad6b
6
+ metadata.gz: de74ddeb7271f1ced1c21dde221b2bdd10fec9b7c9f8663cdf01f146c6a242d93dcde9ac7c63828e41045565f4870359469124a55ef999847f1d02416e36b919
7
+ data.tar.gz: 2d7d44bb00879fa869c5ec630654632632fd74719c7cb276a9a5310606a952cf3eece0bd52c70b25a2a75cb6e69949a1f3ab9597badfb89e17175905b5e08f3e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.37.0] - 2026-07-06
6
+
7
+ ### Added
8
+
9
+ * AppSec: Add sign-up event tracking to `Datadog::Kit::AppSec::Events::V2` ([#5973][])
10
+ * AppSec: Integrations: Add normalized HTTP route for API Security Testing ([#5834][])
11
+ * Dynamic Instrumentation: DI can now be enabled from the Datadog UI without setting `DD_DYNAMIC_INSTRUMENTATION_ENABLED` or restarting the application. Setting `DD_DYNAMIC_INSTRUMENTATION_ENABLED=false` explicitly still disables it and blocks UI-driven enablement ([#5525][])
12
+
13
+ ### Changed
14
+
15
+ * Profiling: Reduce profiler overhead by sampling profiler-internal threads only once per minute ([#5955][])
16
+ * Dynamic Instrumentation: Reject method probes that target `Kernel#lambda`, which cannot be safely instrumented ([#5954][])
17
+ * Dynamic Instrumentation: Reject method probes that target classes or modules in the Datadog namespace ([#5907][])
18
+ * Dynamic Instrumentation: Enable Symbol Database by default when Dynamic Instrumentation is enabled ([#5828][])
19
+
20
+ ### Fixed
21
+
22
+ * AppSec: AI Guard: Fix endpoint configuration via `DD_SITE` environment variable ([#5940][])
23
+ * AppSec: Fix API Security schema extraction timeout and telemetry ([#5975][])
24
+ * AppSec: Fix remote configuration errors when the ruleset name changes ([#5970][])
25
+ * AppSec: Integrations: Add configurable size limit for downstream HTTP request and response body analysis ([#5990][])
26
+ * AppSec: Integrations: Fix WAF analysis for requests with cached or parsed bodies in Rack and Sinatra ([#5991][])
27
+ * AppSec: Integrations: Fix an exception for unauthorized requests when using Devise with Rails. ([#5987][])
28
+ * Tracing: Fix a `SIGSEGV` crash that could happen with experimental heap profiling enabled on Ruby 4.0 ([#5938][]) ([@navidemad][])
29
+ * Dynamic Instrumentation: Normalize Rack CGI header prefix (`HTTP_<HEADER>`) in redactor so snapshot captures redact sensitive headers like their bare names ([#5911][])
30
+ * Dynamic Instrumentation: Symbol Database and DI background threads no longer stop when application code raises a non-StandardError during introspection ([#5945][])
31
+
5
32
  ## [2.36.0] - 2026-06-24
6
33
 
7
34
  ### Added
@@ -3658,7 +3685,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3658
3685
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3659
3686
 
3660
3687
 
3661
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.36.0...master
3688
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.37.0...master
3689
+ [2.37.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.36.0...v2.37.0
3662
3690
  [2.36.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.35.0...v2.36.0
3663
3691
  [2.35.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.34.0...v2.35.0
3664
3692
  [2.34.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.33.0...v2.34.0
@@ -5385,6 +5413,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5385
5413
  [#5499]: https://github.com/DataDog/dd-trace-rb/issues/5499
5386
5414
  [#5501]: https://github.com/DataDog/dd-trace-rb/issues/5501
5387
5415
  [#5509]: https://github.com/DataDog/dd-trace-rb/issues/5509
5416
+ [#5525]: https://github.com/DataDog/dd-trace-rb/issues/5525
5388
5417
  [#5531]: https://github.com/DataDog/dd-trace-rb/issues/5531
5389
5418
  [#5564]: https://github.com/DataDog/dd-trace-rb/issues/5564
5390
5419
  [#5569]: https://github.com/DataDog/dd-trace-rb/issues/5569
@@ -5420,7 +5449,9 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5420
5449
  [#5811]: https://github.com/DataDog/dd-trace-rb/issues/5811
5421
5450
  [#5812]: https://github.com/DataDog/dd-trace-rb/issues/5812
5422
5451
  [#5816]: https://github.com/DataDog/dd-trace-rb/issues/5816
5452
+ [#5828]: https://github.com/DataDog/dd-trace-rb/issues/5828
5423
5453
  [#5830]: https://github.com/DataDog/dd-trace-rb/issues/5830
5454
+ [#5834]: https://github.com/DataDog/dd-trace-rb/issues/5834
5424
5455
  [#5836]: https://github.com/DataDog/dd-trace-rb/issues/5836
5425
5456
  [#5844]: https://github.com/DataDog/dd-trace-rb/issues/5844
5426
5457
  [#5857]: https://github.com/DataDog/dd-trace-rb/issues/5857
@@ -5430,8 +5461,21 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5430
5461
  [#5883]: https://github.com/DataDog/dd-trace-rb/issues/5883
5431
5462
  [#5890]: https://github.com/DataDog/dd-trace-rb/issues/5890
5432
5463
  [#5894]: https://github.com/DataDog/dd-trace-rb/issues/5894
5464
+ [#5907]: https://github.com/DataDog/dd-trace-rb/issues/5907
5465
+ [#5911]: https://github.com/DataDog/dd-trace-rb/issues/5911
5433
5466
  [#5916]: https://github.com/DataDog/dd-trace-rb/issues/5916
5434
5467
  [#5920]: https://github.com/DataDog/dd-trace-rb/issues/5920
5468
+ [#5938]: https://github.com/DataDog/dd-trace-rb/issues/5938
5469
+ [#5940]: https://github.com/DataDog/dd-trace-rb/issues/5940
5470
+ [#5945]: https://github.com/DataDog/dd-trace-rb/issues/5945
5471
+ [#5954]: https://github.com/DataDog/dd-trace-rb/issues/5954
5472
+ [#5955]: https://github.com/DataDog/dd-trace-rb/issues/5955
5473
+ [#5970]: https://github.com/DataDog/dd-trace-rb/issues/5970
5474
+ [#5973]: https://github.com/DataDog/dd-trace-rb/issues/5973
5475
+ [#5975]: https://github.com/DataDog/dd-trace-rb/issues/5975
5476
+ [#5987]: https://github.com/DataDog/dd-trace-rb/issues/5987
5477
+ [#5990]: https://github.com/DataDog/dd-trace-rb/issues/5990
5478
+ [#5991]: https://github.com/DataDog/dd-trace-rb/issues/5991
5435
5479
  [@AdrianLC]: https://github.com/AdrianLC
5436
5480
  [@Azure7111]: https://github.com/Azure7111
5437
5481
  [@BabyGroot]: https://github.com/BabyGroot
@@ -5546,6 +5590,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5546
5590
  [@mscrivo]: https://github.com/mscrivo
5547
5591
  [@mstruve]: https://github.com/mstruve
5548
5592
  [@mustela]: https://github.com/mustela
5593
+ [@navidemad]: https://github.com/navidemad
5549
5594
  [@nic-lan]: https://github.com/nic-lan
5550
5595
  [@noma4i]: https://github.com/noma4i
5551
5596
  [@norbertnytko]: https://github.com/norbertnytko
@@ -5,7 +5,6 @@
5
5
  #ifdef HAVE_MACH_THREAD_INFO
6
6
 
7
7
  #include <pthread.h>
8
- #include <time.h>
9
8
  #include <mach/mach.h>
10
9
  #include <mach/thread_info.h>
11
10
 
@@ -47,17 +46,11 @@ thread_cpu_time thread_cpu_time_for(thread_cpu_time_id time_id) {
47
46
 
48
47
  if (!time_id.valid) return error;
49
48
 
50
- // Fast path: clock_gettime(CLOCK_THREAD_CPUTIME_ID) is ~5x cheaper than thread_info()
51
- // and gives sub-microsecond precision (vs microsecond), but only measures the calling
52
- // thread on macOS (there is no pthread_getcpuclockid() equivalent).
53
- if (time_id.clock_id == pthread_mach_thread_np(pthread_self())) {
54
- struct timespec ts;
55
- if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) {
56
- return (thread_cpu_time) {.valid = true, .result_ns = SECONDS_AS_NS(ts.tv_sec) + ts.tv_nsec};
57
- }
58
- // Fall through to thread_info on the unlikely failure case.
59
- }
60
-
49
+ // We intentionally use thread_info() for all threads, including the current one, even though
50
+ // clock_gettime(CLOCK_THREAD_CPUTIME_ID) is ~5x faster for the current thread. Mixing the two
51
+ // sources causes CPU time to appear to go backwards: thread_info() has microsecond precision
52
+ // while clock_gettime() has nanosecond precision, and comparing values across sources on
53
+ // successive samples produces small negative deltas.
61
54
  struct thread_basic_info info;
62
55
  mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
63
56
  kern_return_t kr = thread_info(time_id.clock_id, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
@@ -530,6 +530,8 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
530
530
  // situation we stop immediately and never even start the sampling trigger loop.
531
531
  if (state->stop_thread == rb_thread_current()) return Qnil;
532
532
 
533
+ thread_context_collector_profiler_internal_thread_started();
534
+
533
535
  // Reset the dynamic sampling rate state, if any (reminder: the monotonic clock reference may change after a fork)
534
536
  dynamic_sampling_rate_reset(&state->cpu_dynamic_sampling_rate);
535
537
  long now = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
@@ -893,6 +895,8 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
893
895
  // If we stopped sampling due to an exception, re-raise it (now in the worker thread)
894
896
  if (state->failure_exception != Qnil) rb_exc_raise(state->failure_exception);
895
897
 
898
+ thread_context_collector_profiler_internal_thread_done(state->thread_context_collector_instance);
899
+
896
900
  return Qnil;
897
901
  }
898
902
 
@@ -1267,9 +1271,8 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
1267
1271
 
1268
1272
  per_thread_context *thread_context = get_per_thread_context(current_thread);
1269
1273
  if (!thread_context) {
1270
- // No per_thread_context yet on this Thread, we can't use get_or_create_context_for() as that allocates,
1271
- // and we are inside on_newobj_event where we MUST NOT allocate.
1272
- // So we don't sample allocations until another hook allocates the per_thread_context.
1274
+ // Context is created eagerly via on_thread_begin_event, so this should not normally be NULL.
1275
+ // We keep the guard since we can't allocate here (inside on_newobj_event).
1273
1276
  return;
1274
1277
  }
1275
1278
 
@@ -6,6 +6,7 @@
6
6
  #include "helpers.h"
7
7
  #include "ruby_helpers.h"
8
8
  #include "collectors_idle_sampling_helper.h"
9
+ #include "collectors_thread_context.h"
9
10
 
10
11
  // Used by the Collectors::CpuAndWallTimeWorker to gather samples when the Ruby process is idle.
11
12
  //
@@ -30,7 +31,9 @@ typedef struct {
30
31
 
31
32
  static VALUE _native_new(VALUE klass);
32
33
  static void reset_state(idle_sampling_loop_state *state);
33
- static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance);
34
+ static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance, VALUE thread_context_collector_instance);
35
+ static VALUE idle_sampling_loop_body(VALUE self_instance);
36
+ static VALUE idle_sampling_loop_ensure(VALUE thread_context_collector_instance);
34
37
  static VALUE _native_stop(DDTRACE_UNUSED VALUE self, VALUE self_instance);
35
38
  static void *run_idle_sampling_loop(void *state_ptr);
36
39
  static void interrupt_idle_sampling_loop(void *state_ptr);
@@ -56,7 +59,7 @@ void collectors_idle_sampling_helper_init(VALUE profiling_module) {
56
59
  // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
57
60
  rb_define_alloc_func(collectors_idle_sampling_helper_class, _native_new);
58
61
 
59
- rb_define_singleton_method(collectors_idle_sampling_helper_class, "_native_idle_sampling_loop", _native_idle_sampling_loop, 1);
62
+ rb_define_singleton_method(collectors_idle_sampling_helper_class, "_native_idle_sampling_loop", _native_idle_sampling_loop, 2);
60
63
  rb_define_singleton_method(collectors_idle_sampling_helper_class, "_native_stop", _native_stop, 1);
61
64
  rb_define_singleton_method(collectors_idle_sampling_helper_class, "_native_reset", _native_reset, 1);
62
65
  rb_define_singleton_method(testing_module, "_native_idle_sampling_helper_request_action", _native_idle_sampling_helper_request_action, 1);
@@ -109,16 +112,27 @@ static VALUE _native_reset(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
109
112
  return Qtrue;
110
113
  }
111
114
 
112
- static VALUE _native_idle_sampling_loop(DDTRACE_UNUSED VALUE self, VALUE self_instance) {
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);
117
+ }
118
+
119
+ static VALUE idle_sampling_loop_body(VALUE self_instance) {
113
120
  idle_sampling_loop_state *state;
114
121
  TypedData_Get_Struct(self_instance, idle_sampling_loop_state, &idle_sampling_helper_typed_data, state);
115
122
 
123
+ thread_context_collector_profiler_internal_thread_started();
124
+
116
125
  // Release GVL and run the loop waiting for requests
117
126
  rb_thread_call_without_gvl(run_idle_sampling_loop, state, interrupt_idle_sampling_loop, state);
118
127
 
119
128
  return Qtrue;
120
129
  }
121
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;
134
+ }
135
+
122
136
  static void *run_idle_sampling_loop(void *state_ptr) {
123
137
  idle_sampling_loop_state *state = (idle_sampling_loop_state *) state_ptr;
124
138
  int error = 0;