datadog 2.14.0 → 2.16.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 (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -1
  3. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +7 -6
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  5. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  6. data/ext/datadog_profiling_native_extension/encoded_profile.c +69 -0
  7. data/ext/datadog_profiling_native_extension/encoded_profile.h +7 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  9. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  10. data/ext/datadog_profiling_native_extension/http_transport.c +25 -32
  11. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  12. data/ext/datadog_profiling_native_extension/stack_recorder.c +22 -21
  13. data/ext/libdatadog_api/crashtracker.c +1 -9
  14. data/ext/libdatadog_api/crashtracker.h +5 -0
  15. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  16. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  17. data/ext/libdatadog_api/init.c +15 -0
  18. data/ext/libdatadog_api/library_config.c +122 -0
  19. data/ext/libdatadog_api/library_config.h +19 -0
  20. data/ext/libdatadog_api/process_discovery.c +117 -0
  21. data/ext/libdatadog_api/process_discovery.h +5 -0
  22. data/lib/datadog/appsec/actions_handler.rb +3 -2
  23. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  24. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  25. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  26. data/lib/datadog/appsec/autoload.rb +1 -1
  27. data/lib/datadog/appsec/component.rb +29 -20
  28. data/lib/datadog/appsec/compressed_json.rb +40 -0
  29. data/lib/datadog/appsec/configuration/settings.rb +31 -18
  30. data/lib/datadog/appsec/context.rb +1 -1
  31. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  32. data/lib/datadog/appsec/contrib/active_record/integration.rb +2 -2
  33. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  34. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
  35. data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
  36. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
  38. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
  39. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  40. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  41. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  42. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  43. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  44. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  47. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
  48. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  49. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  50. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  51. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  52. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  53. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  54. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  55. data/lib/datadog/appsec/event.rb +95 -134
  56. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
  57. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  58. data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
  59. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  60. data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
  61. data/lib/datadog/appsec/processor.rb +1 -1
  62. data/lib/datadog/appsec/remote.rb +16 -11
  63. data/lib/datadog/appsec/response.rb +6 -6
  64. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  65. data/lib/datadog/appsec/security_event.rb +39 -0
  66. data/lib/datadog/appsec.rb +1 -1
  67. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  68. data/lib/datadog/core/configuration/components.rb +19 -10
  69. data/lib/datadog/core/configuration/option.rb +61 -25
  70. data/lib/datadog/core/configuration/settings.rb +10 -0
  71. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  72. data/lib/datadog/core/configuration.rb +24 -0
  73. data/lib/datadog/core/crashtracking/component.rb +1 -9
  74. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  75. data/lib/datadog/core/environment/git.rb +1 -0
  76. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  77. data/lib/datadog/core/metrics/client.rb +8 -7
  78. data/lib/datadog/core/process_discovery.rb +32 -0
  79. data/lib/datadog/core/remote/client.rb +7 -0
  80. data/lib/datadog/core/runtime/metrics.rb +1 -1
  81. data/lib/datadog/core/telemetry/component.rb +60 -50
  82. data/lib/datadog/core/telemetry/emitter.rb +17 -11
  83. data/lib/datadog/core/telemetry/event.rb +7 -4
  84. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  85. data/lib/datadog/core/telemetry/metric.rb +5 -5
  86. data/lib/datadog/core/telemetry/request.rb +4 -4
  87. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  88. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  89. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  90. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  91. data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
  92. data/lib/datadog/core/telemetry/worker.rb +45 -0
  93. data/lib/datadog/core/utils/time.rb +12 -0
  94. data/lib/datadog/core/workers/async.rb +20 -2
  95. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  96. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  97. data/lib/datadog/core.rb +8 -0
  98. data/lib/datadog/di/boot.rb +34 -0
  99. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  100. data/lib/datadog/di/remote.rb +2 -0
  101. data/lib/datadog/di/transport/http/diagnostics.rb +0 -1
  102. data/lib/datadog/di/transport/http/input.rb +0 -1
  103. data/lib/datadog/di/transport/http.rb +0 -6
  104. data/lib/datadog/di.rb +5 -32
  105. data/lib/datadog/error_tracking/collector.rb +87 -0
  106. data/lib/datadog/error_tracking/component.rb +167 -0
  107. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  108. data/lib/datadog/error_tracking/configuration.rb +11 -0
  109. data/lib/datadog/error_tracking/ext.rb +18 -0
  110. data/lib/datadog/error_tracking/extensions.rb +16 -0
  111. data/lib/datadog/error_tracking/filters.rb +77 -0
  112. data/lib/datadog/error_tracking.rb +18 -0
  113. data/lib/datadog/kit/identity.rb +1 -1
  114. data/lib/datadog/profiling/collectors/info.rb +3 -0
  115. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  116. data/lib/datadog/profiling/exporter.rb +3 -4
  117. data/lib/datadog/profiling/ext.rb +0 -1
  118. data/lib/datadog/profiling/flush.rb +4 -7
  119. data/lib/datadog/profiling/http_transport.rb +10 -59
  120. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  121. data/lib/datadog/profiling.rb +1 -0
  122. data/lib/datadog/tracing/analytics.rb +1 -1
  123. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  124. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  125. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  126. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  127. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  128. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  129. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  130. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  131. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  132. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  133. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  134. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  135. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  136. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  137. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  138. data/lib/datadog/tracing/span_event.rb +1 -1
  139. data/lib/datadog/tracing/span_operation.rb +38 -14
  140. data/lib/datadog/tracing/trace_operation.rb +15 -7
  141. data/lib/datadog/tracing/tracer.rb +7 -3
  142. data/lib/datadog/tracing/utils.rb +1 -1
  143. data/lib/datadog/version.rb +1 -1
  144. data/lib/datadog.rb +2 -3
  145. metadata +40 -10
  146. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  147. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  148. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  149. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6f1f9a8bd097f353792ce207813881aadce161aaef09d6790c551686de7d53e
4
- data.tar.gz: 34dbaf125e9b9a3ce3eec376546ae3817f42f3556033a27b83b69578372b2475
3
+ metadata.gz: da587b7c67d38c9ec9730e62603ffecf699d3841978676a06f0fe99506614a3d
4
+ data.tar.gz: d17d0f78fe1226187aedd815606ce3b450eb6150139c13116ce24082215452dd
5
5
  SHA512:
6
- metadata.gz: 07d6d7499521fb3ebb75574960e7eff4bd7e893dc8631b02b9a4db2201ed47afa0b294ab493a198c09b5bfe7e00e1d215ae61a45f4e8a756c2644e7a59ee56d9
7
- data.tar.gz: 31aa80c9ee735eef7dc676a72e7fe2b33fe996704a2a58c97386284af16fdf5fa6037269e6d7e1f3a4a2b823825a0e3cef0f36f3e04f45bf9c8907510d7d5e54
6
+ metadata.gz: 8d40c4f84ca2396f1011bc27eeb5489a1ded2669c47473a838d5b70191c57b3e34beee38abe8c9737d13212bbf07221ec17a0b428023974ec7001465bbfa7745
7
+ data.tar.gz: '0155923613825e859fb952901a98f2a779a5128b1cb02cf4e3c619fb99b1bf9b4a7428b1e56cb8580103d52cc189a354df9a1db697c5b857a8c318d2a383bdba'
data/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.16.0] - 2025-05-19
6
+
7
+ ### Added
8
+
9
+ * Core: Add new configuration precedence value `environment` ([#4610][])
10
+ * Core: Add Source Code Integration (SCI) tags in Telemetry app-started event and in each Remote Config request ([#4653][])
11
+ * Core: Tracing: ErrorTracking: Add automatic reporting of handled errors ([#4604][])
12
+ * AppSec: Integrations: Add session tracking and attacker fingerprinting to `devise` and `rails` ([#4644][], [#4625][])
13
+ * Profiling: Add support for Ruby 3.5.0-preview1 ([#4600][])
14
+ * Tracing: Add warning when `on_error` handler is not a `Proc` ([#4611][])
15
+ * Tracing: Integrations: Add option to serialize MongoDB command as JSON ([#4403][])
16
+ * Tracing: Integrations: Add baggage to `karafka` list of propagation styles ([#4614][])
17
+
18
+ ### Changed
19
+
20
+ * Tracing: Adjust trace sampling formula ([#4616][])
21
+ * Profiling: Replace `JSON.fast_generate` with `JSON.generate` ([#4602][])
22
+
23
+ ### Fixed
24
+
25
+ * Core: Fix Ruby warnings when providing a custom time provider ([#4613][])
26
+ * Core: Fix Telemetry configuration in agentless mode to respect the timeout specified for the Agent ([#4590][])
27
+ * Profiling: Fix profiler compatibility with ruby-head (3.5) ([#4656][])
28
+
29
+ ### Removed
30
+
31
+ * Core: Remove duplicated classes from Telemetry transport ([#4575][])
32
+
33
+ ## [2.15.0] - 2025-04-17
34
+
35
+ ### Added
36
+
37
+ * AppSec: Add auto-patching for `activerecord` with sql injection detection ([#4581][])
38
+ * Tracing: Add option for `opensearch` to set resource with relative path ([#4509][])
39
+
40
+ ### Changed
41
+
42
+ * AppSec: Update In-App WAF rules, processors, and scanners ([#4568][])
43
+
44
+ ### Fixed
45
+
46
+ * AppSec: Fix blocked requests not marked correctly when using custom redirect blocking action ([#4580][])
47
+ * AppSec: Fix UTF-8 unsafe payloads in InApp-WAF causing runtime exceptions ([#4573][])
48
+
5
49
  ## [2.14.0] - 2025-04-04
6
50
 
7
51
  ### Added
@@ -3178,7 +3222,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3178
3222
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3179
3223
 
3180
3224
 
3181
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.14.0...master
3225
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.16.0...master
3226
+ [2.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.15.0...v2.16.0
3227
+ [2.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.14.0...v2.15.0
3182
3228
  [2.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.13.0...v2.14.0
3183
3229
  [2.13.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.2...v2.13.0
3184
3230
  [2.12.2]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.1...v2.12.2
@@ -4679,6 +4725,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4679
4725
  [#4391]: https://github.com/DataDog/dd-trace-rb/issues/4391
4680
4726
  [#4398]: https://github.com/DataDog/dd-trace-rb/issues/4398
4681
4727
  [#4399]: https://github.com/DataDog/dd-trace-rb/issues/4399
4728
+ [#4403]: https://github.com/DataDog/dd-trace-rb/issues/4403
4682
4729
  [#4406]: https://github.com/DataDog/dd-trace-rb/issues/4406
4683
4730
  [#4411]: https://github.com/DataDog/dd-trace-rb/issues/4411
4684
4731
  [#4422]: https://github.com/DataDog/dd-trace-rb/issues/4422
@@ -4693,6 +4740,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4693
4740
  [#4498]: https://github.com/DataDog/dd-trace-rb/issues/4498
4694
4741
  [#4505]: https://github.com/DataDog/dd-trace-rb/issues/4505
4695
4742
  [#4507]: https://github.com/DataDog/dd-trace-rb/issues/4507
4743
+ [#4509]: https://github.com/DataDog/dd-trace-rb/issues/4509
4696
4744
  [#4526]: https://github.com/DataDog/dd-trace-rb/issues/4526
4697
4745
  [#4528]: https://github.com/DataDog/dd-trace-rb/issues/4528
4698
4746
  [#4530]: https://github.com/DataDog/dd-trace-rb/issues/4530
@@ -4701,6 +4749,24 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4701
4749
  [#4549]: https://github.com/DataDog/dd-trace-rb/issues/4549
4702
4750
  [#4552]: https://github.com/DataDog/dd-trace-rb/issues/4552
4703
4751
  [#4558]: https://github.com/DataDog/dd-trace-rb/issues/4558
4752
+ [#4568]: https://github.com/DataDog/dd-trace-rb/issues/4568
4753
+ [#4573]: https://github.com/DataDog/dd-trace-rb/issues/4573
4754
+ [#4575]: https://github.com/DataDog/dd-trace-rb/issues/4575
4755
+ [#4580]: https://github.com/DataDog/dd-trace-rb/issues/4580
4756
+ [#4581]: https://github.com/DataDog/dd-trace-rb/issues/4581
4757
+ [#4590]: https://github.com/DataDog/dd-trace-rb/issues/4590
4758
+ [#4600]: https://github.com/DataDog/dd-trace-rb/issues/4600
4759
+ [#4602]: https://github.com/DataDog/dd-trace-rb/issues/4602
4760
+ [#4604]: https://github.com/DataDog/dd-trace-rb/issues/4604
4761
+ [#4610]: https://github.com/DataDog/dd-trace-rb/issues/4610
4762
+ [#4611]: https://github.com/DataDog/dd-trace-rb/issues/4611
4763
+ [#4613]: https://github.com/DataDog/dd-trace-rb/issues/4613
4764
+ [#4614]: https://github.com/DataDog/dd-trace-rb/issues/4614
4765
+ [#4616]: https://github.com/DataDog/dd-trace-rb/issues/4616
4766
+ [#4625]: https://github.com/DataDog/dd-trace-rb/issues/4625
4767
+ [#4644]: https://github.com/DataDog/dd-trace-rb/issues/4644
4768
+ [#4653]: https://github.com/DataDog/dd-trace-rb/issues/4653
4769
+ [#4656]: https://github.com/DataDog/dd-trace-rb/issues/4656
4704
4770
  [@AdrianLC]: https://github.com/AdrianLC
4705
4771
  [@Azure7111]: https://github.com/Azure7111
4706
4772
  [@BabyGroot]: https://github.com/BabyGroot
@@ -297,7 +297,7 @@ static void otel_without_ddtrace_trace_identifiers_for(
297
297
  static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key);
298
298
  static uint64_t otel_span_id_to_uint(VALUE otel_span_id);
299
299
  static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key);
300
- static VALUE _native_reset_monotonic_to_system_state(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
300
+ static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
301
301
 
302
302
  void collectors_thread_context_init(VALUE profiling_module) {
303
303
  VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
@@ -329,7 +329,7 @@ void collectors_thread_context_init(VALUE profiling_module) {
329
329
  rb_define_singleton_method(testing_module, "_native_gc_tracking", _native_gc_tracking, 1);
330
330
  rb_define_singleton_method(testing_module, "_native_new_empty_thread", _native_new_empty_thread, 0);
331
331
  rb_define_singleton_method(testing_module, "_native_sample_skipped_allocation_samples", _native_sample_skipped_allocation_samples, 2);
332
- rb_define_singleton_method(testing_module, "_native_reset_monotonic_to_system_state", _native_reset_monotonic_to_system_state, 1);
332
+ rb_define_singleton_method(testing_module, "_native_system_epoch_time_now_ns", _native_system_epoch_time_now_ns, 1);
333
333
  #ifndef NO_GVL_INSTRUMENTATION
334
334
  rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
335
335
  rb_define_singleton_method(testing_module, "_native_gvl_waiting_at_for", _native_gvl_waiting_at_for, 1);
@@ -1308,7 +1308,7 @@ static long thread_id_for(VALUE thread) {
1308
1308
  }
1309
1309
 
1310
1310
  VALUE enforce_thread_context_collector_instance(VALUE object) {
1311
- Check_TypedStruct(object, &thread_context_collector_typed_data);
1311
+ ENFORCE_TYPED_DATA(object, &thread_context_collector_typed_data);
1312
1312
  return object;
1313
1313
  }
1314
1314
 
@@ -2160,11 +2160,12 @@ static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE k
2160
2160
  return state.result;
2161
2161
  }
2162
2162
 
2163
- static VALUE _native_reset_monotonic_to_system_state(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
2163
+ static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
2164
2164
  thread_context_collector_state *state;
2165
2165
  TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
2166
2166
 
2167
- state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
2167
+ long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
2168
+ long system_epoch_time_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns);
2168
2169
 
2169
- return Qtrue;
2170
+ return LONG2NUM(system_epoch_time_ns);
2170
2171
  }
@@ -29,10 +29,7 @@ VALUE datadog_gem_version(void) {
29
29
  }
30
30
 
31
31
  static VALUE log_failure_to_process_tag(VALUE err_details) {
32
- VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
33
- VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
34
-
35
- return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
32
+ return log_warning(rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
36
33
  }
37
34
 
38
35
  __attribute__((warn_unused_result))
@@ -27,6 +27,9 @@
27
27
  #define ENFORCE_BOOLEAN(value) \
28
28
  { if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
29
29
 
30
+ #define ENFORCE_TYPED_DATA(value, type) \
31
+ { if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), "TypedData of type " ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
32
+
30
33
  NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
31
34
 
32
35
  // Helper to retrieve Datadog::VERSION::STRING
@@ -38,6 +41,13 @@ static inline ddog_CharSlice char_slice_from_ruby_string(VALUE string) {
38
41
  return char_slice;
39
42
  }
40
43
 
44
+ static inline VALUE log_warning(VALUE warning) {
45
+ VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
46
+ VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
47
+
48
+ return rb_funcall(logger, rb_intern("warn"), 1, warning);
49
+ }
50
+
41
51
  __attribute__((warn_unused_result))
42
52
  ddog_Vec_Tag convert_tags(VALUE tags_as_array);
43
53
 
@@ -0,0 +1,69 @@
1
+ #include "encoded_profile.h"
2
+ #include "datadog_ruby_common.h"
3
+ #include "libdatadog_helpers.h"
4
+
5
+ // This class exists to wrap a ddog_prof_EncodedProfile into a Ruby object
6
+ // This file implements the native bits of the Datadog::Profiling::EncodedProfile class
7
+
8
+ static void encoded_profile_typed_data_free(void *state_ptr);
9
+ static VALUE _native_bytes(VALUE self);
10
+
11
+ static VALUE encoded_profile_class = Qnil;
12
+
13
+ void encoded_profile_init(VALUE profiling_module) {
14
+ encoded_profile_class = rb_define_class_under(profiling_module, "EncodedProfile", rb_cObject);
15
+
16
+ rb_undef_alloc_func(encoded_profile_class); // Class cannot be created from Ruby code
17
+ rb_global_variable(&encoded_profile_class);
18
+
19
+ rb_define_method(encoded_profile_class, "_native_bytes", _native_bytes, 0);
20
+ }
21
+
22
+ // This structure is used to define a Ruby object that stores a `ddog_prof_EncodedProfile`
23
+ // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
24
+ static const rb_data_type_t encoded_profile_typed_data = {
25
+ .wrap_struct_name = "Datadog::Profiling::EncodedProfile",
26
+ .function = {
27
+ .dmark = NULL, // We don't store references to Ruby objects so we don't need to mark any of them
28
+ .dfree = encoded_profile_typed_data_free,
29
+ .dsize = NULL, // We don't track memory usage (although it'd be cool if we did!)
30
+ //.dcompact = NULL, // Not needed -- we don't store references to Ruby objects
31
+ },
32
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
33
+ };
34
+
35
+ VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile) {
36
+ ddog_prof_EncodedProfile *state = ruby_xcalloc(1, sizeof(ddog_prof_EncodedProfile));
37
+ *state = profile;
38
+ return TypedData_Wrap_Struct(encoded_profile_class, &encoded_profile_typed_data, state);
39
+ }
40
+
41
+ static void encoded_profile_typed_data_free(void *state_ptr) {
42
+ ddog_prof_EncodedProfile *state = (ddog_prof_EncodedProfile *) state_ptr;
43
+
44
+ // This drops the profile itself
45
+ ddog_prof_EncodedProfile_drop(state);
46
+
47
+ // This drops the tiny bit of memory we allocated to contain the ` ddog_prof_EncodedProfile` struct
48
+ ruby_xfree(state);
49
+ }
50
+
51
+ static VALUE _native_bytes(VALUE self) {
52
+ ddog_prof_EncodedProfile *state;
53
+ TypedData_Get_Struct(self, ddog_prof_EncodedProfile, &encoded_profile_typed_data, state);
54
+
55
+ return ruby_string_from_vec_u8(state->buffer);
56
+
57
+ // TODO: This will be used for libdatadog 17
58
+ /*ddog_prof_Result_ByteSlice raw_bytes = ddog_prof_EncodedProfile_bytes(state);
59
+ if (raw_bytes.tag == DDOG_PROF_RESULT_BYTE_SLICE_ERR_BYTE_SLICE) {
60
+ rb_raise(rb_eRuntimeError, "Failed to get bytes from profile: %"PRIsVALUE, get_error_details_and_drop(&raw_bytes.err));
61
+ }
62
+
63
+ return rb_str_new((const char *) raw_bytes.ok.ptr, raw_bytes.ok.len);*/
64
+ }
65
+
66
+ VALUE enforce_encoded_profile_instance(VALUE object) {
67
+ ENFORCE_TYPED_DATA(object, &encoded_profile_typed_data);
68
+ return object;
69
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+ #include <datadog/profiling.h>
5
+
6
+ VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile);
7
+ VALUE enforce_encoded_profile_instance(VALUE object);
@@ -131,6 +131,9 @@ end
131
131
 
132
132
  have_func "malloc_stats"
133
133
 
134
+ # On Ruby 3.5, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
135
+ $defs << "-DNO_IMEMO_OBJECT_ID" unless RUBY_VERSION < "3.5"
136
+
134
137
  # On Ruby 2.5 and 3.3, this symbol was not visible. It is on 2.6 to 3.2, as well as 3.4+
135
138
  $defs << "-DNO_RB_OBJ_INFO" if RUBY_VERSION.start_with?("2.5", "3.3")
136
139
 
@@ -314,7 +314,14 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
314
314
  rb_raise(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
315
315
  }
316
316
 
317
- if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate) {
317
+ if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate ||
318
+ #ifdef NO_IMEMO_OBJECT_ID
319
+ // On Ruby 3.5, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
320
+ RB_BUILTIN_TYPE(new_obj) == RUBY_T_IMEMO
321
+ #else
322
+ false
323
+ #endif
324
+ ) {
318
325
  heap_recorder->active_recording = &SKIPPED_RECORD;
319
326
  return;
320
327
  }
@@ -4,6 +4,7 @@
4
4
  #include "helpers.h"
5
5
  #include "libdatadog_helpers.h"
6
6
  #include "ruby_helpers.h"
7
+ #include "encoded_profile.h"
7
8
 
8
9
  // Used to report profiling data to Datadog.
9
10
  // This file implements the native bits of the Datadog::Profiling::HttpTransport class
@@ -29,17 +30,11 @@ static VALUE _native_do_export(
29
30
  VALUE self,
30
31
  VALUE exporter_configuration,
31
32
  VALUE upload_timeout_milliseconds,
33
+ VALUE flush,
32
34
  VALUE start_timespec_seconds,
33
35
  VALUE start_timespec_nanoseconds,
34
36
  VALUE finish_timespec_seconds,
35
- VALUE finish_timespec_nanoseconds,
36
- VALUE pprof_file_name,
37
- VALUE pprof_data,
38
- VALUE code_provenance_file_name,
39
- VALUE code_provenance_data,
40
- VALUE tags_as_array,
41
- VALUE internal_metadata_json,
42
- VALUE info_json
37
+ VALUE finish_timespec_nanoseconds
43
38
  );
44
39
  static void *call_exporter_without_gvl(void *call_args);
45
40
  static void interrupt_exporter_call(void *cancel_token);
@@ -48,7 +43,7 @@ void http_transport_init(VALUE profiling_module) {
48
43
  VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
49
44
 
50
45
  rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
51
- rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 13);
46
+ rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 7);
52
47
 
53
48
  ok_symbol = ID2SYM(rb_intern_const("ok"));
54
49
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -84,22 +79,17 @@ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
84
79
  ENFORCE_TYPE(exporter_working_mode, T_SYMBOL);
85
80
  ID working_mode = SYM2ID(exporter_working_mode);
86
81
 
87
- ID agentless_id = rb_intern("agentless");
88
- ID agent_id = rb_intern("agent");
89
-
90
- if (working_mode != agentless_id && working_mode != agent_id) {
91
- rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
92
- }
93
-
94
- if (working_mode == agentless_id) {
82
+ if (working_mode == rb_intern("agentless")) {
95
83
  VALUE site = rb_ary_entry(exporter_configuration, 1);
96
84
  VALUE api_key = rb_ary_entry(exporter_configuration, 2);
97
85
 
98
86
  return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
99
- } else { // agent_id
87
+ } else if (working_mode == rb_intern("agent")) {
100
88
  VALUE base_url = rb_ary_entry(exporter_configuration, 1);
101
89
 
102
90
  return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
91
+ } else {
92
+ rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
103
93
  }
104
94
  }
105
95
 
@@ -139,7 +129,6 @@ static VALUE perform_export(
139
129
  ddog_Timespec finish,
140
130
  ddog_prof_Exporter_Slice_File files_to_compress_and_export,
141
131
  ddog_prof_Exporter_Slice_File files_to_export_unmodified,
142
- ddog_Vec_Tag *additional_tags,
143
132
  ddog_CharSlice internal_metadata,
144
133
  ddog_CharSlice info
145
134
  ) {
@@ -150,7 +139,7 @@ static VALUE perform_export(
150
139
  finish,
151
140
  files_to_compress_and_export,
152
141
  files_to_export_unmodified,
153
- additional_tags,
142
+ /* optional_additional_tags: */ NULL,
154
143
  endpoints_stats,
155
144
  &internal_metadata,
156
145
  &info
@@ -214,26 +203,27 @@ static VALUE _native_do_export(
214
203
  DDTRACE_UNUSED VALUE _self,
215
204
  VALUE exporter_configuration,
216
205
  VALUE upload_timeout_milliseconds,
206
+ VALUE flush,
217
207
  VALUE start_timespec_seconds,
218
208
  VALUE start_timespec_nanoseconds,
219
209
  VALUE finish_timespec_seconds,
220
- VALUE finish_timespec_nanoseconds,
221
- VALUE pprof_file_name,
222
- VALUE pprof_data,
223
- VALUE code_provenance_file_name,
224
- VALUE code_provenance_data,
225
- VALUE tags_as_array,
226
- VALUE internal_metadata_json,
227
- VALUE info_json
210
+ VALUE finish_timespec_nanoseconds
228
211
  ) {
212
+ VALUE encoded_profile = rb_funcall(flush, rb_intern("encoded_profile"), 0);
213
+ VALUE code_provenance_file_name = rb_funcall(flush, rb_intern("code_provenance_file_name"), 0);
214
+ VALUE code_provenance_data = rb_funcall(flush, rb_intern("code_provenance_data"), 0);
215
+ VALUE tags_as_array = rb_funcall(flush, rb_intern("tags_as_array"), 0);
216
+ VALUE internal_metadata_json = rb_funcall(flush, rb_intern("internal_metadata_json"), 0);
217
+ VALUE info_json = rb_funcall(flush, rb_intern("info_json"), 0);
218
+
229
219
  ENFORCE_TYPE(upload_timeout_milliseconds, T_FIXNUM);
230
220
  ENFORCE_TYPE(start_timespec_seconds, T_FIXNUM);
231
221
  ENFORCE_TYPE(start_timespec_nanoseconds, T_FIXNUM);
232
222
  ENFORCE_TYPE(finish_timespec_seconds, T_FIXNUM);
233
223
  ENFORCE_TYPE(finish_timespec_nanoseconds, T_FIXNUM);
234
- ENFORCE_TYPE(pprof_file_name, T_STRING);
235
- ENFORCE_TYPE(pprof_data, T_STRING);
224
+ enforce_encoded_profile_instance(encoded_profile);
236
225
  ENFORCE_TYPE(code_provenance_file_name, T_STRING);
226
+ ENFORCE_TYPE(tags_as_array, T_ARRAY);
237
227
  ENFORCE_TYPE(internal_metadata_json, T_STRING);
238
228
  ENFORCE_TYPE(info_json, T_STRING);
239
229
 
@@ -256,6 +246,11 @@ static VALUE _native_do_export(
256
246
  ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
257
247
  ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
258
248
 
249
+ // TODO: Hardcoding the file name will go away with libdatadog 17
250
+ VALUE pprof_file_name = rb_str_new_cstr("rubyprofile.pprof");
251
+ VALUE pprof_data = rb_funcall(encoded_profile, rb_intern("_native_bytes"), 0);
252
+ ENFORCE_TYPE(pprof_data, T_STRING);
253
+
259
254
  already_compressed[0] = (ddog_prof_Exporter_File) {
260
255
  .name = char_slice_from_ruby_string(pprof_file_name),
261
256
  .file = byte_slice_from_ruby_string(pprof_data),
@@ -268,7 +263,6 @@ static VALUE _native_do_export(
268
263
  };
269
264
  }
270
265
 
271
- ddog_Vec_Tag *null_additional_tags = NULL;
272
266
  ddog_CharSlice internal_metadata = char_slice_from_ruby_string(internal_metadata_json);
273
267
  ddog_CharSlice info = char_slice_from_ruby_string(info_json);
274
268
 
@@ -293,7 +287,6 @@ static VALUE _native_do_export(
293
287
  finish,
294
288
  files_to_compress_and_export,
295
289
  files_to_export_unmodified,
296
- null_additional_tags,
297
290
  internal_metadata,
298
291
  info
299
292
  );
@@ -20,6 +20,7 @@ void collectors_dynamic_sampling_rate_init(VALUE profiling_module);
20
20
  void collectors_idle_sampling_helper_init(VALUE profiling_module);
21
21
  void collectors_stack_init(VALUE profiling_module);
22
22
  void collectors_thread_context_init(VALUE profiling_module);
23
+ void encoded_profile_init(VALUE profiling_module);
23
24
  void http_transport_init(VALUE profiling_module);
24
25
  void stack_recorder_init(VALUE profiling_module);
25
26
 
@@ -61,6 +62,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
61
62
  collectors_idle_sampling_helper_init(profiling_module);
62
63
  collectors_stack_init(profiling_module);
63
64
  collectors_thread_context_init(profiling_module);
65
+ encoded_profile_init(profiling_module);
64
66
  http_transport_init(profiling_module);
65
67
  stack_recorder_init(profiling_module);
66
68
  unsafe_api_calls_check_init();
@@ -8,6 +8,7 @@
8
8
  #include "ruby_helpers.h"
9
9
  #include "time_helpers.h"
10
10
  #include "heap_recorder.h"
11
+ #include "encoded_profile.h"
11
12
 
12
13
  // Used to wrap a ddog_prof_Profile in a Ruby object and expose Ruby-level serialization APIs
13
14
  // This file implements the native bits of the Datadog::Profiling::StackRecorder class
@@ -181,6 +182,7 @@ typedef struct {
181
182
  typedef struct {
182
183
  ddog_prof_Profile profile;
183
184
  stats_slot stats;
185
+ ddog_Timespec start_timestamp;
184
186
  } profile_slot;
185
187
 
186
188
  // Contains native state for each instance
@@ -252,7 +254,7 @@ static ddog_Timespec system_epoch_now_timespec(void);
252
254
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
253
255
  static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time);
254
256
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
255
- static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */);
257
+ static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
256
258
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
257
259
  static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
258
260
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
@@ -358,24 +360,26 @@ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
358
360
  }
359
361
 
360
362
  static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
363
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
364
+
361
365
  ddog_prof_Profile_NewResult slot_one_profile_result =
362
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
366
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
363
367
 
364
368
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
365
369
  rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
366
370
  }
367
371
 
368
- state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok };
372
+ state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
369
373
 
370
374
  ddog_prof_Profile_NewResult slot_two_profile_result =
371
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
375
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
372
376
 
373
377
  if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
374
378
  // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
375
379
  rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
376
380
  }
377
381
 
378
- state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok };
382
+ state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
379
383
  }
380
384
 
381
385
  static void stack_recorder_typed_data_free(void *state_ptr) {
@@ -564,18 +568,14 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
564
568
 
565
569
  state->stats_lifetime.serialization_successes++;
566
570
 
567
- VALUE encoded_pprof = ruby_string_from_vec_u8(serialized_profile.ok.buffer);
568
-
569
- ddog_Timespec ddprof_start = serialized_profile.ok.start;
570
- ddog_Timespec ddprof_finish = serialized_profile.ok.end;
571
+ // Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it
572
+ VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
571
573
 
572
- ddog_prof_EncodedProfile_drop(&serialized_profile.ok);
573
-
574
- VALUE start = ruby_time_from(ddprof_start);
575
- VALUE finish = ruby_time_from(ddprof_finish);
574
+ VALUE start = ruby_time_from(args.slot->start_timestamp);
575
+ VALUE finish = ruby_time_from(finish_timestamp);
576
576
  VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
577
577
 
578
- return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_pprof, profile_stats));
578
+ return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
579
579
  }
580
580
 
581
581
  static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
@@ -780,7 +780,7 @@ static void *call_serialize_without_gvl(void *call_args) {
780
780
  }
781
781
 
782
782
  VALUE enforce_recorder_instance(VALUE object) {
783
- Check_TypedStruct(object, &stack_recorder_typed_data);
783
+ ENFORCE_TYPED_DATA(object, &stack_recorder_typed_data);
784
784
  return object;
785
785
  }
786
786
 
@@ -889,9 +889,9 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
889
889
  // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
890
890
  // resulting state is inconsistent, we make sure to reset it back to the initial state.
891
891
  initialize_slot_concurrency_control(state);
892
-
893
- reset_profile_slot(&state->profile_slot_one, /* start_time: */ NULL);
894
- reset_profile_slot(&state->profile_slot_two, /* start_time: */ NULL);
892
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
893
+ reset_profile_slot(&state->profile_slot_one, start_timestamp);
894
+ reset_profile_slot(&state->profile_slot_two, start_timestamp);
895
895
 
896
896
  heap_recorder_after_fork(state->heap_recorder);
897
897
 
@@ -903,7 +903,7 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
903
903
  static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) {
904
904
  // Before making this profile active, we reset it so that it uses the correct start_time for its start
905
905
  profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one;
906
- reset_profile_slot(next_profile_slot, &start_time);
906
+ reset_profile_slot(next_profile_slot, start_time);
907
907
  }
908
908
 
909
909
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
@@ -948,11 +948,12 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
948
948
  return Qnil;
949
949
  }
950
950
 
951
- static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */) {
952
- ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile, start_time);
951
+ 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);
953
953
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
954
954
  rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
955
955
  }
956
+ slot->start_timestamp = start_timestamp;
956
957
  slot->stats = (stats_slot) {};
957
958
  }
958
959
 
@@ -5,20 +5,12 @@
5
5
 
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
- static void crashtracker_init(VALUE crashtracking_module);
9
8
 
10
9
  // Used to report Ruby VM crashes.
11
10
  // Once initialized, segfaults will be reported automatically using libdatadog.
12
11
 
13
- void DDTRACE_EXPORT Init_libdatadog_api(void) {
14
- VALUE datadog_module = rb_define_module("Datadog");
15
- VALUE core_module = rb_define_module_under(datadog_module, "Core");
12
+ void crashtracker_init(VALUE core_module) {
16
13
  VALUE crashtracking_module = rb_define_module_under(core_module, "Crashtracking");
17
-
18
- crashtracker_init(crashtracking_module);
19
- }
20
-
21
- void crashtracker_init(VALUE crashtracking_module) {
22
14
  VALUE crashtracker_class = rb_define_class_under(crashtracking_module, "Component", rb_cObject);
23
15
 
24
16
  rb_define_singleton_method(crashtracker_class, "_native_start_or_update_on_fork", _native_start_or_update_on_fork, -1);
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include "datadog_ruby_common.h"
4
+
5
+ void crashtracker_init(VALUE core_module);
@@ -29,10 +29,7 @@ VALUE datadog_gem_version(void) {
29
29
  }
30
30
 
31
31
  static VALUE log_failure_to_process_tag(VALUE err_details) {
32
- VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
33
- VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
34
-
35
- return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
32
+ return log_warning(rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
36
33
  }
37
34
 
38
35
  __attribute__((warn_unused_result))
@@ -27,6 +27,9 @@
27
27
  #define ENFORCE_BOOLEAN(value) \
28
28
  { if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
29
29
 
30
+ #define ENFORCE_TYPED_DATA(value, type) \
31
+ { if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), "TypedData of type " ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
32
+
30
33
  NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
31
34
 
32
35
  // Helper to retrieve Datadog::VERSION::STRING
@@ -38,6 +41,13 @@ static inline ddog_CharSlice char_slice_from_ruby_string(VALUE string) {
38
41
  return char_slice;
39
42
  }
40
43
 
44
+ static inline VALUE log_warning(VALUE warning) {
45
+ VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
46
+ VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
47
+
48
+ return rb_funcall(logger, rb_intern("warn"), 1, warning);
49
+ }
50
+
41
51
  __attribute__((warn_unused_result))
42
52
  ddog_Vec_Tag convert_tags(VALUE tags_as_array);
43
53