datadog 2.16.0 → 2.18.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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  8. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  9. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  10. data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
  13. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  14. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  15. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  16. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
  17. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
  18. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
  19. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  20. data/ext/datadog_profiling_native_extension/stack_recorder.c +156 -60
  21. data/ext/libdatadog_api/crashtracker.c +10 -3
  22. data/ext/libdatadog_api/extconf.rb +2 -2
  23. data/ext/libdatadog_api/library_config.c +54 -12
  24. data/ext/libdatadog_api/library_config.h +6 -0
  25. data/ext/libdatadog_api/macos_development.md +3 -3
  26. data/ext/libdatadog_api/process_discovery.c +2 -7
  27. data/ext/libdatadog_extconf_helpers.rb +2 -2
  28. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  29. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  30. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  31. data/lib/datadog/appsec/api_security.rb +23 -0
  32. data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
  33. data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
  34. data/lib/datadog/appsec/component.rb +30 -54
  35. data/lib/datadog/appsec/configuration/settings.rb +60 -2
  36. data/lib/datadog/appsec/context.rb +6 -6
  37. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  38. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
  39. data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
  40. data/lib/datadog/appsec/remote.rb +15 -55
  41. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  42. data/lib/datadog/appsec/security_engine/runner.rb +10 -11
  43. data/lib/datadog/appsec.rb +4 -7
  44. data/lib/datadog/core/buffer/random.rb +18 -2
  45. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  46. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -46
  47. data/lib/datadog/core/configuration/components.rb +31 -24
  48. data/lib/datadog/core/configuration/components_state.rb +23 -0
  49. data/lib/datadog/core/configuration/option.rb +27 -27
  50. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  51. data/lib/datadog/core/configuration/options.rb +1 -1
  52. data/lib/datadog/core/configuration/settings.rb +32 -20
  53. data/lib/datadog/core/configuration/stable_config.rb +1 -2
  54. data/lib/datadog/core/configuration.rb +16 -16
  55. data/lib/datadog/core/crashtracking/component.rb +2 -1
  56. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  57. data/lib/datadog/core/encoding.rb +1 -1
  58. data/lib/datadog/core/environment/cgroup.rb +10 -12
  59. data/lib/datadog/core/environment/container.rb +38 -40
  60. data/lib/datadog/core/environment/ext.rb +6 -6
  61. data/lib/datadog/core/environment/identity.rb +3 -3
  62. data/lib/datadog/core/environment/platform.rb +3 -3
  63. data/lib/datadog/core/error.rb +11 -9
  64. data/lib/datadog/core/logger.rb +2 -2
  65. data/lib/datadog/core/metrics/client.rb +12 -14
  66. data/lib/datadog/core/metrics/logging.rb +5 -5
  67. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  68. data/lib/datadog/core/process_discovery.rb +5 -1
  69. data/lib/datadog/core/rate_limiter.rb +4 -2
  70. data/lib/datadog/core/remote/client.rb +32 -31
  71. data/lib/datadog/core/remote/component.rb +3 -3
  72. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  73. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  74. data/lib/datadog/core/remote/configuration/repository.rb +12 -0
  75. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  76. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  77. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  78. data/lib/datadog/core/runtime/metrics.rb +3 -3
  79. data/lib/datadog/core/tag_builder.rb +56 -0
  80. data/lib/datadog/core/telemetry/component.rb +39 -24
  81. data/lib/datadog/core/telemetry/emitter.rb +7 -1
  82. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  83. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  84. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  85. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  86. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  87. data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
  88. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  89. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  90. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  91. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  92. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  93. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  94. data/lib/datadog/core/telemetry/event.rb +17 -475
  95. data/lib/datadog/core/telemetry/logger.rb +5 -4
  96. data/lib/datadog/core/telemetry/logging.rb +11 -5
  97. data/lib/datadog/core/telemetry/metric.rb +3 -3
  98. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -2
  99. data/lib/datadog/core/telemetry/transport/telemetry.rb +0 -1
  100. data/lib/datadog/core/telemetry/worker.rb +48 -27
  101. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  102. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  103. data/lib/datadog/core/transport/http/builder.rb +14 -14
  104. data/lib/datadog/core/transport/http/env.rb +8 -0
  105. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  106. data/lib/datadog/core/utils/duration.rb +32 -32
  107. data/lib/datadog/core/utils/forking.rb +2 -2
  108. data/lib/datadog/core/utils/network.rb +6 -6
  109. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  110. data/lib/datadog/core/utils/time.rb +10 -2
  111. data/lib/datadog/core/utils/truncation.rb +21 -0
  112. data/lib/datadog/core/utils.rb +7 -0
  113. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  114. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  115. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  116. data/lib/datadog/core/worker.rb +1 -1
  117. data/lib/datadog/core/workers/async.rb +9 -10
  118. data/lib/datadog/di/instrumenter.rb +52 -2
  119. data/lib/datadog/di/probe_notification_builder.rb +31 -41
  120. data/lib/datadog/di/probe_notifier_worker.rb +9 -1
  121. data/lib/datadog/di/serializer.rb +6 -2
  122. data/lib/datadog/di/transport/http/input.rb +10 -0
  123. data/lib/datadog/di/transport/input.rb +10 -2
  124. data/lib/datadog/error_tracking/component.rb +2 -2
  125. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  126. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  127. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  128. data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
  129. data/lib/datadog/profiling/component.rb +7 -9
  130. data/lib/datadog/profiling/ext.rb +0 -13
  131. data/lib/datadog/profiling/flush.rb +1 -1
  132. data/lib/datadog/profiling/http_transport.rb +3 -8
  133. data/lib/datadog/profiling/profiler.rb +2 -0
  134. data/lib/datadog/profiling/scheduler.rb +10 -2
  135. data/lib/datadog/profiling/stack_recorder.rb +5 -5
  136. data/lib/datadog/profiling/tag_builder.rb +5 -41
  137. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  138. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  139. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  140. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  141. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  142. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  143. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  144. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  145. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  146. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  149. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  150. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  151. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  152. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  153. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  154. data/lib/datadog/tracing/contrib/support.rb +28 -0
  155. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  156. data/lib/datadog/tracing/sync_writer.rb +1 -1
  157. data/lib/datadog/tracing/trace_operation.rb +12 -4
  158. data/lib/datadog/tracing/tracer.rb +6 -2
  159. data/lib/datadog/version.rb +1 -1
  160. metadata +31 -12
  161. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
  162. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
  163. data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
  164. data/lib/datadog/appsec/processor.rb +0 -107
@@ -196,6 +196,10 @@ typedef struct {
196
196
  pthread_mutex_t mutex_slot_two;
197
197
  profile_slot profile_slot_two;
198
198
 
199
+ ddog_prof_ManagedStringStorage string_storage;
200
+ ddog_prof_ManagedStringId label_key_allocation_class;
201
+ ddog_prof_ManagedStringId label_key_gc_gen_age;
202
+
199
203
  short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
200
204
 
201
205
  uint8_t position_for[ALL_VALUE_TYPES_COUNT];
@@ -230,6 +234,7 @@ typedef struct {
230
234
  ddog_prof_Profile_SerializeResult result;
231
235
  long heap_profile_build_time_ns;
232
236
  long serialize_no_gvl_time_ns;
237
+ ddog_prof_MaybeError advance_gen_result;
233
238
 
234
239
  // Set by both
235
240
  bool serialize_ran;
@@ -256,7 +261,6 @@ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state
256
261
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
257
262
  static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
258
263
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
259
- static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
260
264
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
261
265
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
262
266
  static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
@@ -265,6 +269,8 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns,
265
269
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE object_id);
266
270
  static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
267
271
  static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
272
+ static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all);
273
+ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self);
268
274
 
269
275
  void stack_recorder_init(VALUE profiling_module) {
270
276
  VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
@@ -290,7 +296,6 @@ void stack_recorder_init(VALUE profiling_module) {
290
296
  rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
291
297
  rb_define_singleton_method(testing_module, "_native_record_endpoint", _native_record_endpoint, 3);
292
298
  rb_define_singleton_method(testing_module, "_native_track_object", _native_track_object, 4);
293
- rb_define_singleton_method(testing_module, "_native_check_heap_hashes", _native_check_heap_hashes, 1);
294
299
  rb_define_singleton_method(testing_module, "_native_start_fake_slow_heap_serialization",
295
300
  _native_start_fake_slow_heap_serialization, 1);
296
301
  rb_define_singleton_method(testing_module, "_native_end_fake_slow_heap_serialization",
@@ -300,6 +305,8 @@ void stack_recorder_init(VALUE profiling_module) {
300
305
  rb_define_singleton_method(testing_module, "_native_is_object_recorded?", _native_is_object_recorded, 2);
301
306
  rb_define_singleton_method(testing_module, "_native_heap_recorder_reset_last_update", _native_heap_recorder_reset_last_update, 1);
302
307
  rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
308
+ rb_define_singleton_method(testing_module, "_native_benchmark_intern", _native_benchmark_intern, 4);
309
+ rb_define_singleton_method(testing_module, "_native_test_managed_string_storage_produces_valid_profiles", _native_test_managed_string_storage_produces_valid_profiles, 0);
303
310
 
304
311
  ok_symbol = ID2SYM(rb_intern_const("ok"));
305
312
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -334,17 +341,27 @@ static VALUE _native_new(VALUE klass) {
334
341
  .serialization_time_ns_min = INT64_MAX,
335
342
  };
336
343
 
337
- // Note: At this point, slot_one_profile/slot_two_profile contain null pointers. Libdatadog validates pointers
344
+ // Note: At this point, slot_one_profile/slot_two_profile/string_storage contain null pointers. Libdatadog validates pointers
338
345
  // before using them so it's ok for us to go ahead and create the StackRecorder object.
339
346
 
340
347
  VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
341
348
 
349
+ ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
350
+
351
+ if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
352
+ rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
353
+ }
354
+
355
+ state->string_storage = string_storage.ok;
356
+ state->label_key_allocation_class = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("allocation class"));
357
+ state->label_key_gc_gen_age = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("gc gen age"));
358
+
359
+ initialize_profiles(state, sample_types);
360
+
342
361
  // NOTE: We initialize this because we want a new recorder to be operational even before #initialize runs and our
343
362
  // default is everything enabled. However, if during recording initialization it turns out we don't want
344
363
  // heap samples, we will free and reset heap_recorder back to NULL.
345
- state->heap_recorder = heap_recorder_new();
346
-
347
- initialize_profiles(state, sample_types);
364
+ state->heap_recorder = heap_recorder_new(state->string_storage);
348
365
 
349
366
  return stack_recorder;
350
367
  }
@@ -363,7 +380,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
363
380
  ddog_Timespec start_timestamp = system_epoch_now_timespec();
364
381
 
365
382
  ddog_prof_Profile_NewResult slot_one_profile_result =
366
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
383
+ ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
367
384
 
368
385
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
369
386
  rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
@@ -372,7 +389,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
372
389
  state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
373
390
 
374
391
  ddog_prof_Profile_NewResult slot_two_profile_result =
375
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
392
+ ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
376
393
 
377
394
  if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
378
395
  // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
@@ -393,6 +410,8 @@ static void stack_recorder_typed_data_free(void *state_ptr) {
393
410
 
394
411
  heap_recorder_free(state->heap_recorder);
395
412
 
413
+ ddog_prof_ManagedStringStorage_drop(state->string_storage);
414
+
396
415
  ruby_xfree(state);
397
416
  }
398
417
 
@@ -519,6 +538,8 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
519
538
  long heap_iteration_prep_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
520
539
  // Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
521
540
  // happen while holding on to the GVL.
541
+ // NOTE: While rare, it's possible for the GVL to be released inside this function (see comments on `heap_recorder_update`)
542
+ // and thus don't assume this is an "atomic" step -- other threads may get some running time in the meanwhile.
522
543
  heap_recorder_prepare_iteration(state->heap_recorder);
523
544
  long heap_iteration_prep_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - heap_iteration_prep_start_time_ns;
524
545
 
@@ -527,7 +548,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
527
548
  call_serialize_without_gvl_arguments args = {
528
549
  .state = state,
529
550
  .finish_timestamp = finish_timestamp,
530
- .serialize_ran = false
551
+ .serialize_ran = false,
531
552
  };
532
553
 
533
554
  while (!args.serialize_ran) {
@@ -551,13 +572,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
551
572
  // really cover the full serialization process but it gives a more useful number since it bypasses
552
573
  // the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
553
574
  // conditions and over which we really have no control about.
554
- long serialization_time_ns = args.serialize_no_gvl_time_ns;
555
- if (serialization_time_ns >= 0) {
556
- // Only update stats if our serialization time is valid.
557
- state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, serialization_time_ns);
558
- state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, serialization_time_ns);
559
- state->stats_lifetime.serialization_time_ns_total += serialization_time_ns;
560
- }
575
+ state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, args.serialize_no_gvl_time_ns);
576
+ state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, args.serialize_no_gvl_time_ns);
577
+ state->stats_lifetime.serialization_time_ns_total += args.serialize_no_gvl_time_ns;
561
578
 
562
579
  ddog_prof_Profile_SerializeResult serialized_profile = args.result;
563
580
 
@@ -566,14 +583,20 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
566
583
  return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
567
584
  }
568
585
 
586
+ // Note: If we got here, the profile serialized correctly.
587
+ // Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it and we
588
+ // can raise exceptions without worrying about leaking the profile.
569
589
  state->stats_lifetime.serialization_successes++;
570
-
571
- // Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it
572
590
  VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
573
591
 
592
+ ddog_prof_MaybeError result = args.advance_gen_result;
593
+ if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
594
+ rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&result.some));
595
+ }
596
+
574
597
  VALUE start = ruby_time_from(args.slot->start_timestamp);
575
598
  VALUE finish = ruby_time_from(finish_timestamp);
576
- VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
599
+ VALUE profile_stats = build_profile_stats(args.slot, args.serialize_no_gvl_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
577
600
 
578
601
  return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
579
602
  }
@@ -696,18 +719,15 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
696
719
  ddog_prof_Label labels[2];
697
720
  size_t label_offset = 0;
698
721
 
699
- if (object_data->class != NULL) {
722
+ if (object_data->class.value > 0) {
700
723
  labels[label_offset++] = (ddog_prof_Label) {
701
- .key = DDOG_CHARSLICE_C("allocation class"),
702
- .str = (ddog_CharSlice) {
703
- .ptr = object_data->class,
704
- .len = strlen(object_data->class),
705
- },
724
+ .key_id = context->state->label_key_allocation_class,
725
+ .str_id = object_data->class,
706
726
  .num = 0, // This shouldn't be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this
707
727
  };
708
728
  }
709
729
  labels[label_offset++] = (ddog_prof_Label) {
710
- .key = DDOG_CHARSLICE_C("gc gen age"),
730
+ .key_id = context->state->label_key_gc_gen_age,
711
731
  .num = object_data->gen_age,
712
732
  };
713
733
 
@@ -763,7 +783,6 @@ static void *call_serialize_without_gvl(void *call_args) {
763
783
  long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
764
784
 
765
785
  profile_slot *slot_now_inactive = serializer_flip_active_and_inactive_slots(args->state);
766
-
767
786
  args->slot = slot_now_inactive;
768
787
 
769
788
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
@@ -772,9 +791,10 @@ static void *call_serialize_without_gvl(void *call_args) {
772
791
  args->heap_profile_build_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
773
792
 
774
793
  // Note: The profile gets reset by the serialize call
775
- args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
794
+ args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->slot->start_timestamp, &args->finish_timestamp);
795
+ args->advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(args->state->string_storage);
776
796
  args->serialize_ran = true;
777
- args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
797
+ args->serialize_no_gvl_time_ns = long_max_of(0, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns);
778
798
 
779
799
  return NULL; // Unused
780
800
  }
@@ -918,38 +938,8 @@ static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_ins
918
938
  return Qtrue;
919
939
  }
920
940
 
921
- static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations) {
922
- ENFORCE_TYPE(locations, T_ARRAY);
923
- size_t locations_len = rb_array_len(locations);
924
- ddog_prof_Location locations_arr[locations_len];
925
- for (size_t i = 0; i < locations_len; i++) {
926
- VALUE location = rb_ary_entry(locations, i);
927
- ENFORCE_TYPE(location, T_ARRAY);
928
- VALUE name = rb_ary_entry(location, 0);
929
- VALUE filename = rb_ary_entry(location, 1);
930
- VALUE line = rb_ary_entry(location, 2);
931
- ENFORCE_TYPE(name, T_STRING);
932
- ENFORCE_TYPE(filename, T_STRING);
933
- ENFORCE_TYPE(line, T_FIXNUM);
934
- locations_arr[i] = (ddog_prof_Location) {
935
- .line = line,
936
- .function = (ddog_prof_Function) {
937
- .name = char_slice_from_ruby_string(name),
938
- .filename = char_slice_from_ruby_string(filename),
939
- }
940
- };
941
- }
942
- ddog_prof_Slice_Location ddog_locations = {
943
- .len = locations_len,
944
- .ptr = locations_arr,
945
- };
946
- heap_recorder_testonly_assert_hash_matches(ddog_locations);
947
-
948
- return Qnil;
949
- }
950
-
951
941
  static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
952
- ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile, &start_timestamp);
942
+ ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
953
943
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
954
944
  rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
955
945
  }
@@ -1047,3 +1037,109 @@ static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE re
1047
1037
  recorder_after_gc_step(recorder_instance);
1048
1038
  return Qtrue;
1049
1039
  }
1040
+
1041
+ static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all) {
1042
+ ENFORCE_TYPE(string, T_STRING);
1043
+ ENFORCE_TYPE(times, T_FIXNUM);
1044
+ ENFORCE_BOOLEAN(use_all);
1045
+
1046
+ stack_recorder_state *state;
1047
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1048
+
1049
+ heap_recorder_testonly_benchmark_intern(state->heap_recorder, char_slice_from_ruby_string(string), FIX2INT(times), use_all == Qtrue);
1050
+
1051
+ return Qtrue;
1052
+ }
1053
+
1054
+ // See comments in rspec test for details on what we're testing here.
1055
+ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self) {
1056
+ ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
1057
+
1058
+ if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
1059
+ rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
1060
+ }
1061
+
1062
+ ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
1063
+ ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
1064
+
1065
+ if (profile.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
1066
+ rb_raise(rb_eRuntimeError, "Failed to initialize profile: %"PRIsVALUE, get_error_details_and_drop(&profile.err));
1067
+ }
1068
+
1069
+ ddog_prof_ManagedStringId hello = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("hello"));
1070
+ ddog_prof_ManagedStringId world = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("world"));
1071
+ ddog_prof_ManagedStringId key = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("key"));
1072
+
1073
+ int64_t metric_values[] = {1, 2, 3, 4, 5, 6, 7, 8};
1074
+ ddog_prof_Label labels[] = {{.key_id = key, .str_id = key}};
1075
+
1076
+ ddog_prof_Location locations[] = {
1077
+ (ddog_prof_Location) {
1078
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
1079
+ .function = {
1080
+ .name = DDOG_CHARSLICE_C(""),
1081
+ .name_id = hello,
1082
+ .filename = DDOG_CHARSLICE_C(""),
1083
+ .filename_id = world,
1084
+ },
1085
+ .line = 1,
1086
+ }
1087
+ };
1088
+
1089
+ ddog_prof_Profile_Result result = ddog_prof_Profile_add(
1090
+ &profile.ok,
1091
+ (ddog_prof_Sample) {
1092
+ .locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
1093
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
1094
+ .labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
1095
+ },
1096
+ 0
1097
+ );
1098
+
1099
+ if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
1100
+ rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1101
+ }
1102
+
1103
+ ddog_Timespec finish_timestamp = system_epoch_now_timespec();
1104
+ ddog_Timespec start_timestamp = {.seconds = finish_timestamp.seconds - 60};
1105
+ ddog_prof_Profile_SerializeResult serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1106
+
1107
+ if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
1108
+ rb_raise(rb_eRuntimeError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1109
+ }
1110
+
1111
+ ddog_prof_MaybeError advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(string_storage.ok);
1112
+
1113
+ if (advance_gen_result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
1114
+ rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&advance_gen_result.some));
1115
+ }
1116
+
1117
+ VALUE encoded_pprof_1 = from_ddog_prof_EncodedProfile(serialize_result.ok);
1118
+
1119
+ result = ddog_prof_Profile_add(
1120
+ &profile.ok,
1121
+ (ddog_prof_Sample) {
1122
+ .locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
1123
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
1124
+ .labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
1125
+ },
1126
+ 0
1127
+ );
1128
+
1129
+ if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
1130
+ rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1131
+ }
1132
+
1133
+ serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1134
+
1135
+ if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
1136
+ rb_raise(rb_eArgError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1137
+ }
1138
+
1139
+ VALUE encoded_pprof_2 = from_ddog_prof_EncodedProfile(serialize_result.ok);
1140
+
1141
+ ddog_prof_Profile_drop(&profile.ok);
1142
+ ddog_prof_ManagedStringStorage_drop(string_storage.ok);
1143
+
1144
+ return rb_ary_new_from_args(2, encoded_pprof_1, encoded_pprof_2);
1145
+ }
@@ -6,6 +6,8 @@
6
6
  static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
7
7
  static VALUE _native_stop(DDTRACE_UNUSED VALUE _self);
8
8
 
9
+ static bool first_init = true;
10
+
9
11
  // Used to report Ruby VM crashes.
10
12
  // Once initialized, segfaults will be reported automatically using libdatadog.
11
13
 
@@ -62,7 +64,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
62
64
  // "Process.kill('SEGV', Process.pid)" gets run.
63
65
  //
64
66
  // This actually changed in libdatadog 14, so I could see no issues with `create_alt_stack = true`, but not
65
- // overridding what Ruby set up seems a saner default to keep anyway.
67
+ // overriding what Ruby set up seems a saner default to keep anyway.
66
68
  .create_alt_stack = false,
67
69
  .use_alt_stack = true,
68
70
  .endpoint = endpoint,
@@ -92,9 +94,14 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
92
94
 
93
95
  ddog_VoidResult result =
94
96
  action == start_action ?
95
- ddog_crasht_init(config, receiver_config, metadata) :
97
+ (first_init ?
98
+ ddog_crasht_init(config, receiver_config, metadata) :
99
+ ddog_crasht_reconfigure(config, receiver_config, metadata)
100
+ ) :
96
101
  ddog_crasht_update_on_fork(config, receiver_config, metadata);
97
102
 
103
+ first_init = false;
104
+
98
105
  // Clean up before potentially raising any exceptions
99
106
  ddog_Vec_Tag_drop(tags);
100
107
  ddog_endpoint_drop(endpoint);
@@ -108,7 +115,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
108
115
  }
109
116
 
110
117
  static VALUE _native_stop(DDTRACE_UNUSED VALUE _self) {
111
- ddog_VoidResult result = ddog_crasht_shutdown();
118
+ ddog_VoidResult result = ddog_crasht_disable();
112
119
 
113
120
  if (result.tag == DDOG_VOID_RESULT_ERR) {
114
121
  rb_raise(rb_eRuntimeError, "Failed to stop the crash tracker: %"PRIsVALUE, get_error_details_and_drop(&result.err));
@@ -72,8 +72,8 @@ if ENV['DDTRACE_DEBUG'] == 'true'
72
72
  end
73
73
 
74
74
  # If we got here, libdatadog is available and loaded
75
- ENV['PKG_CONFIG_PATH'] = "#{ENV['PKG_CONFIG_PATH']}:#{Libdatadog.pkgconfig_folder}"
76
- Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV['PKG_CONFIG_PATH'].inspect}\n")
75
+ ENV['PKG_CONFIG_PATH'] = "#{ENV["PKG_CONFIG_PATH"]}:#{Libdatadog.pkgconfig_folder}"
76
+ Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV["PKG_CONFIG_PATH"].inspect}\n")
77
77
  $stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
78
78
 
79
79
  unless pkg_config('datadog_profiling_with_rpath')
@@ -7,6 +7,10 @@
7
7
  static VALUE _native_configurator_new(VALUE klass);
8
8
  static VALUE _native_configurator_get(VALUE self);
9
9
 
10
+ // Used for testing in RSpec
11
+ static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
12
+ static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
13
+
10
14
  static VALUE config_vec_class = Qnil;
11
15
 
12
16
  // ddog_Configurator memory management
@@ -52,20 +56,42 @@ void library_config_init(VALUE core_module) {
52
56
  rb_define_alloc_func(configurator_class, _native_configurator_new);
53
57
  rb_define_method(configurator_class, "get", _native_configurator_get, 0);
54
58
 
59
+ // Used for testing in RSpec
60
+ VALUE testing_module = rb_define_module_under(stable_config_module, "Testing");
61
+ rb_define_singleton_method(testing_module, "with_local_path", _native_configurator_with_local_path, 2);
62
+ rb_define_singleton_method(testing_module, "with_fleet_path", _native_configurator_with_fleet_path, 2);
63
+
55
64
  rb_undef_alloc_func(config_vec_class); // It cannot be created from Ruby code and only serves as an intermediate object for the Ruby GC
56
65
  }
57
66
 
58
- // TODO: After libdatadog 17.1 release, delete rb_raise, uncomment code and change `DDTRACE_UNUSED VALUE _klass` by `VALUE klass`
59
- static VALUE _native_configurator_new(DDTRACE_UNUSED VALUE _klass) {
60
- /*
67
+ static VALUE _native_configurator_new(VALUE klass) {
61
68
  ddog_Configurator *configurator = ddog_library_configurator_new(false, DDOG_CHARSLICE_C("ruby"));
62
69
 
63
70
  ddog_library_configurator_with_detect_process_info(configurator);
64
71
 
65
72
  return TypedData_Wrap_Struct(klass, &configurator_typed_data, configurator);
66
- */
73
+ }
74
+
75
+ static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
76
+ ddog_Configurator *configurator;
77
+ TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
78
+
79
+ ENFORCE_TYPE(path, T_STRING);
67
80
 
68
- rb_raise(rb_eNotImpError, "TODO: Not in use yet, waiting for libdatadog 17.1");
81
+ ddog_library_configurator_with_local_path(configurator, cstr_from_ruby_string(path));
82
+
83
+ return Qnil;
84
+ }
85
+
86
+ static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
87
+ ddog_Configurator *configurator;
88
+ TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
89
+
90
+ ENFORCE_TYPE(path, T_STRING);
91
+
92
+ ddog_library_configurator_with_fleet_path(configurator, cstr_from_ruby_string(path));
93
+
94
+ return Qnil;
69
95
  }
70
96
 
71
97
  static VALUE _native_configurator_get(VALUE self) {
@@ -96,26 +122,42 @@ static VALUE _native_configurator_get(VALUE self) {
96
122
 
97
123
  VALUE local_config_hash = rb_hash_new();
98
124
  VALUE fleet_config_hash = rb_hash_new();
99
- // TODO: Uncomment next block after libdatadog 17.1 release
100
- /*
125
+
126
+ bool local_config_id_set = false;
127
+ bool fleet_config_id_set = false;
128
+ VALUE local_hash = rb_hash_new();
129
+ VALUE fleet_hash = rb_hash_new();
101
130
  for (uintptr_t i = 0; i < config_vec->len; i++) {
102
131
  ddog_LibraryConfig config = config_vec->ptr[i];
103
132
  VALUE selected_hash;
104
133
  if (config.source == DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG) {
105
134
  selected_hash = local_config_hash;
135
+ if (!local_config_id_set) {
136
+ local_config_id_set = true;
137
+ if (config.config_id.length > 0) {
138
+ rb_hash_aset(local_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
139
+ }
140
+ }
106
141
  }
107
142
  else {
108
143
  selected_hash = fleet_config_hash;
144
+ if (!fleet_config_id_set) {
145
+ fleet_config_id_set = true;
146
+ if (config.config_id.length > 0) {
147
+ rb_hash_aset(fleet_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
148
+ }
149
+ }
109
150
  }
110
151
 
111
- ddog_CStr name = ddog_library_config_name_to_env(config.name);
112
- rb_hash_aset(selected_hash, rb_str_new(name.ptr, name.length), rb_str_new(config.value.ptr, config.value.length));
152
+ rb_hash_aset(selected_hash, rb_utf8_str_new_cstr(config.name.ptr), rb_utf8_str_new_cstr(config.value.ptr));
113
153
  }
114
- */
154
+
155
+ rb_hash_aset(local_hash, ID2SYM(rb_intern("config")), local_config_hash);
156
+ rb_hash_aset(fleet_hash, ID2SYM(rb_intern("config")), fleet_config_hash);
115
157
 
116
158
  VALUE result = rb_hash_new();
117
- rb_hash_aset(result, ID2SYM(rb_intern("local")), local_config_hash);
118
- rb_hash_aset(result, ID2SYM(rb_intern("fleet")), fleet_config_hash);
159
+ rb_hash_aset(result, ID2SYM(rb_intern("local")), local_hash);
160
+ rb_hash_aset(result, ID2SYM(rb_intern("fleet")), fleet_hash);
119
161
 
120
162
  RB_GC_GUARD(config_vec_rb);
121
163
  return result;
@@ -17,3 +17,9 @@ static inline VALUE log_warning_without_config(VALUE warning) {
17
17
 
18
18
  return rb_funcall(logger, rb_intern("warn"), 1, warning);
19
19
  }
20
+
21
+ static inline ddog_CStr cstr_from_ruby_string(VALUE string) {
22
+ ENFORCE_TYPE(string, T_STRING);
23
+ ddog_CStr cstr = {.ptr = RSTRING_PTR(string), .length = RSTRING_LEN(string)};
24
+ return cstr;
25
+ }
@@ -17,9 +17,9 @@ export DD_RUBY_PLATFORM=`ruby -e 'puts Gem::Platform.local.to_s'`
17
17
  mkdir -p my-libdatadog-build/$DD_RUBY_PLATFORM
18
18
  ```
19
19
 
20
- 5. Build libdatadog into this folder: `./build-profiling-ffi.sh my-libdatadog-build/$DD_RUBY_PLATFORM`
21
- 6. Tell the Ruby where to find libdatadog: `export LIBDATADOG_VENDOR_OVERRIDE=/full/path/to/my-libdatadog-build/` (Notice no platform here)
22
- 7. Run `bundle exec rake clean compile`
20
+ 5. From inside of the libdatadog repo, build libdatadog into this folder: `./build-profiling-ffi.sh my-libdatadog-build/$DD_RUBY_PLATFORM`
21
+ 6. Tell Ruby where to find libdatadog: `export LIBDATADOG_VENDOR_OVERRIDE=/full/path/to/my-libdatadog-build/` (Notice no platform here)
22
+ 7. From dd-trace-rb, run `bundle exec rake clean compile`
23
23
 
24
24
  If you additionally want to run the profiler test suite, also remember to `export DD_PROFILING_MACOS_TESTING=true` and re-run `rake clean compile`.
25
25
 
@@ -1,7 +1,7 @@
1
1
  #include <errno.h>
2
2
  #include <stdlib.h>
3
3
  #include <ruby.h>
4
- #include <datadog/common.h>
4
+ #include <datadog/library-config.h>
5
5
 
6
6
  #include "datadog_ruby_common.h"
7
7
 
@@ -36,8 +36,7 @@ void process_discovery_init(VALUE core_module) {
36
36
  rb_define_singleton_method(process_discovery_class, "_native_close_tracer_memfd", _native_close_tracer_memfd, 2);
37
37
  }
38
38
 
39
- // TODO: Remove DDTRACE_UNUSED and rename _self to self once we have updated libdatadog to 17.1
40
- static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
39
+ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
41
40
  VALUE logger;
42
41
  VALUE options;
43
42
  rb_scan_args(argc, argv, "1:", &logger, &options);
@@ -61,7 +60,6 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED
61
60
  ENFORCE_TYPE(service_env, T_STRING);
62
61
  ENFORCE_TYPE(service_version, T_STRING);
63
62
 
64
- /*
65
63
  ddog_Result_TracerMemfdHandle result = ddog_store_tracer_metadata(
66
64
  (uint8_t) NUM2UINT(schema_version),
67
65
  char_slice_from_ruby_string(runtime_id),
@@ -86,9 +84,6 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED
86
84
  VALUE tracer_memfd_class = rb_const_get(self, rb_intern("TracerMemfd"));
87
85
  VALUE tracer_memfd = TypedData_Wrap_Struct(tracer_memfd_class, &tracer_memfd_type, fd);
88
86
  return tracer_memfd;
89
- */
90
-
91
- rb_raise(rb_eNotImpError, "TODO: Not in use yet, waiting for libdatadog 17.1");
92
87
  }
93
88
 
94
89
  static VALUE _native_to_rb_int(DDTRACE_UNUSED VALUE _self, VALUE tracer_memfd) {
@@ -8,7 +8,7 @@ module Datadog
8
8
  module LibdatadogExtconfHelpers
9
9
  # Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
10
10
  # may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
11
- LIBDATADOG_VERSION = '~> 16.0.1.1.0'
11
+ LIBDATADOG_VERSION = '~> 18.1.0.1.0'
12
12
 
13
13
  # Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
14
14
  # libdatadog are moved after the extension gets compiled.
@@ -104,7 +104,7 @@ module Datadog
104
104
 
105
105
  # mkmf sets $PKGCONFIG after the `pkg_config` gets used in extconf.rb. When `pkg_config` is unsuccessful, we use
106
106
  # this helper to decide if we can show more specific error message vs a generic "something went wrong".
107
- def self.pkg_config_missing?(command: $PKGCONFIG) # rubocop:disable Style/GlobalVars
107
+ def self.pkg_config_missing?(command: $PKGCONFIG) # standard:disable Style/GlobalVars
108
108
  pkg_config_available = command && xsystem("#{command} --version")
109
109
 
110
110
  pkg_config_available != true
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Datadog
6
+ module AppSec
7
+ module APISecurity
8
+ # An LRU (Least Recently Used) cache implementation that relies on the
9
+ # Ruby 1.9+ `Hash` implementation that guarantees insertion order.
10
+ #
11
+ # WARNING: This implementation is NOT thread-safe and should be used
12
+ # in a single-threaded context.
13
+ class LRUCache
14
+ extend Forwardable
15
+
16
+ def_delegators :@store, :clear, :empty?
17
+
18
+ def initialize(max_size)
19
+ raise ArgumentError, 'max_size must be an Integer' unless max_size.is_a?(Integer)
20
+ raise ArgumentError, 'max_size must be greater than 0' if max_size <= 0
21
+
22
+ @max_size = max_size
23
+ @store = {}
24
+ end
25
+
26
+ # NOTE: Accessing a key moves it to the end of the list.
27
+ def [](key)
28
+ if (entry = @store.delete(key))
29
+ @store[key] = entry
30
+ end
31
+ end
32
+
33
+ def store(key, value)
34
+ return @store[key] = value if @store.delete(key)
35
+
36
+ # NOTE: evict the oldest entry if store reached the maximum allowed size
37
+ @store.shift if @store.size >= @max_size
38
+ @store[key] = value
39
+ end
40
+
41
+ # NOTE: If the key exists, it's moved to the end of the list and
42
+ # if does not, the given block will be executed and the result
43
+ # will be stored (which will add it to the end of the list).
44
+ def fetch_or_store(key)
45
+ if (entry = @store.delete(key))
46
+ return @store[key] = entry
47
+ end
48
+
49
+ # NOTE: evict the oldest entry if store reached the maximum allowed size
50
+ @store.shift if @store.size >= @max_size
51
+ @store[key] = yield
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end