datadog 2.9.0 → 2.11.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 (131) 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 +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +46 -6
  7. data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
  8. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  9. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  10. data/ext/datadog_profiling_native_extension/heap_recorder.c +51 -93
  11. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  12. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +56 -0
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
  14. data/ext/datadog_profiling_native_extension/profiling.c +7 -0
  15. data/ext/datadog_profiling_native_extension/stack_recorder.c +9 -22
  16. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  17. data/ext/libdatadog_api/crashtracker.c +4 -4
  18. data/ext/libdatadog_extconf_helpers.rb +1 -1
  19. data/lib/datadog/appsec/actions_handler.rb +27 -0
  20. data/lib/datadog/appsec/component.rb +14 -8
  21. data/lib/datadog/appsec/configuration/settings.rb +73 -11
  22. data/lib/datadog/appsec/context.rb +28 -8
  23. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +6 -2
  24. data/lib/datadog/appsec/contrib/active_record/patcher.rb +0 -3
  25. data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
  26. data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
  27. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
  28. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
  29. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
  30. data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
  31. data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
  32. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  33. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  34. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
  35. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  36. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  37. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  38. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  39. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
  40. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  41. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +11 -14
  42. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  43. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +65 -70
  44. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  45. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +3 -3
  46. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +11 -22
  47. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -24
  48. data/lib/datadog/appsec/contrib/rails/patcher.rb +3 -16
  49. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -47
  50. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +3 -29
  51. data/lib/datadog/appsec/ext.rb +6 -1
  52. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  53. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  54. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  55. data/lib/datadog/appsec/metrics.rb +13 -0
  56. data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -24
  57. data/lib/datadog/appsec/processor.rb +4 -3
  58. data/lib/datadog/appsec/remote.rb +4 -0
  59. data/lib/datadog/appsec/response.rb +18 -80
  60. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  61. data/lib/datadog/appsec/security_engine/runner.rb +88 -0
  62. data/lib/datadog/appsec/security_engine.rb +9 -0
  63. data/lib/datadog/appsec.rb +16 -5
  64. data/lib/datadog/core/configuration/components.rb +7 -1
  65. data/lib/datadog/core/configuration/ext.rb +1 -1
  66. data/lib/datadog/core/configuration/option_definition.rb +2 -0
  67. data/lib/datadog/core/configuration/settings.rb +22 -6
  68. data/lib/datadog/core/encoding.rb +16 -0
  69. data/lib/datadog/core/environment/agent_info.rb +77 -0
  70. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  71. data/lib/datadog/core/remote/transport/http/config.rb +0 -18
  72. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
  73. data/lib/datadog/core/remote/transport/http.rb +7 -12
  74. data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
  75. data/lib/datadog/core/telemetry/event.rb +5 -0
  76. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  77. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
  78. data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
  79. data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
  80. data/lib/datadog/core/transport/response.rb +4 -0
  81. data/lib/datadog/di/code_tracker.rb +15 -8
  82. data/lib/datadog/di/component.rb +3 -0
  83. data/lib/datadog/di/configuration/settings.rb +14 -0
  84. data/lib/datadog/di/contrib.rb +2 -0
  85. data/lib/datadog/di/logger.rb +30 -0
  86. data/lib/datadog/di/probe.rb +3 -6
  87. data/lib/datadog/di/probe_manager.rb +5 -2
  88. data/lib/datadog/di/probe_notification_builder.rb +6 -0
  89. data/lib/datadog/di/probe_notifier_worker.rb +15 -4
  90. data/lib/datadog/di/redactor.rb +0 -1
  91. data/lib/datadog/di/remote.rb +29 -8
  92. data/lib/datadog/di/utils.rb +91 -0
  93. data/lib/datadog/di.rb +3 -0
  94. data/lib/datadog/profiling/component.rb +2 -8
  95. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  96. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  97. data/lib/datadog/tracing/contrib/aws/integration.rb +1 -1
  98. data/lib/datadog/tracing/contrib/extensions.rb +29 -3
  99. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  100. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  101. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  102. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  103. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  104. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  105. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  106. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  107. data/lib/datadog/tracing/transport/http/api.rb +11 -2
  108. data/lib/datadog/tracing/transport/http/traces.rb +0 -3
  109. data/lib/datadog/tracing/transport/http.rb +12 -7
  110. data/lib/datadog/tracing/transport/serializable_trace.rb +8 -4
  111. data/lib/datadog/tracing/transport/traces.rb +25 -8
  112. data/lib/datadog/version.rb +1 -1
  113. metadata +51 -42
  114. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  115. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  116. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  117. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  118. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  119. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  120. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  121. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  122. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  123. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  124. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  125. data/lib/datadog/appsec/processor/context.rb +0 -107
  126. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  127. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  128. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  129. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  130. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  131. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5666f79db7cd7abdb43c961e51978ef2711ec4566ba8090ebafeb074d06dec33
4
- data.tar.gz: 907d0787aedf67f9db8ff57a2f16b6216cbc5514bb2a47005026f0e5263e7168
3
+ metadata.gz: ae1f5db840520c849d4a21b02232137e5272619ddd7fb46126f263c71c8a5849
4
+ data.tar.gz: bd1b16b752c9e457722965ee29cf8af770ba1dcf3b42cac412c206f6245dd333
5
5
  SHA512:
6
- metadata.gz: 22a55675bb273845ec829245812e9f447767878d924083d505ddc8ec6dc97c28770252b3bbb25f0811ab4bf92e44bf2e7439815b61bc14c8d98a8025c7f1db13
7
- data.tar.gz: 6a71cfdfbb3bd78949c23e11cbfcc9cea6a582925812862e0ff9a8c8f6ecded1807ee0d52e36c4422cb49181e0138e5e5d566a9895ccf46c0a0cd91fc74cfd64
6
+ metadata.gz: 072e88d7ba0698a8ef6b080b6b1ab6a5be18b4a69fdb142b42494bc0afc6184aadbe7c4f52e54e2373a37f40fe439215a8a9a4594653d4d6453ef614142ca8e7
7
+ data.tar.gz: 88cb6087f42bc450a517d53338772b4fb10b00fe40024843fec3df3849bbc14f6efd25defaf1dcadb9224c9513878c75e2ee33fb0d3d24bb063ca1d2dd36dcb6
data/CHANGELOG.md CHANGED
@@ -2,6 +2,53 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.11.0] - 2025-02-24
6
+
7
+ ### Added
8
+
9
+ * Tracing: Support `graphql` multiple query errors report via Span Events ([#4177][])
10
+ * Profiling: Enable GVL profiling by default on Ruby 3.2+ ([#4406][])
11
+ * Profiling: Support correlating profiling with OTel API 1.5+ ([#4425][])
12
+ * AppSec: Add detection of Server-Side Request Forgery attacks for `excon` ([#4399][])
13
+ * AppSec: Add detection of Server-Side Request Forgery attacks for `faraday` ([#4391][])
14
+ * AppSec: Deprecate `appsec.track_user_events` configuration setting in favor of `appsec.auto_user_instrumentation` ([#4352][])
15
+ * Dynamic Instrumentation: Add optional trace logging ([#4283][])
16
+
17
+ ### Changed
18
+
19
+ * Increase default timeout for unix domain socket to 30 seconds ([#4411][])
20
+ * Upgrade `libdatadog` to `16.0.1` ([#4353][])
21
+ * Dynamic Instrumentation: Improve path matching with prefixes of probe paths ([#4346][])
22
+ * Dynamic Instrumentation: Improve event reporting with combing status and snapshot events ([#4360][])
23
+
24
+ ### Fixed
25
+
26
+ * Tracing: Fix `rack` to continue trace if only distributed trace is present ([#4398][])
27
+ * AppSec: Fix a memory leak issue for RASP ([#4422][])
28
+ * Dynamic Instrumentation: Fix event submission on forked servers ([#4363][])
29
+
30
+ ### Removed
31
+
32
+ * Tracing: Remove peer services by default ([#3846][])
33
+
34
+ ## [2.10.0] - 2025-02-04
35
+
36
+ ### Added
37
+
38
+ * AppSec: Add configuration option(`Datadog.configuration.appsec.rasp_enabled`) to enable/disable Runtime Application Self-Protection checks ([#4311][])
39
+ * AppSec: Add stack trace when SQL Injection attack is detected ([#4321][])
40
+
41
+ ### Changed
42
+
43
+ * Add `logger` gem as dependency ([#4257][])
44
+ * Bump minimum version of `datadog-ruby_core_source` to 3.4 ([#4323][])
45
+
46
+ ### Fixed
47
+
48
+ * Dynamic instrumentation: Fix report probe status when dynamic instrumentation probes fail to instrument ([#4301][])
49
+ * Dynamic instrumentation: Include variables named `env` in probe snapshots ([#4292][])
50
+ * Fix a concurrency issue during application boot ([#4303][])
51
+
5
52
  ## [2.9.0] - 2025-01-15
6
53
 
7
54
  ### Added
@@ -3079,7 +3126,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3079
3126
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3080
3127
 
3081
3128
 
3082
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.9.0...master
3129
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.11.0...master
3130
+ [2.11.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.10.0...v2.11.0
3131
+ [2.10.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.9.0...v2.10.0
3083
3132
  [2.9.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.8.0...v2.9.0
3084
3133
  [2.8.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.7.1...v2.8.0
3085
3134
  [2.7.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.6.0...v2.7.0
@@ -4506,6 +4555,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4506
4555
  [#3837]: https://github.com/DataDog/dd-trace-rb/issues/3837
4507
4556
  [#3839]: https://github.com/DataDog/dd-trace-rb/issues/3839
4508
4557
  [#3841]: https://github.com/DataDog/dd-trace-rb/issues/3841
4558
+ [#3846]: https://github.com/DataDog/dd-trace-rb/issues/3846
4509
4559
  [#3849]: https://github.com/DataDog/dd-trace-rb/issues/3849
4510
4560
  [#3852]: https://github.com/DataDog/dd-trace-rb/issues/3852
4511
4561
  [#3857]: https://github.com/DataDog/dd-trace-rb/issues/3857
@@ -4539,6 +4589,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4539
4589
  [#4161]: https://github.com/DataDog/dd-trace-rb/issues/4161
4540
4590
  [#4164]: https://github.com/DataDog/dd-trace-rb/issues/4164
4541
4591
  [#4167]: https://github.com/DataDog/dd-trace-rb/issues/4167
4592
+ [#4177]: https://github.com/DataDog/dd-trace-rb/issues/4177
4542
4593
  [#4178]: https://github.com/DataDog/dd-trace-rb/issues/4178
4543
4594
  [#4195]: https://github.com/DataDog/dd-trace-rb/issues/4195
4544
4595
  [#4196]: https://github.com/DataDog/dd-trace-rb/issues/4196
@@ -4550,10 +4601,30 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4550
4601
  [#4239]: https://github.com/DataDog/dd-trace-rb/issues/4239
4551
4602
  [#4240]: https://github.com/DataDog/dd-trace-rb/issues/4240
4552
4603
  [#4249]: https://github.com/DataDog/dd-trace-rb/issues/4249
4604
+ [#4257]: https://github.com/DataDog/dd-trace-rb/issues/4257
4553
4605
  [#4266]: https://github.com/DataDog/dd-trace-rb/issues/4266
4554
4606
  [#4272]: https://github.com/DataDog/dd-trace-rb/issues/4272
4607
+ [#4283]: https://github.com/DataDog/dd-trace-rb/issues/4283
4555
4608
  [#4285]: https://github.com/DataDog/dd-trace-rb/issues/4285
4556
4609
  [#4288]: https://github.com/DataDog/dd-trace-rb/issues/4288
4610
+ [#4292]: https://github.com/DataDog/dd-trace-rb/issues/4292
4611
+ [#4301]: https://github.com/DataDog/dd-trace-rb/issues/4301
4612
+ [#4303]: https://github.com/DataDog/dd-trace-rb/issues/4303
4613
+ [#4311]: https://github.com/DataDog/dd-trace-rb/issues/4311
4614
+ [#4321]: https://github.com/DataDog/dd-trace-rb/issues/4321
4615
+ [#4323]: https://github.com/DataDog/dd-trace-rb/issues/4323
4616
+ [#4346]: https://github.com/DataDog/dd-trace-rb/issues/4346
4617
+ [#4352]: https://github.com/DataDog/dd-trace-rb/issues/4352
4618
+ [#4353]: https://github.com/DataDog/dd-trace-rb/issues/4353
4619
+ [#4360]: https://github.com/DataDog/dd-trace-rb/issues/4360
4620
+ [#4363]: https://github.com/DataDog/dd-trace-rb/issues/4363
4621
+ [#4391]: https://github.com/DataDog/dd-trace-rb/issues/4391
4622
+ [#4398]: https://github.com/DataDog/dd-trace-rb/issues/4398
4623
+ [#4399]: https://github.com/DataDog/dd-trace-rb/issues/4399
4624
+ [#4406]: https://github.com/DataDog/dd-trace-rb/issues/4406
4625
+ [#4411]: https://github.com/DataDog/dd-trace-rb/issues/4411
4626
+ [#4422]: https://github.com/DataDog/dd-trace-rb/issues/4422
4627
+ [#4425]: https://github.com/DataDog/dd-trace-rb/issues/4425
4557
4628
  [@AdrianLC]: https://github.com/AdrianLC
4558
4629
  [@Azure7111]: https://github.com/Azure7111
4559
4630
  [@BabyGroot]: https://github.com/BabyGroot
@@ -17,7 +17,7 @@
17
17
  #include "setup_signal_handler.h"
18
18
  #include "time_helpers.h"
19
19
 
20
- // Used to trigger the execution of Collectors::ThreadState, which implements all of the sampling logic
20
+ // Used to trigger the execution of Collectors::ThreadContext, which implements all of the sampling logic
21
21
  // itself; this class only implements the "when to do it" part.
22
22
  //
23
23
  // This file implements the native bits of the Datadog::Profiling::Collectors::CpuAndWallTimeWorker class
@@ -33,7 +33,7 @@
33
33
  // Currently, sampling Ruby threads requires calling Ruby VM APIs that are only safe to call while holding on to the
34
34
  // global VM lock (and are not async-signal safe -- cannot be called from a signal handler).
35
35
  //
36
- // @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since can reach into the Ruby
36
+ // @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since we can reach inside the Ruby
37
37
  // internals, we may be able to figure out a way of overcoming it. But it's definitely going to be hard so for now
38
38
  // we're considering it as a given.
39
39
  //
@@ -300,7 +300,7 @@ void sample_thread(
300
300
  }
301
301
 
302
302
  buffer->locations[i] = (ddog_prof_Location) {
303
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
303
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
304
304
  .function = (ddog_prof_Function) {.name = name_slice, .filename = filename_slice},
305
305
  .line = line,
306
306
  };
@@ -379,7 +379,7 @@ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer*
379
379
  ddog_CharSlice function_name = DDOG_CHARSLICE_C("");
380
380
  ddog_CharSlice function_filename = {.ptr = frames_omitted_message, .len = strlen(frames_omitted_message)};
381
381
  buffer->locations[buffer->max_frames - 1] = (ddog_prof_Location) {
382
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
382
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
383
383
  .function = (ddog_prof_Function) {.name = function_name, .filename = function_filename},
384
384
  .line = 0,
385
385
  };
@@ -426,7 +426,7 @@ void record_placeholder_stack(
426
426
  ddog_CharSlice placeholder_stack
427
427
  ) {
428
428
  ddog_prof_Location placeholder_location = {
429
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
429
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
430
430
  .function = {.name = DDOG_CHARSLICE_C(""), .filename = placeholder_stack},
431
431
  .line = 0,
432
432
  };
@@ -4,8 +4,8 @@
4
4
 
5
5
  #include "stack_recorder.h"
6
6
 
7
- #define MAX_FRAMES_LIMIT 10000
8
- #define MAX_FRAMES_LIMIT_AS_STRING "10000"
7
+ #define MAX_FRAMES_LIMIT 3000
8
+ #define MAX_FRAMES_LIMIT_AS_STRING "3000"
9
9
 
10
10
  typedef struct sampling_buffer sampling_buffer;
11
11
 
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
 
3
+ #include "datadog_ruby_common.h"
3
4
  #include "collectors_thread_context.h"
4
5
  #include "clock_id.h"
5
6
  #include "collectors_stack.h"
@@ -102,6 +103,7 @@ static ID at_kind_id; // id of :@kind in Ruby
102
103
  static ID at_name_id; // id of :@name in Ruby
103
104
  static ID server_id; // id of :server in Ruby
104
105
  static ID otel_context_storage_id; // id of :__opentelemetry_context_storage__ in Ruby
106
+ static ID otel_fiber_context_storage_id; // id of :@opentelemetry_context in Ruby
105
107
 
106
108
  // This is used by `thread_context_collector_on_gvl_running`. Because when that method gets called we're not sure if
107
109
  // it's safe to access the state of the thread context collector, we store this setting as a global value. This does
@@ -111,6 +113,7 @@ static ID otel_context_storage_id; // id of :__opentelemetry_context_storage__ i
111
113
  static uint32_t global_waiting_for_gvl_threshold_ns = MILLIS_AS_NS(10);
112
114
 
113
115
  typedef enum { OTEL_CONTEXT_ENABLED_FALSE, OTEL_CONTEXT_ENABLED_ONLY, OTEL_CONTEXT_ENABLED_BOTH } otel_context_enabled;
116
+ typedef enum { OTEL_CONTEXT_SOURCE_UNKNOWN, OTEL_CONTEXT_SOURCE_FIBER_IVAR, OTEL_CONTEXT_SOURCE_FIBER_LOCAL } otel_context_source;
114
117
 
115
118
  // Contains state for a single ThreadContext instance
116
119
  typedef struct {
@@ -140,6 +143,8 @@ typedef struct {
140
143
  bool timeline_enabled;
141
144
  // Used to control context collection
142
145
  otel_context_enabled otel_context_enabled;
146
+ // Used to remember where otel context is being stored after we observe it the first time
147
+ otel_context_source otel_context_source;
143
148
  // Used when calling monotonic_to_system_epoch_ns
144
149
  monotonic_to_system_epoch_state time_converter_state;
145
150
  // Used to identify the main thread, to give it a fallback name
@@ -348,6 +353,7 @@ void collectors_thread_context_init(VALUE profiling_module) {
348
353
  at_name_id = rb_intern_const("@name");
349
354
  server_id = rb_intern_const("server");
350
355
  otel_context_storage_id = rb_intern_const("__opentelemetry_context_storage__");
356
+ otel_fiber_context_storage_id = rb_intern_const("@opentelemetry_context");
351
357
 
352
358
  #ifndef NO_GVL_INSTRUMENTATION
353
359
  // This will raise if Ruby already ran out of thread-local keys
@@ -433,6 +439,7 @@ static VALUE _native_new(VALUE klass) {
433
439
  state->endpoint_collection_enabled = true;
434
440
  state->timeline_enabled = true;
435
441
  state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
442
+ state->otel_context_source = OTEL_CONTEXT_SOURCE_UNKNOWN;
436
443
  state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
437
444
  VALUE main_thread = rb_thread_main();
438
445
  state->main_thread = main_thread;
@@ -1450,11 +1457,8 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
1450
1457
 
1451
1458
  // Since this is stack allocated, be careful about moving it
1452
1459
  ddog_CharSlice class_name;
1453
- ddog_CharSlice *optional_class_name = NULL;
1454
1460
  char imemo_type[100];
1455
1461
 
1456
- optional_class_name = &class_name;
1457
-
1458
1462
  if (
1459
1463
  type == RUBY_T_OBJECT ||
1460
1464
  type == RUBY_T_CLASS ||
@@ -1510,7 +1514,7 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
1510
1514
  class_name = ruby_vm_type; // For other weird internal things we just use the VM type
1511
1515
  }
1512
1516
 
1513
- track_object(state->recorder_instance, new_object, sample_weight, optional_class_name);
1517
+ track_object(state->recorder_instance, new_object, sample_weight, class_name);
1514
1518
 
1515
1519
  per_thread_context *thread_context = get_or_create_context_for(current_thread, state);
1516
1520
 
@@ -1523,7 +1527,7 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
1523
1527
  (sample_values) {.alloc_samples = sample_weight, .alloc_samples_unscaled = 1, .heap_sample = true},
1524
1528
  INVALID_TIME, // For now we're not collecting timestamps for allocation events, as per profiling team internal discussions
1525
1529
  &ruby_vm_type,
1526
- optional_class_name,
1530
+ &class_name,
1527
1531
  /* is_gvl_waiting_state: */ false,
1528
1532
  /* is_safe_to_allocate_objects: */ false // Not safe to allocate further inside the NEWOBJ tracepoint
1529
1533
  );
@@ -1685,6 +1689,42 @@ static VALUE _native_sample_skipped_allocation_samples(DDTRACE_UNUSED VALUE self
1685
1689
  return Qtrue;
1686
1690
  }
1687
1691
 
1692
+ #ifndef NO_CURRENT_FIBER_FOR // Ruby 3.1+
1693
+ static VALUE otel_context_storage_for(thread_context_collector_state *state, VALUE thread) {
1694
+ if (state->otel_context_source == OTEL_CONTEXT_SOURCE_FIBER_IVAR) { // otel-api 1.5+
1695
+ VALUE current_fiber = current_fiber_for(thread);
1696
+ return current_fiber == Qnil ? Qnil : rb_ivar_get(current_fiber, otel_fiber_context_storage_id /* @opentelemetry_context */);
1697
+ }
1698
+
1699
+ if (state->otel_context_source == OTEL_CONTEXT_SOURCE_FIBER_LOCAL) { // otel-api < 1.5
1700
+ return rb_thread_local_aref(thread, otel_context_storage_id /* __opentelemetry_context_storage__ */);
1701
+ }
1702
+
1703
+ // If we got here, it means we never observed a context being set. Let's probe which one to use.
1704
+ VALUE current_fiber = current_fiber_for(thread);
1705
+ if (current_fiber != Qnil) {
1706
+ VALUE context_storage = rb_ivar_get(current_fiber, otel_fiber_context_storage_id /* @opentelemetry_context */);
1707
+ if (context_storage != Qnil) {
1708
+ state->otel_context_source = OTEL_CONTEXT_SOURCE_FIBER_IVAR; // Remember for next time
1709
+ return context_storage;
1710
+ }
1711
+ } else {
1712
+ VALUE context_storage = rb_thread_local_aref(thread, otel_context_storage_id /* __opentelemetry_context_storage__ */);
1713
+ if (context_storage != Qnil) {
1714
+ state->otel_context_source = OTEL_CONTEXT_SOURCE_FIBER_LOCAL; // Remember for next time
1715
+ return context_storage;
1716
+ }
1717
+ }
1718
+
1719
+ // There's no context storage attached to the current thread
1720
+ return Qnil;
1721
+ }
1722
+ #else
1723
+ static inline VALUE otel_context_storage_for(DDTRACE_UNUSED thread_context_collector_state *state, VALUE thread) {
1724
+ return rb_thread_local_aref(thread, otel_context_storage_id /* __opentelemetry_context_storage__ */);
1725
+ }
1726
+ #endif
1727
+
1688
1728
  // This method differs from trace_identifiers_for/ddtrace_otel_trace_identifiers_for to support the situation where
1689
1729
  // the opentelemetry ruby library is being used for tracing AND the ddtrace tracing bits are not involved at all.
1690
1730
  //
@@ -1712,7 +1752,7 @@ static void otel_without_ddtrace_trace_identifiers_for(
1712
1752
  trace_identifiers *trace_identifiers_result,
1713
1753
  bool is_safe_to_allocate_objects
1714
1754
  ) {
1715
- VALUE context_storage = rb_thread_local_aref(thread, otel_context_storage_id /* __opentelemetry_context_storage__ */);
1755
+ VALUE context_storage = otel_context_storage_for(state, thread);
1716
1756
 
1717
1757
  // If it exists, context_storage is expected to be an Array[OpenTelemetry::Context]
1718
1758
  if (context_storage == Qnil || !RB_TYPE_P(context_storage, T_ARRAY)) return;
@@ -164,6 +164,10 @@ $defs << "-DNO_INT_FIRST_LINENO" if RUBY_VERSION < "3.2"
164
164
  # On older Rubies, "pop" was not a primitive operation
165
165
  $defs << "-DNO_PRIMITIVE_POP" if RUBY_VERSION < "3.2"
166
166
 
167
+ # We could support this for older Rubies, but since this only gets used by the OTEL context extraction, and that
168
+ # use-case is only for 3.1+, we didn't bother supporting it farther back yet.
169
+ $defs << "-DNO_CURRENT_FIBER_FOR" if RUBY_VERSION < "3.1"
170
+
167
171
  # On older Rubies, there was no tid member in the internal thread structure
168
172
  $defs << "-DNO_THREAD_TID" if RUBY_VERSION < "3.1"
169
173
 
@@ -1,5 +1,7 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/thread.h>
3
+
4
+ #include "datadog_ruby_common.h"
3
5
  #include "gvl_profiling_helper.h"
4
6
 
5
7
  #if !defined(NO_GVL_INSTRUMENTATION) && !defined(USE_GVL_PROFILING_3_2_WORKAROUNDS) // Ruby 3.3+
@@ -39,14 +39,6 @@
39
39
 
40
40
  static inline void gvl_profiling_init(void) { }
41
41
 
42
- // This header gets included in private_vm_access.c which can't include datadog_ruby_common.h so we replicate this
43
- // helper here
44
- #ifdef __GNUC__
45
- #define DDTRACE_UNUSED __attribute__((unused))
46
- #else
47
- #define DDTRACE_UNUSED
48
- #endif
49
-
50
42
  // NOTE: This is a hack that relies on the knowledge that on Ruby 3.2 the
51
43
  // RUBY_INTERNAL_THREAD_EVENT_READY and RUBY_INTERNAL_THREAD_EVENT_RESUMED events always get called on the thread they
52
44
  // are about. Thus, we can use our thread local storage hack to get this data, even though the event doesn't include it.
@@ -1,8 +1,6 @@
1
1
  #include "heap_recorder.h"
2
- #include <pthread.h>
3
2
  #include "ruby/st.h"
4
3
  #include "ruby_helpers.h"
5
- #include <errno.h>
6
4
  #include "collectors_stack.h"
7
5
  #include "libdatadog_helpers.h"
8
6
  #include "time_helpers.h"
@@ -30,7 +28,6 @@ typedef struct {
30
28
  char *filename;
31
29
  int32_t line;
32
30
  } heap_frame;
33
- static st_index_t heap_frame_hash(heap_frame*, st_index_t seed);
34
31
 
35
32
  // A compact representation of a stacktrace for a heap allocation.
36
33
  //
@@ -113,14 +110,6 @@ static void object_record_free(object_record*);
113
110
  static VALUE object_record_inspect(object_record*);
114
111
  static object_record SKIPPED_RECORD = {0};
115
112
 
116
- // A wrapper around an object record that is in the process of being recorded and was not
117
- // yet committed.
118
- typedef struct {
119
- // Pointer to the (potentially partial) object_record containing metadata about an ongoing recording.
120
- // When NULL, this symbolizes an unstarted/invalid recording.
121
- object_record *object_record;
122
- } recording;
123
-
124
113
  struct heap_recorder {
125
114
  // Config
126
115
  // Whether the recorder should try to determine approximate sizes for tracked objects.
@@ -140,6 +129,9 @@ struct heap_recorder {
140
129
  // outside the GVL.
141
130
  // NOTE: This table has ownership of its object_records. The keys are longs and so are
142
131
  // passed as values.
132
+ //
133
+ // TODO: @ivoanjo We've evolved to actually never need to look up on object_records (we only insert and iterate),
134
+ // so right now this seems to be just a really really fancy self-resizing list/set.
143
135
  st_table *object_records;
144
136
 
145
137
  // Map[obj_id: long, record: object_record*]
@@ -162,7 +154,7 @@ struct heap_recorder {
162
154
  long last_update_ns;
163
155
 
164
156
  // Data for a heap recording that was started but not yet ended
165
- recording active_recording;
157
+ object_record *active_recording;
166
158
 
167
159
  // Reusable location array, implementing a flyweight pattern for things like iteration.
168
160
  ddog_prof_Location *reusable_locations;
@@ -207,7 +199,7 @@ static int st_object_record_update(st_data_t, st_data_t, st_data_t);
207
199
  static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
208
200
  static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
209
201
  static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
210
- static void commit_recording(heap_recorder*, heap_record*, recording);
202
+ static void commit_recording(heap_recorder *, heap_record *, object_record *active_recording);
211
203
  static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
212
204
  static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update);
213
205
  static inline double ewma_stat(double previous, double current);
@@ -228,7 +220,7 @@ heap_recorder* heap_recorder_new(void) {
228
220
  recorder->object_records = st_init_numtable();
229
221
  recorder->object_records_snapshot = NULL;
230
222
  recorder->reusable_locations = ruby_xcalloc(MAX_FRAMES_LIMIT, sizeof(ddog_prof_Location));
231
- recorder->active_recording = (recording) {0};
223
+ recorder->active_recording = NULL;
232
224
  recorder->size_enabled = true;
233
225
  recorder->sample_rate = 1; // By default do no sampling on top of what allocation profiling already does
234
226
 
@@ -254,9 +246,9 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
254
246
  st_foreach(heap_recorder->heap_records, st_heap_record_entry_free, 0);
255
247
  st_free_table(heap_recorder->heap_records);
256
248
 
257
- if (heap_recorder->active_recording.object_record != NULL && heap_recorder->active_recording.object_record != &SKIPPED_RECORD) {
249
+ if (heap_recorder->active_recording != NULL && heap_recorder->active_recording != &SKIPPED_RECORD) {
258
250
  // If there's a partial object record, clean it up as well
259
- object_record_free(heap_recorder->active_recording.object_record);
251
+ object_record_free(heap_recorder->active_recording);
260
252
  }
261
253
 
262
254
  ruby_xfree(heap_recorder->reusable_locations);
@@ -301,7 +293,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
301
293
  //
302
294
  // There is one small caveat though: fork only preserves one thread and in a Ruby app, that
303
295
  // will be the thread holding on to the GVL. Since we support iteration on the heap recorder
304
- // outside of the GVL, any state specific to that interaction may be incosistent after fork
296
+ // outside of the GVL, any state specific to that interaction may be inconsistent after fork
305
297
  // (e.g. an acquired lock for thread safety). Iteration operates on object_records_snapshot
306
298
  // though and that one will be updated on next heap_recorder_prepare_iteration so we really
307
299
  // only need to finish any iteration that might have been left unfinished.
@@ -313,18 +305,17 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
313
305
  heap_recorder->stats_lifetime = (struct stats_lifetime) {0};
314
306
  }
315
307
 
316
- void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice *alloc_class) {
308
+ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class) {
317
309
  if (heap_recorder == NULL) {
318
310
  return;
319
311
  }
320
312
 
321
- if (heap_recorder->active_recording.object_record != NULL) {
313
+ if (heap_recorder->active_recording != NULL) {
322
314
  rb_raise(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
323
315
  }
324
316
 
325
- if (heap_recorder->num_recordings_skipped + 1 < heap_recorder->sample_rate) {
326
- heap_recorder->active_recording.object_record = &SKIPPED_RECORD;
327
- heap_recorder->num_recordings_skipped++;
317
+ if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate) {
318
+ heap_recorder->active_recording = &SKIPPED_RECORD;
328
319
  return;
329
320
  }
330
321
 
@@ -335,13 +326,15 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
335
326
  rb_raise(rb_eRuntimeError, "Detected a bignum object id. These are not supported by heap profiling.");
336
327
  }
337
328
 
338
- heap_recorder->active_recording = (recording) {
339
- .object_record = object_record_new(FIX2LONG(ruby_obj_id), NULL, (live_object_data) {
340
- .weight = weight * heap_recorder->sample_rate,
341
- .class = alloc_class != NULL ? string_from_char_slice(*alloc_class) : NULL,
342
- .alloc_gen = rb_gc_count(),
343
- }),
344
- };
329
+ heap_recorder->active_recording = object_record_new(
330
+ FIX2LONG(ruby_obj_id),
331
+ NULL,
332
+ (live_object_data) {
333
+ .weight = weight * heap_recorder->sample_rate,
334
+ .class = string_from_char_slice(alloc_class),
335
+ .alloc_gen = rb_gc_count(),
336
+ }
337
+ );
345
338
  }
346
339
 
347
340
  // end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
@@ -349,6 +342,10 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
349
342
  // with an rb_protect.
350
343
  __attribute__((warn_unused_result))
351
344
  int end_heap_allocation_recording_with_rb_protect(struct heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
345
+ if (heap_recorder == NULL) {
346
+ return 0;
347
+ }
348
+
352
349
  int exception_state;
353
350
  struct end_heap_allocation_args end_heap_allocation_args = {
354
351
  .heap_recorder = heap_recorder,
@@ -364,22 +361,18 @@ static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args) {
364
361
  struct heap_recorder *heap_recorder = args->heap_recorder;
365
362
  ddog_prof_Slice_Location locations = args->locations;
366
363
 
367
- if (heap_recorder == NULL) {
368
- return Qnil;
369
- }
364
+ object_record *active_recording = heap_recorder->active_recording;
370
365
 
371
- recording active_recording = heap_recorder->active_recording;
372
-
373
- if (active_recording.object_record == NULL) {
366
+ if (active_recording == NULL) {
374
367
  // Recording ended without having been started?
375
368
  rb_raise(rb_eRuntimeError, "Ended a heap recording that was not started");
376
369
  }
377
370
  // From now on, mark the global active recording as invalid so we can short-circuit at any point
378
371
  // and not end up with a still active recording. the local active_recording still holds the
379
372
  // data required for committing though.
380
- heap_recorder->active_recording = (recording) {0};
373
+ heap_recorder->active_recording = NULL;
381
374
 
382
- if (active_recording.object_record == &SKIPPED_RECORD) { // special marker when we decided to skip due to sampling
375
+ if (active_recording == &SKIPPED_RECORD) { // special marker when we decided to skip due to sampling
383
376
  return Qnil;
384
377
  }
385
378
 
@@ -685,7 +678,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
685
678
  for (uint16_t i = 0; i < stack->frames_len; i++) {
686
679
  const heap_frame *frame = &stack->frames[i];
687
680
  locations[i] = (ddog_prof_Location) {
688
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
681
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
689
682
  .function = {
690
683
  .name = {.ptr = frame->name, .len = strlen(frame->name)},
691
684
  .filename = {.ptr = frame->filename, .len = strlen(frame->filename)},
@@ -698,6 +691,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
698
691
  iteration_data.object_data = record->object_data;
699
692
  iteration_data.locations = (ddog_prof_Slice_Location) {.ptr = locations, .len = stack->frames_len};
700
693
 
694
+ // This is expected to be StackRecorder's add_heap_sample_to_active_profile_without_gvl
701
695
  if (!context->for_each_callback(iteration_data, context->for_each_callback_extra_arg)) {
702
696
  return ST_STOP;
703
697
  }
@@ -715,49 +709,35 @@ static int st_object_records_debug(DDTRACE_UNUSED st_data_t key, st_data_t value
715
709
  return ST_CONTINUE;
716
710
  }
717
711
 
718
- // Struct holding data required for an update operation on heap_records
719
- typedef struct {
720
- // [in] The recording containing the new object record we want to add.
721
- // NOTE: Transfer of ownership of the contained object record is assumed, do not re-use it after call to ::update_object_record_entry
722
- recording recording;
723
-
724
- // [in] The heap recorder where the update is happening.
725
- heap_recorder *heap_recorder;
726
- } object_record_update_data;
727
-
728
- static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t data, int existing) {
729
- object_record_update_data *update_data = (object_record_update_data*) data;
730
- recording recording = update_data->recording;
731
- object_record *new_object_record = recording.object_record;
732
- if (existing) {
733
- object_record *existing_record = (object_record*) (*value);
734
-
735
- // This is not supposed to happen, raising...
736
- VALUE existing_inspect = object_record_inspect(existing_record);
737
- VALUE new_inspect = object_record_inspect(new_object_record);
738
- rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
739
- "the same id. previous=%"PRIsVALUE" new=%"PRIsVALUE, existing_inspect, new_inspect);
712
+ static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t new_object_record, int existing) {
713
+ if (!existing) {
714
+ (*value) = (st_data_t) new_object_record; // Expected to be a `object_record *`
715
+ } else {
716
+ // If key already existed, we don't touch the existing value, so it can be used for diagnostics
740
717
  }
741
- // Always carry on with the update, we want the new record to be there at the end
742
- (*value) = (st_data_t) new_object_record;
743
718
  return ST_CONTINUE;
744
719
  }
745
720
 
746
- static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, recording recording) {
721
+ static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, object_record *active_recording) {
747
722
  // Link the object record with the corresponding heap record. This was the last remaining thing we
748
723
  // needed to fully build the object_record.
749
- recording.object_record->heap_record = heap_record;
724
+ active_recording->heap_record = heap_record;
750
725
  if (heap_record->num_tracked_objects == UINT32_MAX) {
751
726
  rb_raise(rb_eRuntimeError, "Reached maximum number of tracked objects for heap record");
752
727
  }
753
728
  heap_record->num_tracked_objects++;
754
729
 
755
- // Update object_records with the data for this new recording
756
- object_record_update_data update_data = (object_record_update_data) {
757
- .heap_recorder = heap_recorder,
758
- .recording = recording,
759
- };
760
- st_update(heap_recorder->object_records, recording.object_record->obj_id, update_object_record_entry, (st_data_t) &update_data);
730
+ int existing_error = st_update(heap_recorder->object_records, active_recording->obj_id, update_object_record_entry, (st_data_t) active_recording);
731
+ if (existing_error) {
732
+ object_record *existing_record = NULL;
733
+ st_lookup(heap_recorder->object_records, active_recording->obj_id, (st_data_t *) &existing_record);
734
+ if (existing_record == NULL) rb_raise(rb_eRuntimeError, "Unexpected NULL when reading existing record");
735
+
736
+ VALUE existing_inspect = object_record_inspect(existing_record);
737
+ VALUE new_inspect = object_record_inspect(active_recording);
738
+ rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
739
+ "the same id. previous={%"PRIsVALUE"} new={%"PRIsVALUE"}", existing_inspect, new_inspect);
740
+ }
761
741
  }
762
742
 
763
743
  // Struct holding data required for an update operation on heap_records
@@ -867,7 +847,6 @@ void heap_record_free(heap_record *record) {
867
847
  ruby_xfree(record);
868
848
  }
869
849
 
870
-
871
850
  // =================
872
851
  // Object Record API
873
852
  // =================
@@ -917,25 +896,6 @@ VALUE object_record_inspect(object_record *record) {
917
896
  // ==============
918
897
  // Heap Frame API
919
898
  // ==============
920
- int heap_frame_cmp(heap_frame *f1, heap_frame *f2) {
921
- int line_diff = (int) (f1->line - f2->line);
922
- if (line_diff != 0) {
923
- return line_diff;
924
- }
925
- int cmp = strcmp(f1->name, f2->name);
926
- if (cmp != 0) {
927
- return cmp;
928
- }
929
- return strcmp(f1->filename, f2->filename);
930
- }
931
-
932
- // TODO: Research potential performance improvements around hashing stuff here
933
- // once we have a benchmarking suite.
934
- // Example: Each call to st_hash is calling murmur_finish and we may want
935
- // to only finish once per structure, not per field?
936
- // Example: There may be a more efficient hashing for line that is not the
937
- // generic st_hash algorithm?
938
-
939
899
  // WARN: Must be kept in-sync with ::char_slice_hash
940
900
  st_index_t string_hash(char *str, st_index_t seed) {
941
901
  return st_hash(str, strlen(str), seed);
@@ -971,9 +931,7 @@ st_index_t ddog_location_hash(ddog_prof_Location location, st_index_t seed) {
971
931
  heap_stack* heap_stack_new(ddog_prof_Slice_Location locations) {
972
932
  uint16_t frames_len = locations.len;
973
933
  if (frames_len > MAX_FRAMES_LIMIT) {
974
- // This should not be happening anyway since MAX_FRAMES_LIMIT should be shared with
975
- // the stacktrace construction mechanism. If it happens, lets just raise. This should
976
- // be safe since only allocate with the GVL anyway.
934
+ // This is not expected as MAX_FRAMES_LIMIT is shared with the stacktrace construction mechanism
977
935
  rb_raise(rb_eRuntimeError, "Found stack with more than %d frames (%d)", MAX_FRAMES_LIMIT, frames_len);
978
936
  }
979
937
  heap_stack *stack = ruby_xcalloc(1, sizeof(heap_stack) + frames_len * sizeof(heap_frame));
@@ -105,7 +105,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder);
105
105
  // The sampling weight of this object.
106
106
  //
107
107
  // WARN: It needs to be paired with a ::end_heap_allocation_recording call.
108
- void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice *alloc_class);
108
+ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class);
109
109
 
110
110
  // End a previously started heap allocation recording on the heap recorder.
111
111
  //