ddtrace 1.14.0 → 1.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 (283) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +146 -2
  3. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +3 -5
  4. data/ext/ddtrace_profiling_native_extension/clock_id.h +0 -3
  5. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +0 -22
  6. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +0 -1
  7. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +41 -6
  8. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +3 -0
  9. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +76 -24
  10. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +1 -1
  11. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +207 -32
  12. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +1 -1
  13. data/ext/ddtrace_profiling_native_extension/extconf.rb +8 -2
  14. data/ext/ddtrace_profiling_native_extension/http_transport.c +26 -10
  15. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.c +42 -0
  16. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +6 -0
  17. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +1 -16
  18. data/ext/ddtrace_profiling_native_extension/pid_controller.c +57 -0
  19. data/ext/ddtrace_profiling_native_extension/pid_controller.h +45 -0
  20. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +17 -12
  21. data/ext/ddtrace_profiling_native_extension/profiling.c +0 -2
  22. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +74 -37
  23. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +13 -3
  24. data/lib/datadog/appsec/assets/waf_rules/processors.json +92 -0
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +698 -75
  26. data/lib/datadog/appsec/assets/waf_rules/scanners.json +114 -0
  27. data/lib/datadog/appsec/assets/waf_rules/strict.json +98 -8
  28. data/lib/datadog/appsec/assets.rb +8 -0
  29. data/lib/datadog/appsec/component.rb +9 -2
  30. data/lib/datadog/appsec/configuration/settings.rb +67 -2
  31. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -2
  32. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +46 -0
  33. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +8 -6
  34. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +2 -7
  35. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +2 -5
  36. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +7 -5
  37. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +3 -2
  38. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +34 -10
  39. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -2
  40. data/lib/datadog/appsec/contrib/rails/patcher.rb +9 -3
  41. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +2 -5
  42. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -4
  43. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +13 -7
  44. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +2 -5
  45. data/lib/datadog/appsec/event.rb +106 -50
  46. data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -3
  47. data/lib/datadog/appsec/monitor/reactive/set_user.rb +2 -5
  48. data/lib/datadog/appsec/processor/actions.rb +49 -0
  49. data/lib/datadog/appsec/processor/rule_merger.rb +22 -2
  50. data/lib/datadog/appsec/processor.rb +34 -6
  51. data/lib/datadog/appsec/remote.rb +4 -1
  52. data/lib/datadog/appsec/response.rb +82 -4
  53. data/lib/datadog/appsec/sample_rate.rb +21 -0
  54. data/lib/datadog/appsec.rb +2 -2
  55. data/lib/datadog/core/configuration/agent_settings_resolver.rb +29 -24
  56. data/lib/datadog/core/configuration/base.rb +1 -11
  57. data/lib/datadog/core/configuration/components.rb +7 -2
  58. data/lib/datadog/core/configuration/ext.rb +21 -0
  59. data/lib/datadog/core/configuration/option.rb +2 -4
  60. data/lib/datadog/core/configuration/option_definition.rb +17 -41
  61. data/lib/datadog/core/configuration/options.rb +5 -5
  62. data/lib/datadog/core/configuration/settings.rb +47 -45
  63. data/lib/datadog/core/environment/execution.rb +47 -9
  64. data/lib/datadog/core/environment/variable_helpers.rb +0 -69
  65. data/lib/datadog/core/error.rb +1 -0
  66. data/lib/datadog/core/git/ext.rb +2 -0
  67. data/lib/datadog/core/remote/client/capabilities.rb +1 -1
  68. data/lib/datadog/core/remote/component.rb +2 -2
  69. data/lib/datadog/core/remote/negotiation.rb +2 -2
  70. data/lib/datadog/core/remote/transport/config.rb +60 -0
  71. data/lib/datadog/core/remote/transport/http/api/instance.rb +39 -0
  72. data/lib/datadog/core/remote/transport/http/api/spec.rb +21 -0
  73. data/lib/datadog/core/remote/transport/http/api.rb +58 -0
  74. data/lib/datadog/core/remote/transport/http/builder.rb +219 -0
  75. data/lib/datadog/core/remote/transport/http/client.rb +48 -0
  76. data/lib/datadog/core/remote/transport/http/config.rb +280 -0
  77. data/lib/datadog/core/remote/transport/http/negotiation.rb +146 -0
  78. data/lib/datadog/core/remote/transport/http.rb +179 -0
  79. data/lib/datadog/core/{transport → remote/transport}/negotiation.rb +25 -23
  80. data/lib/datadog/core/remote/worker.rb +3 -1
  81. data/lib/datadog/core/telemetry/collector.rb +3 -2
  82. data/lib/datadog/core/telemetry/http/transport.rb +2 -1
  83. data/lib/datadog/core/transport/ext.rb +47 -0
  84. data/lib/datadog/core/transport/http/adapters/net.rb +168 -0
  85. data/lib/datadog/core/transport/http/adapters/registry.rb +29 -0
  86. data/lib/datadog/core/transport/http/adapters/test.rb +89 -0
  87. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +83 -0
  88. data/lib/datadog/core/transport/http/api/endpoint.rb +31 -0
  89. data/lib/datadog/core/transport/http/api/fallbacks.rb +26 -0
  90. data/lib/datadog/core/transport/http/api/map.rb +18 -0
  91. data/lib/datadog/core/transport/http/env.rb +62 -0
  92. data/lib/datadog/core/transport/http/response.rb +60 -0
  93. data/lib/datadog/core/transport/parcel.rb +22 -0
  94. data/lib/datadog/core/transport/request.rb +17 -0
  95. data/lib/datadog/core/transport/response.rb +64 -0
  96. data/lib/datadog/core/workers/polling.rb +2 -2
  97. data/lib/datadog/opentelemetry/api/context.rb +10 -3
  98. data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -1
  99. data/lib/datadog/opentelemetry/sdk/span_processor.rb +14 -2
  100. data/lib/datadog/opentelemetry/sdk/trace/span.rb +68 -0
  101. data/lib/datadog/opentelemetry/trace.rb +58 -0
  102. data/lib/datadog/opentelemetry.rb +1 -0
  103. data/lib/datadog/opentracer.rb +9 -0
  104. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +14 -19
  105. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
  106. data/lib/datadog/profiling/collectors/thread_context.rb +9 -1
  107. data/lib/datadog/profiling/component.rb +24 -99
  108. data/lib/datadog/profiling/ext.rb +0 -12
  109. data/lib/datadog/profiling/flush.rb +0 -3
  110. data/lib/datadog/profiling/http_transport.rb +6 -3
  111. data/lib/datadog/profiling/native_extension.rb +0 -21
  112. data/lib/datadog/profiling/profiler.rb +36 -13
  113. data/lib/datadog/profiling/scheduler.rb +16 -9
  114. data/lib/datadog/profiling.rb +8 -81
  115. data/lib/datadog/tracing/component.rb +10 -4
  116. data/lib/datadog/tracing/configuration/agent_settings_resolver.rb +13 -0
  117. data/lib/datadog/tracing/configuration/ext.rb +4 -2
  118. data/lib/datadog/tracing/configuration/settings.rb +14 -7
  119. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +1 -1
  120. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +1 -1
  121. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +4 -0
  122. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +106 -197
  123. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +3 -0
  124. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -0
  125. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +14 -14
  126. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +3 -10
  127. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +2 -1
  128. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +8 -1
  129. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +22 -0
  130. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  131. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +6 -0
  132. data/lib/datadog/tracing/contrib/dalli/ext.rb +7 -0
  133. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +9 -2
  134. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +1 -1
  135. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +5 -0
  136. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +5 -0
  137. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +8 -0
  138. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -0
  139. data/lib/datadog/tracing/contrib/ext.rb +3 -0
  140. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +1 -1
  141. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -0
  142. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +21 -1
  143. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -1
  144. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +18 -0
  145. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +0 -4
  146. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +3 -3
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -0
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -0
  149. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
  150. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +7 -0
  151. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +13 -3
  152. data/lib/datadog/tracing/contrib/opensearch/integration.rb +2 -2
  153. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +7 -0
  154. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +5 -0
  155. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +5 -0
  156. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +1 -1
  157. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +1 -1
  158. data/lib/datadog/tracing/contrib/racecar/event.rb +5 -0
  159. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +14 -4
  160. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +4 -4
  161. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +1 -1
  162. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -1
  163. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +3 -38
  164. data/lib/datadog/tracing/contrib/redis/tags.rb +7 -2
  165. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +46 -33
  166. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +1 -1
  167. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -0
  168. data/lib/datadog/tracing/contrib/sequel/utils.rb +5 -0
  169. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +1 -1
  170. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +1 -1
  171. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
  172. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +2 -2
  173. data/lib/datadog/tracing/diagnostics/environment_logger.rb +6 -0
  174. data/lib/datadog/tracing/distributed/propagation.rb +13 -33
  175. data/lib/datadog/tracing/metadata/tagging.rb +3 -3
  176. data/lib/datadog/tracing/sync_writer.rb +3 -3
  177. data/lib/datadog/tracing/tracer.rb +2 -0
  178. data/lib/datadog/{core → tracing}/transport/http/api/instance.rb +1 -1
  179. data/lib/datadog/{core → tracing}/transport/http/api/spec.rb +1 -1
  180. data/lib/datadog/tracing/transport/http/api.rb +43 -0
  181. data/lib/datadog/{core → tracing}/transport/http/builder.rb +13 -68
  182. data/lib/datadog/tracing/transport/http/client.rb +57 -0
  183. data/lib/datadog/tracing/transport/http/statistics.rb +47 -0
  184. data/lib/datadog/tracing/transport/http/traces.rb +152 -0
  185. data/lib/datadog/tracing/transport/http.rb +124 -0
  186. data/lib/datadog/tracing/transport/io/client.rb +89 -0
  187. data/lib/datadog/tracing/transport/io/response.rb +27 -0
  188. data/lib/datadog/tracing/transport/io/traces.rb +101 -0
  189. data/lib/datadog/tracing/transport/io.rb +30 -0
  190. data/lib/datadog/tracing/transport/serializable_trace.rb +126 -0
  191. data/lib/datadog/tracing/transport/statistics.rb +77 -0
  192. data/lib/datadog/tracing/transport/trace_formatter.rb +209 -0
  193. data/lib/datadog/tracing/transport/traces.rb +224 -0
  194. data/lib/datadog/tracing/workers/trace_writer.rb +5 -3
  195. data/lib/datadog/tracing/workers.rb +3 -2
  196. data/lib/datadog/tracing/writer.rb +5 -2
  197. data/lib/ddtrace/transport/ext.rb +17 -15
  198. data/lib/ddtrace/version.rb +1 -1
  199. data/lib/ddtrace.rb +1 -1
  200. metadata +73 -96
  201. data/lib/datadog/ci/configuration/components.rb +0 -32
  202. data/lib/datadog/ci/configuration/settings.rb +0 -51
  203. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +0 -35
  204. data/lib/datadog/ci/contrib/cucumber/ext.rb +0 -22
  205. data/lib/datadog/ci/contrib/cucumber/formatter.rb +0 -94
  206. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +0 -28
  207. data/lib/datadog/ci/contrib/cucumber/integration.rb +0 -47
  208. data/lib/datadog/ci/contrib/cucumber/patcher.rb +0 -27
  209. data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +0 -35
  210. data/lib/datadog/ci/contrib/minitest/ext.rb +0 -21
  211. data/lib/datadog/ci/contrib/minitest/integration.rb +0 -49
  212. data/lib/datadog/ci/contrib/minitest/patcher.rb +0 -27
  213. data/lib/datadog/ci/contrib/minitest/test_helper.rb +0 -68
  214. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +0 -35
  215. data/lib/datadog/ci/contrib/rspec/example.rb +0 -68
  216. data/lib/datadog/ci/contrib/rspec/ext.rb +0 -21
  217. data/lib/datadog/ci/contrib/rspec/integration.rb +0 -48
  218. data/lib/datadog/ci/contrib/rspec/patcher.rb +0 -27
  219. data/lib/datadog/ci/ext/app_types.rb +0 -9
  220. data/lib/datadog/ci/ext/environment.rb +0 -575
  221. data/lib/datadog/ci/ext/settings.rb +0 -10
  222. data/lib/datadog/ci/ext/test.rb +0 -35
  223. data/lib/datadog/ci/extensions.rb +0 -19
  224. data/lib/datadog/ci/flush.rb +0 -38
  225. data/lib/datadog/ci/test.rb +0 -81
  226. data/lib/datadog/ci.rb +0 -21
  227. data/lib/datadog/core/configuration/dependency_resolver.rb +0 -28
  228. data/lib/datadog/core/configuration/option_definition_set.rb +0 -22
  229. data/lib/datadog/core/configuration/option_set.rb +0 -10
  230. data/lib/datadog/core/transport/config.rb +0 -58
  231. data/lib/datadog/core/transport/http/api.rb +0 -57
  232. data/lib/datadog/core/transport/http/client.rb +0 -45
  233. data/lib/datadog/core/transport/http/config.rb +0 -278
  234. data/lib/datadog/core/transport/http/negotiation.rb +0 -144
  235. data/lib/datadog/core/transport/http.rb +0 -169
  236. data/lib/datadog/core/utils/object_set.rb +0 -43
  237. data/lib/datadog/core/utils/string_table.rb +0 -47
  238. data/lib/datadog/profiling/backtrace_location.rb +0 -34
  239. data/lib/datadog/profiling/buffer.rb +0 -43
  240. data/lib/datadog/profiling/collectors/old_stack.rb +0 -301
  241. data/lib/datadog/profiling/encoding/profile.rb +0 -41
  242. data/lib/datadog/profiling/event.rb +0 -15
  243. data/lib/datadog/profiling/events/stack.rb +0 -82
  244. data/lib/datadog/profiling/old_recorder.rb +0 -107
  245. data/lib/datadog/profiling/pprof/builder.rb +0 -125
  246. data/lib/datadog/profiling/pprof/converter.rb +0 -102
  247. data/lib/datadog/profiling/pprof/message_set.rb +0 -16
  248. data/lib/datadog/profiling/pprof/payload.rb +0 -20
  249. data/lib/datadog/profiling/pprof/pprof.proto +0 -212
  250. data/lib/datadog/profiling/pprof/pprof_pb.rb +0 -81
  251. data/lib/datadog/profiling/pprof/stack_sample.rb +0 -139
  252. data/lib/datadog/profiling/pprof/string_table.rb +0 -12
  253. data/lib/datadog/profiling/pprof/template.rb +0 -118
  254. data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +0 -43
  255. data/lib/datadog/profiling/trace_identifiers/helper.rb +0 -45
  256. data/lib/ddtrace/transport/http/adapters/net.rb +0 -168
  257. data/lib/ddtrace/transport/http/adapters/registry.rb +0 -27
  258. data/lib/ddtrace/transport/http/adapters/test.rb +0 -85
  259. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +0 -77
  260. data/lib/ddtrace/transport/http/api/endpoint.rb +0 -29
  261. data/lib/ddtrace/transport/http/api/fallbacks.rb +0 -24
  262. data/lib/ddtrace/transport/http/api/instance.rb +0 -35
  263. data/lib/ddtrace/transport/http/api/map.rb +0 -16
  264. data/lib/ddtrace/transport/http/api/spec.rb +0 -17
  265. data/lib/ddtrace/transport/http/api.rb +0 -39
  266. data/lib/ddtrace/transport/http/builder.rb +0 -176
  267. data/lib/ddtrace/transport/http/client.rb +0 -52
  268. data/lib/ddtrace/transport/http/env.rb +0 -58
  269. data/lib/ddtrace/transport/http/response.rb +0 -58
  270. data/lib/ddtrace/transport/http/statistics.rb +0 -43
  271. data/lib/ddtrace/transport/http/traces.rb +0 -144
  272. data/lib/ddtrace/transport/http.rb +0 -117
  273. data/lib/ddtrace/transport/io/client.rb +0 -85
  274. data/lib/ddtrace/transport/io/response.rb +0 -25
  275. data/lib/ddtrace/transport/io/traces.rb +0 -99
  276. data/lib/ddtrace/transport/io.rb +0 -28
  277. data/lib/ddtrace/transport/parcel.rb +0 -20
  278. data/lib/ddtrace/transport/request.rb +0 -15
  279. data/lib/ddtrace/transport/response.rb +0 -60
  280. data/lib/ddtrace/transport/serializable_trace.rb +0 -122
  281. data/lib/ddtrace/transport/statistics.rb +0 -75
  282. data/lib/ddtrace/transport/trace_formatter.rb +0 -207
  283. data/lib/ddtrace/transport/traces.rb +0 -216
@@ -13,7 +13,7 @@ void sample_thread(
13
13
  sampling_buffer* buffer,
14
14
  VALUE recorder_instance,
15
15
  sample_values values,
16
- ddog_prof_Slice_Label labels,
16
+ sample_labels labels,
17
17
  sample_type type
18
18
  );
19
19
  sampling_buffer *sampling_buffer_new(unsigned int max_frames);
@@ -101,6 +101,8 @@ struct thread_context_collector_state {
101
101
  bool endpoint_collection_enabled;
102
102
  // Used to omit timestamps / timeline events from collected data
103
103
  bool timeline_enabled;
104
+ // Used to omit class information from collected allocation data
105
+ bool allocation_type_enabled;
104
106
  // Used when calling monotonic_to_system_epoch_ns
105
107
  monotonic_to_system_epoch_state time_converter_state;
106
108
  // Used to identify the main thread, to give it a fallback name
@@ -157,7 +159,8 @@ static VALUE _native_initialize(
157
159
  VALUE max_frames,
158
160
  VALUE tracer_context_key,
159
161
  VALUE endpoint_collection_enabled,
160
- VALUE timeline_enabled
162
+ VALUE timeline_enabled,
163
+ VALUE allocation_type_enabled
161
164
  );
162
165
  static VALUE _native_sample(VALUE self, VALUE collector_instance, VALUE profiler_overhead_stack_thread);
163
166
  static VALUE _native_on_gc_start(VALUE self, VALUE collector_instance);
@@ -178,7 +181,9 @@ static void trigger_sample_for_thread(
178
181
  struct per_thread_context *thread_context,
179
182
  sample_values values,
180
183
  sample_type type,
181
- long current_monotonic_wall_time_ns
184
+ long current_monotonic_wall_time_ns,
185
+ ddog_CharSlice *ruby_vm_type,
186
+ ddog_CharSlice *class_name
182
187
  );
183
188
  static VALUE _native_thread_list(VALUE self);
184
189
  static struct per_thread_context *get_or_create_context_for(VALUE thread, struct thread_context_collector_state *state);
@@ -196,11 +201,12 @@ static long cpu_time_now_ns(struct per_thread_context *thread_context);
196
201
  static long thread_id_for(VALUE thread);
197
202
  static VALUE _native_stats(VALUE self, VALUE collector_instance);
198
203
  static void trace_identifiers_for(struct thread_context_collector_state *state, VALUE thread, struct trace_identifiers *trace_identifiers_result);
199
- static bool is_type_web(VALUE root_span_type);
204
+ static bool should_collect_resource(VALUE root_span_type);
200
205
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
201
206
  static VALUE thread_list(struct thread_context_collector_state *state);
202
- static VALUE _native_sample_allocation(VALUE self, VALUE collector_instance, VALUE sample_weight);
207
+ static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object);
203
208
  static VALUE _native_new_empty_thread(VALUE self);
209
+ ddog_CharSlice ruby_value_type_to_class_name(enum ruby_value_type type);
204
210
 
205
211
  void collectors_thread_context_init(VALUE profiling_module) {
206
212
  VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
@@ -218,11 +224,11 @@ void collectors_thread_context_init(VALUE profiling_module) {
218
224
  // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
219
225
  rb_define_alloc_func(collectors_thread_context_class, _native_new);
220
226
 
221
- rb_define_singleton_method(collectors_thread_context_class, "_native_initialize", _native_initialize, 6);
227
+ rb_define_singleton_method(collectors_thread_context_class, "_native_initialize", _native_initialize, 7);
222
228
  rb_define_singleton_method(collectors_thread_context_class, "_native_inspect", _native_inspect, 1);
223
229
  rb_define_singleton_method(collectors_thread_context_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
224
230
  rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 2);
225
- rb_define_singleton_method(testing_module, "_native_sample_allocation", _native_sample_allocation, 2);
231
+ rb_define_singleton_method(testing_module, "_native_sample_allocation", _native_sample_allocation, 3);
226
232
  rb_define_singleton_method(testing_module, "_native_on_gc_start", _native_on_gc_start, 1);
227
233
  rb_define_singleton_method(testing_module, "_native_on_gc_finish", _native_on_gc_finish, 1);
228
234
  rb_define_singleton_method(testing_module, "_native_sample_after_gc", _native_sample_after_gc, 1);
@@ -298,6 +304,9 @@ static int hash_map_per_thread_context_free_values(DDTRACE_UNUSED st_data_t _thr
298
304
  static VALUE _native_new(VALUE klass) {
299
305
  struct thread_context_collector_state *state = ruby_xcalloc(1, sizeof(struct thread_context_collector_state));
300
306
 
307
+ // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
308
+ // being leaked.
309
+
301
310
  // Update this when modifying state struct
302
311
  state->sampling_buffer = NULL;
303
312
  state->hash_map_per_thread_context =
@@ -308,6 +317,7 @@ static VALUE _native_new(VALUE klass) {
308
317
  state->thread_list_buffer = rb_ary_new();
309
318
  state->endpoint_collection_enabled = true;
310
319
  state->timeline_enabled = true;
320
+ state->allocation_type_enabled = true;
311
321
  state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
312
322
  state->main_thread = rb_thread_main();
313
323
 
@@ -321,10 +331,12 @@ static VALUE _native_initialize(
321
331
  VALUE max_frames,
322
332
  VALUE tracer_context_key,
323
333
  VALUE endpoint_collection_enabled,
324
- VALUE timeline_enabled
334
+ VALUE timeline_enabled,
335
+ VALUE allocation_type_enabled
325
336
  ) {
326
337
  ENFORCE_BOOLEAN(endpoint_collection_enabled);
327
338
  ENFORCE_BOOLEAN(timeline_enabled);
339
+ ENFORCE_BOOLEAN(allocation_type_enabled);
328
340
 
329
341
  struct thread_context_collector_state *state;
330
342
  TypedData_Get_Struct(collector_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state);
@@ -338,6 +350,7 @@ static VALUE _native_initialize(
338
350
  state->recorder_instance = enforce_recorder_instance(recorder_instance);
339
351
  state->endpoint_collection_enabled = (endpoint_collection_enabled == Qtrue);
340
352
  state->timeline_enabled = (timeline_enabled == Qtrue);
353
+ state->allocation_type_enabled = (allocation_type_enabled == Qtrue);
341
354
 
342
355
  if (RTEST(tracer_context_key)) {
343
356
  ENFORCE_TYPE(tracer_context_key, T_SYMBOL);
@@ -461,9 +474,11 @@ void update_metrics_and_sample(
461
474
  thread_being_sampled,
462
475
  stack_from_thread,
463
476
  thread_context,
464
- (sample_values) {.cpu_time_ns = cpu_time_elapsed_ns, .cpu_samples = 1, .wall_time_ns = wall_time_elapsed_ns},
477
+ (sample_values) {.cpu_time_ns = cpu_time_elapsed_ns, .cpu_or_wall_samples = 1, .wall_time_ns = wall_time_elapsed_ns},
465
478
  SAMPLE_REGULAR,
466
- current_monotonic_wall_time_ns
479
+ current_monotonic_wall_time_ns,
480
+ NULL,
481
+ NULL
467
482
  );
468
483
  }
469
484
 
@@ -604,9 +619,11 @@ VALUE thread_context_collector_sample_after_gc(VALUE self_instance) {
604
619
  /* thread: */ thread,
605
620
  /* stack_from_thread: */ thread,
606
621
  thread_context,
607
- (sample_values) {.cpu_time_ns = gc_cpu_time_elapsed_ns, .cpu_samples = 1, .wall_time_ns = gc_wall_time_elapsed_ns},
622
+ (sample_values) {.cpu_time_ns = gc_cpu_time_elapsed_ns, .cpu_or_wall_samples = 1, .wall_time_ns = gc_wall_time_elapsed_ns},
608
623
  SAMPLE_IN_GC,
609
- INVALID_TIME // For now we're not collecting timestamps for these events
624
+ INVALID_TIME, // For now we're not collecting timestamps for these events
625
+ NULL,
626
+ NULL
610
627
  );
611
628
 
612
629
  // Mark thread as no longer in GC
@@ -637,13 +654,17 @@ static void trigger_sample_for_thread(
637
654
  struct per_thread_context *thread_context,
638
655
  sample_values values,
639
656
  sample_type type,
640
- long current_monotonic_wall_time_ns
657
+ long current_monotonic_wall_time_ns,
658
+ // These two labels are only used for allocation profiling; @ivoanjo: may want to refactor this at some point?
659
+ ddog_CharSlice *ruby_vm_type,
660
+ ddog_CharSlice *class_name
641
661
  ) {
642
662
  int max_label_count =
643
663
  1 + // thread id
644
664
  1 + // thread name
645
665
  1 + // profiler overhead
646
- 1 + // end_timestamp_ns
666
+ 2 + // ruby vm type and allocation class
667
+ 1 + // state (only set for cpu/wall-time samples)
647
668
  2; // local root span id and span id
648
669
  ddog_prof_Label labels[max_label_count];
649
670
  int label_pos = 0;
@@ -706,10 +727,31 @@ static void trigger_sample_for_thread(
706
727
  };
707
728
  }
708
729
 
709
- if (state->timeline_enabled && current_monotonic_wall_time_ns != INVALID_TIME) {
730
+ if (ruby_vm_type != NULL) {
710
731
  labels[label_pos++] = (ddog_prof_Label) {
711
- .key = DDOG_CHARSLICE_C("end_timestamp_ns"),
712
- .num = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns)
732
+ .key = DDOG_CHARSLICE_C("ruby vm type"),
733
+ .str = *ruby_vm_type
734
+ };
735
+ }
736
+
737
+ if (class_name != NULL) {
738
+ labels[label_pos++] = (ddog_prof_Label) {
739
+ .key = DDOG_CHARSLICE_C("allocation class"),
740
+ .str = *class_name
741
+ };
742
+ }
743
+
744
+ // This label is handled specially:
745
+ // 1. It's only set for cpu/wall-time samples
746
+ // 2. We set it here to its default state of "unknown", but the `Collectors::Stack` may choose to override it with
747
+ // something more interesting.
748
+ ddog_prof_Label *state_label = NULL;
749
+ if (values.cpu_or_wall_samples > 0) {
750
+ state_label = &labels[label_pos++];
751
+ *state_label = (ddog_prof_Label) {
752
+ .key = DDOG_CHARSLICE_C("state"),
753
+ .str = DDOG_CHARSLICE_C("unknown"),
754
+ .num = 0, // This shouldn't be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this
713
755
  };
714
756
  }
715
757
 
@@ -721,12 +763,20 @@ static void trigger_sample_for_thread(
721
763
  rb_raise(rb_eRuntimeError, "BUG: Unexpected label_pos (%d) > max_label_count (%d)", label_pos, max_label_count);
722
764
  }
723
765
 
766
+ ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = label_pos};
767
+
768
+ // The end_timestamp_ns is treated specially by libdatadog and that's why it's not added as a ddog_prof_Label
769
+ int64_t end_timestamp_ns = 0;
770
+ if (state->timeline_enabled && current_monotonic_wall_time_ns != INVALID_TIME) {
771
+ end_timestamp_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns);
772
+ }
773
+
724
774
  sample_thread(
725
775
  stack_from_thread,
726
776
  state->sampling_buffer,
727
777
  state->recorder_instance,
728
778
  values,
729
- (ddog_prof_Slice_Label) {.ptr = labels, .len = label_pos},
779
+ (sample_labels) {.labels = slice_labels, .state_label = state_label, .end_timestamp_ns = end_timestamp_ns},
730
780
  type
731
781
  );
732
782
  }
@@ -765,6 +815,27 @@ static struct per_thread_context *get_context_for(VALUE thread, struct thread_co
765
815
  return thread_context;
766
816
  }
767
817
 
818
+ #define LOGGING_GEM_PATH "/lib/logging/diagnostic_context.rb"
819
+
820
+ // The `logging` gem monkey patches thread creation, which makes the `invoke_location_for` useless, since every thread
821
+ // will point to the `logging` gem. When that happens, we avoid using the invoke location.
822
+ //
823
+ // TODO: This approach is a bit brittle, since it matches on the specific gem path, and only works for the `logging`
824
+ // gem.
825
+ // In the future we should probably explore a more generic fix (e.g. using Thread.method(:new).source_location or
826
+ // something like that to detect redefinition of the `Thread` methods). One difficulty of doing it is that we need
827
+ // to either run Ruby code during sampling (not great), or otherwise use some of the VM private APIs to detect this.
828
+ //
829
+ static bool is_logging_gem_monkey_patch(VALUE invoke_file_location) {
830
+ int logging_gem_path_len = strlen(LOGGING_GEM_PATH);
831
+ char *invoke_file = StringValueCStr(invoke_file_location);
832
+ int invoke_file_len = strlen(invoke_file);
833
+
834
+ if (invoke_file_len < logging_gem_path_len) return false;
835
+
836
+ return strncmp(invoke_file + invoke_file_len - logging_gem_path_len, LOGGING_GEM_PATH, logging_gem_path_len) == 0;
837
+ }
838
+
768
839
  static void initialize_context(VALUE thread, struct per_thread_context *thread_context, struct thread_context_collector_state *state) {
769
840
  snprintf(thread_context->thread_id, THREAD_ID_LIMIT_CHARS, "%"PRIu64" (%lu)", native_thread_id_for(thread), (unsigned long) thread_id_for(thread));
770
841
  thread_context->thread_id_char_slice = (ddog_CharSlice) {.ptr = thread_context->thread_id, .len = strlen(thread_context->thread_id)};
@@ -772,13 +843,17 @@ static void initialize_context(VALUE thread, struct per_thread_context *thread_c
772
843
  int invoke_line_location;
773
844
  VALUE invoke_file_location = invoke_location_for(thread, &invoke_line_location);
774
845
  if (invoke_file_location != Qnil) {
775
- snprintf(
776
- thread_context->thread_invoke_location,
777
- THREAD_INVOKE_LOCATION_LIMIT_CHARS,
778
- "%s:%d",
779
- StringValueCStr(invoke_file_location),
780
- invoke_line_location
781
- );
846
+ if (!is_logging_gem_monkey_patch(invoke_file_location)) {
847
+ snprintf(
848
+ thread_context->thread_invoke_location,
849
+ THREAD_INVOKE_LOCATION_LIMIT_CHARS,
850
+ "%s:%d",
851
+ StringValueCStr(invoke_file_location),
852
+ invoke_line_location
853
+ );
854
+ } else {
855
+ snprintf(thread_context->thread_invoke_location, THREAD_INVOKE_LOCATION_LIMIT_CHARS, "%s", "(Unnamed thread)");
856
+ }
782
857
  } else if (thread != state->main_thread) {
783
858
  // If the first function of a thread is native code, there won't be an invoke location, so we use this fallback.
784
859
  // NOTE: In the future, I wonder if we could take the pointer to the native function, and try to see if there's a native
@@ -819,6 +894,7 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
819
894
  rb_str_concat(result, rb_sprintf(" stats=%"PRIsVALUE, stats_as_ruby_hash(state)));
820
895
  rb_str_concat(result, rb_sprintf(" endpoint_collection_enabled=%"PRIsVALUE, state->endpoint_collection_enabled ? Qtrue : Qfalse));
821
896
  rb_str_concat(result, rb_sprintf(" timeline_enabled=%"PRIsVALUE, state->timeline_enabled ? Qtrue : Qfalse));
897
+ rb_str_concat(result, rb_sprintf(" allocation_type_enabled=%"PRIsVALUE, state->allocation_type_enabled ? Qtrue : Qfalse));
822
898
  rb_str_concat(result, rb_sprintf(
823
899
  " time_converter_state={.system_epoch_ns_reference=%ld, .delta_to_epoch_ns=%ld}",
824
900
  state->time_converter_state.system_epoch_ns_reference,
@@ -1008,7 +1084,7 @@ static void trace_identifiers_for(struct thread_context_collector_state *state,
1008
1084
  if (!state->endpoint_collection_enabled) return;
1009
1085
 
1010
1086
  VALUE root_span_type = rb_ivar_get(root_span, at_type_id /* @type */);
1011
- if (root_span_type == Qnil || !is_type_web(root_span_type)) return;
1087
+ if (root_span_type == Qnil || !should_collect_resource(root_span_type)) return;
1012
1088
 
1013
1089
  VALUE trace_resource = rb_ivar_get(active_trace, at_resource_id /* @resource */);
1014
1090
  if (RB_TYPE_P(trace_resource, T_STRING)) {
@@ -1019,11 +1095,21 @@ static void trace_identifiers_for(struct thread_context_collector_state *state,
1019
1095
  }
1020
1096
  }
1021
1097
 
1022
- static bool is_type_web(VALUE root_span_type) {
1098
+ // We only collect the resource for spans of types:
1099
+ // * 'web', for web requests
1100
+ // * proxy', used by the rack integration with request_queuing: true (e.g. also represents a web request)
1101
+ //
1102
+ // NOTE: Currently we're only interested in HTTP service endpoints. Over time, this list may be expanded.
1103
+ // Resources MUST NOT include personal identifiable information (PII); this should not be the case with
1104
+ // ddtrace integrations, but worth mentioning just in case :)
1105
+ static bool should_collect_resource(VALUE root_span_type) {
1023
1106
  ENFORCE_TYPE(root_span_type, T_STRING);
1024
1107
 
1025
- return RSTRING_LEN(root_span_type) == strlen("web") &&
1026
- (memcmp("web", StringValuePtr(root_span_type), strlen("web")) == 0);
1108
+ int root_span_type_length = RSTRING_LEN(root_span_type);
1109
+ const char *root_span_type_value = StringValuePtr(root_span_type);
1110
+
1111
+ return (root_span_type_length == strlen("web") && (memcmp("web", root_span_type_value, strlen("web")) == 0)) ||
1112
+ (root_span_type_length == strlen("proxy") && (memcmp("proxy", root_span_type_value, strlen("proxy")) == 0));
1027
1113
  }
1028
1114
 
1029
1115
  // After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
@@ -1050,12 +1136,73 @@ static VALUE thread_list(struct thread_context_collector_state *state) {
1050
1136
  return result;
1051
1137
  }
1052
1138
 
1053
- void thread_context_collector_sample_allocation(VALUE self_instance, unsigned int sample_weight) {
1139
+ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned int sample_weight, VALUE new_object) {
1054
1140
  struct thread_context_collector_state *state;
1055
1141
  TypedData_Get_Struct(self_instance, struct thread_context_collector_state, &thread_context_collector_typed_data, state);
1056
1142
 
1057
1143
  VALUE current_thread = rb_thread_current();
1058
1144
 
1145
+ enum ruby_value_type type = rb_type(new_object);
1146
+
1147
+ // Tag samples with the VM internal types
1148
+ ddog_CharSlice ruby_vm_type = ruby_value_type_to_char_slice(type);
1149
+
1150
+ // Since this is stack allocated, be careful about moving it
1151
+ ddog_CharSlice class_name;
1152
+ ddog_CharSlice *optional_class_name = NULL;
1153
+
1154
+ if (state->allocation_type_enabled) {
1155
+ optional_class_name = &class_name;
1156
+
1157
+ if (
1158
+ type == RUBY_T_OBJECT ||
1159
+ type == RUBY_T_CLASS ||
1160
+ type == RUBY_T_MODULE ||
1161
+ type == RUBY_T_FLOAT ||
1162
+ type == RUBY_T_STRING ||
1163
+ type == RUBY_T_REGEXP ||
1164
+ type == RUBY_T_ARRAY ||
1165
+ type == RUBY_T_HASH ||
1166
+ type == RUBY_T_STRUCT ||
1167
+ type == RUBY_T_BIGNUM ||
1168
+ type == RUBY_T_FILE ||
1169
+ type == RUBY_T_DATA ||
1170
+ type == RUBY_T_MATCH ||
1171
+ type == RUBY_T_COMPLEX ||
1172
+ type == RUBY_T_RATIONAL ||
1173
+ type == RUBY_T_NIL ||
1174
+ type == RUBY_T_TRUE ||
1175
+ type == RUBY_T_FALSE ||
1176
+ type == RUBY_T_SYMBOL ||
1177
+ type == RUBY_T_FIXNUM
1178
+ ) {
1179
+ VALUE klass = rb_class_of(new_object);
1180
+
1181
+ // Ruby sometimes plays a bit fast and loose with some of its internal objects, e.g.
1182
+ // `rb_str_tmp_frozen_acquire` allocates a string with no class (klass=0).
1183
+ // Thus, we need to make sure there's actually a class before getting its name.
1184
+
1185
+ if (klass != 0) {
1186
+ const char *name = rb_obj_classname(new_object);
1187
+ size_t name_length = name != NULL ? strlen(name) : 0;
1188
+
1189
+ if (name_length > 0) {
1190
+ class_name = (ddog_CharSlice) {.ptr = name, .len = name_length};
1191
+ } else {
1192
+ // @ivoanjo: I'm not sure this can ever happen, but just-in-case
1193
+ class_name = ruby_value_type_to_class_name(type);
1194
+ }
1195
+ } else {
1196
+ // Fallback for objects with no class
1197
+ class_name = ruby_value_type_to_class_name(type);
1198
+ }
1199
+ } else if (type == RUBY_T_IMEMO) {
1200
+ class_name = DDOG_CHARSLICE_C("(VM Internal, T_IMEMO)");
1201
+ } else {
1202
+ class_name = ruby_vm_type; // For other weird internal things we just use the VM type
1203
+ }
1204
+ }
1205
+
1059
1206
  trigger_sample_for_thread(
1060
1207
  state,
1061
1208
  /* thread: */ current_thread,
@@ -1063,14 +1210,16 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
1063
1210
  get_or_create_context_for(current_thread, state),
1064
1211
  (sample_values) {.alloc_samples = sample_weight},
1065
1212
  SAMPLE_REGULAR,
1066
- INVALID_TIME // For now we're not collecting timestamps for allocation events, as per profiling team internal discussions
1213
+ INVALID_TIME, // For now we're not collecting timestamps for allocation events, as per profiling team internal discussions
1214
+ &ruby_vm_type,
1215
+ optional_class_name
1067
1216
  );
1068
1217
  }
1069
1218
 
1070
1219
  // This method exists only to enable testing Datadog::Profiling::Collectors::ThreadContext behavior using RSpec.
1071
1220
  // It SHOULD NOT be used for other purposes.
1072
- static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight) {
1073
- thread_context_collector_sample_allocation(collector_instance, NUM2UINT(sample_weight));
1221
+ static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object) {
1222
+ thread_context_collector_sample_allocation(collector_instance, NUM2UINT(sample_weight), new_object);
1074
1223
  return Qtrue;
1075
1224
  }
1076
1225
 
@@ -1082,3 +1231,29 @@ static VALUE new_empty_thread_inner(DDTRACE_UNUSED void *arg) { return Qnil; }
1082
1231
  static VALUE _native_new_empty_thread(DDTRACE_UNUSED VALUE self) {
1083
1232
  return rb_thread_create(new_empty_thread_inner, NULL);
1084
1233
  }
1234
+
1235
+ ddog_CharSlice ruby_value_type_to_class_name(enum ruby_value_type type) {
1236
+ switch (type) {
1237
+ case(RUBY_T_OBJECT ): return DDOG_CHARSLICE_C("Object");
1238
+ case(RUBY_T_CLASS ): return DDOG_CHARSLICE_C("Class");
1239
+ case(RUBY_T_MODULE ): return DDOG_CHARSLICE_C("Module");
1240
+ case(RUBY_T_FLOAT ): return DDOG_CHARSLICE_C("Float");
1241
+ case(RUBY_T_STRING ): return DDOG_CHARSLICE_C("String");
1242
+ case(RUBY_T_REGEXP ): return DDOG_CHARSLICE_C("Regexp");
1243
+ case(RUBY_T_ARRAY ): return DDOG_CHARSLICE_C("Array");
1244
+ case(RUBY_T_HASH ): return DDOG_CHARSLICE_C("Hash");
1245
+ case(RUBY_T_STRUCT ): return DDOG_CHARSLICE_C("Struct");
1246
+ case(RUBY_T_BIGNUM ): return DDOG_CHARSLICE_C("Integer");
1247
+ case(RUBY_T_FILE ): return DDOG_CHARSLICE_C("File");
1248
+ case(RUBY_T_DATA ): return DDOG_CHARSLICE_C("(VM Internal, T_DATA)");
1249
+ case(RUBY_T_MATCH ): return DDOG_CHARSLICE_C("MatchData");
1250
+ case(RUBY_T_COMPLEX ): return DDOG_CHARSLICE_C("Complex");
1251
+ case(RUBY_T_RATIONAL): return DDOG_CHARSLICE_C("Rational");
1252
+ case(RUBY_T_NIL ): return DDOG_CHARSLICE_C("NilClass");
1253
+ case(RUBY_T_TRUE ): return DDOG_CHARSLICE_C("TrueClass");
1254
+ case(RUBY_T_FALSE ): return DDOG_CHARSLICE_C("FalseClass");
1255
+ case(RUBY_T_SYMBOL ): return DDOG_CHARSLICE_C("Symbol");
1256
+ case(RUBY_T_FIXNUM ): return DDOG_CHARSLICE_C("Integer");
1257
+ default: return DDOG_CHARSLICE_C("(VM Internal, Missing class)");
1258
+ }
1259
+ }
@@ -7,7 +7,7 @@ void thread_context_collector_sample(
7
7
  long current_monotonic_wall_time_ns,
8
8
  VALUE profiler_overhead_stack_thread
9
9
  );
10
- void thread_context_collector_sample_allocation(VALUE self_instance, unsigned int sample_weight);
10
+ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned int sample_weight, VALUE new_object);
11
11
  VALUE thread_context_collector_sample_after_gc(VALUE self_instance);
12
12
  void thread_context_collector_on_gc_start(VALUE self_instance);
13
13
  void thread_context_collector_on_gc_finish(VALUE self_instance);
@@ -82,9 +82,9 @@ end
82
82
  # Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
83
83
  # But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
84
84
  #
85
- # @ivoanjo TODO: Ruby 3.3.0-preview1 was causing issues in CI because `have_header('vm_core.h')` below triggers warnings;
85
+ # @ivoanjo TODO: 3.3.0-preview releases are causing issues in CI because `have_header('vm_core.h')` below triggers warnings;
86
86
  # I've chosen to disable `-Werror` for this Ruby version for now, and we can revisit this on a later 3.3 release.
87
- add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.0preview1')
87
+ add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.0preview')
88
88
 
89
89
  # Older gcc releases may not default to C99 and we need to ask for this. This is also used:
90
90
  # * by upstream Ruby -- search for gnu99 in the codebase
@@ -146,6 +146,9 @@ $defs << '-DNO_RB_THREAD_SCHED' if RUBY_VERSION < '3.2'
146
146
  # On older Rubies, the first_lineno inside a location was a VALUE and not a int (https://github.com/ruby/ruby/pull/6430)
147
147
  $defs << '-DNO_INT_FIRST_LINENO' if RUBY_VERSION < '3.2'
148
148
 
149
+ # On older Rubies, "pop" was not a primitive operation
150
+ $defs << '-DNO_PRIMITIVE_POP' if RUBY_VERSION < '3.2'
151
+
149
152
  # On older Rubies, there was no tid member in the internal thread structure
150
153
  $defs << '-DNO_THREAD_TID' if RUBY_VERSION < '3.1'
151
154
 
@@ -155,6 +158,9 @@ $defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
155
158
  # On older Rubies, there are no Ractors
156
159
  $defs << '-DNO_RACTORS' if RUBY_VERSION < '3'
157
160
 
161
+ # On older Rubies, objects would not move
162
+ $defs << '-DNO_T_MOVED' if RUBY_VERSION < '2.7'
163
+
158
164
  # On older Rubies, rb_global_vm_lock_struct did not include the owner field
159
165
  $defs << '-DNO_GVL_OWNER' if RUBY_VERSION < '2.6'
160
166
 
@@ -201,7 +201,8 @@ static VALUE perform_export(
201
201
  ddog_prof_Exporter *exporter,
202
202
  ddog_Timespec start,
203
203
  ddog_Timespec finish,
204
- ddog_prof_Exporter_Slice_File slice_files,
204
+ ddog_prof_Exporter_Slice_File files_to_compress_and_export,
205
+ ddog_prof_Exporter_Slice_File files_to_export_unmodified,
205
206
  ddog_Vec_Tag *additional_tags,
206
207
  ddog_CharSlice internal_metadata,
207
208
  uint64_t timeout_milliseconds
@@ -211,7 +212,8 @@ static VALUE perform_export(
211
212
  exporter,
212
213
  start,
213
214
  finish,
214
- slice_files,
215
+ files_to_compress_and_export,
216
+ files_to_export_unmodified,
215
217
  additional_tags,
216
218
  endpoints_stats,
217
219
  &internal_metadata,
@@ -308,18 +310,23 @@ static VALUE _native_do_export(
308
310
  ddog_Timespec finish =
309
311
  {.seconds = NUM2LONG(finish_timespec_seconds), .nanoseconds = NUM2UINT(finish_timespec_nanoseconds)};
310
312
 
311
- int files_to_report = 1 + (have_code_provenance ? 1 : 0);
312
- ddog_prof_Exporter_File files[files_to_report];
313
- ddog_prof_Exporter_Slice_File slice_files = {.ptr = files, .len = files_to_report};
313
+ int to_compress_length = have_code_provenance ? 1 : 0;
314
+ ddog_prof_Exporter_File to_compress[to_compress_length];
315
+ int already_compressed_length = 1; // pprof
316
+ ddog_prof_Exporter_File already_compressed[already_compressed_length];
314
317
 
315
- files[0] = (ddog_prof_Exporter_File) {
318
+ ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
319
+ ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
320
+
321
+ already_compressed[0] = (ddog_prof_Exporter_File) {
316
322
  .name = char_slice_from_ruby_string(pprof_file_name),
317
- .file = byte_slice_from_ruby_string(pprof_data)
323
+ .file = byte_slice_from_ruby_string(pprof_data),
318
324
  };
325
+
319
326
  if (have_code_provenance) {
320
- files[1] = (ddog_prof_Exporter_File) {
327
+ to_compress[0] = (ddog_prof_Exporter_File) {
321
328
  .name = char_slice_from_ruby_string(code_provenance_file_name),
322
- .file = byte_slice_from_ruby_string(code_provenance_data)
329
+ .file = byte_slice_from_ruby_string(code_provenance_data),
323
330
  };
324
331
  }
325
332
 
@@ -332,7 +339,16 @@ static VALUE _native_do_export(
332
339
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
333
340
  if (!NIL_P(failure_tuple)) return failure_tuple;
334
341
 
335
- return perform_export(exporter_result.ok, start, finish, slice_files, null_additional_tags, internal_metadata, timeout_milliseconds);
342
+ return perform_export(
343
+ exporter_result.ok,
344
+ start,
345
+ finish,
346
+ files_to_compress_and_export,
347
+ files_to_export_unmodified,
348
+ null_additional_tags,
349
+ internal_metadata,
350
+ timeout_milliseconds
351
+ );
336
352
  }
337
353
 
338
354
  static void *call_exporter_without_gvl(void *call_args) {
@@ -0,0 +1,42 @@
1
+ #include "libdatadog_helpers.h"
2
+
3
+ #include <ruby.h>
4
+
5
+ const char *ruby_value_type_to_string(enum ruby_value_type type) {
6
+ return ruby_value_type_to_char_slice(type).ptr;
7
+ }
8
+
9
+ ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type) {
10
+ switch (type) {
11
+ case(RUBY_T_NONE ): return DDOG_CHARSLICE_C("T_NONE");
12
+ case(RUBY_T_OBJECT ): return DDOG_CHARSLICE_C("T_OBJECT");
13
+ case(RUBY_T_CLASS ): return DDOG_CHARSLICE_C("T_CLASS");
14
+ case(RUBY_T_MODULE ): return DDOG_CHARSLICE_C("T_MODULE");
15
+ case(RUBY_T_FLOAT ): return DDOG_CHARSLICE_C("T_FLOAT");
16
+ case(RUBY_T_STRING ): return DDOG_CHARSLICE_C("T_STRING");
17
+ case(RUBY_T_REGEXP ): return DDOG_CHARSLICE_C("T_REGEXP");
18
+ case(RUBY_T_ARRAY ): return DDOG_CHARSLICE_C("T_ARRAY");
19
+ case(RUBY_T_HASH ): return DDOG_CHARSLICE_C("T_HASH");
20
+ case(RUBY_T_STRUCT ): return DDOG_CHARSLICE_C("T_STRUCT");
21
+ case(RUBY_T_BIGNUM ): return DDOG_CHARSLICE_C("T_BIGNUM");
22
+ case(RUBY_T_FILE ): return DDOG_CHARSLICE_C("T_FILE");
23
+ case(RUBY_T_DATA ): return DDOG_CHARSLICE_C("T_DATA");
24
+ case(RUBY_T_MATCH ): return DDOG_CHARSLICE_C("T_MATCH");
25
+ case(RUBY_T_COMPLEX ): return DDOG_CHARSLICE_C("T_COMPLEX");
26
+ case(RUBY_T_RATIONAL): return DDOG_CHARSLICE_C("T_RATIONAL");
27
+ case(RUBY_T_NIL ): return DDOG_CHARSLICE_C("T_NIL");
28
+ case(RUBY_T_TRUE ): return DDOG_CHARSLICE_C("T_TRUE");
29
+ case(RUBY_T_FALSE ): return DDOG_CHARSLICE_C("T_FALSE");
30
+ case(RUBY_T_SYMBOL ): return DDOG_CHARSLICE_C("T_SYMBOL");
31
+ case(RUBY_T_FIXNUM ): return DDOG_CHARSLICE_C("T_FIXNUM");
32
+ case(RUBY_T_UNDEF ): return DDOG_CHARSLICE_C("T_UNDEF");
33
+ case(RUBY_T_IMEMO ): return DDOG_CHARSLICE_C("T_IMEMO");
34
+ case(RUBY_T_NODE ): return DDOG_CHARSLICE_C("T_NODE");
35
+ case(RUBY_T_ICLASS ): return DDOG_CHARSLICE_C("T_ICLASS");
36
+ case(RUBY_T_ZOMBIE ): return DDOG_CHARSLICE_C("T_ZOMBIE");
37
+ #ifndef NO_T_MOVED
38
+ case(RUBY_T_MOVED ): return DDOG_CHARSLICE_C("T_MOVED");
39
+ #endif
40
+ default: return DDOG_CHARSLICE_C("BUG: Unknown value for ruby_value_type");
41
+ }
42
+ }
@@ -23,3 +23,9 @@ inline static VALUE get_error_details_and_drop(ddog_Error *error) {
23
23
  ddog_Error_drop(error);
24
24
  return result;
25
25
  }
26
+
27
+ // Used for pretty printing this Ruby enum. Returns "T_UNKNOWN_OR_MISSING_RUBY_VALUE_TYPE_ENTRY" for unknown elements.
28
+ // In practice, there's a few types that the profiler will probably never encounter, but I've added all entries of
29
+ // ruby_value_type that Ruby uses so that we can also use this for debugging.
30
+ const char *ruby_value_type_to_string(enum ruby_value_type type);
31
+ ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
@@ -15,7 +15,7 @@ module Datadog
15
15
  # The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on debase-ruby_core_source
16
16
  CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?('2.6', '2.7', '3.0.', '3.1.', '3.2.')
17
17
 
18
- LIBDATADOG_VERSION = '~> 3.0.0.1.0'
18
+ LIBDATADOG_VERSION = '~> 5.0.0.1.0'
19
19
 
20
20
  def self.fail_install_if_missing_extension?
21
21
  ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == 'true'
@@ -87,7 +87,6 @@ module Datadog
87
87
  on_unknown_os? ||
88
88
  on_unsupported_cpu_arch? ||
89
89
  on_unsupported_ruby_version? ||
90
- on_ruby_3_3? ||
91
90
  expected_to_use_mjit_but_mjit_is_disabled? ||
92
91
  libdatadog_not_available? ||
93
92
  libdatadog_not_usable?
@@ -270,20 +269,6 @@ module Datadog
270
269
  ruby_version_not_supported if RUBY_VERSION.start_with?('2.1.', '2.2.')
271
270
  end
272
271
 
273
- private_class_method def self.on_ruby_3_3?
274
- incompatible_with_3_3 = explain_issue(
275
- 'the profiler in the current version of ddtrace does not yet support',
276
- 'Ruby version 3.3.',
277
- '(See https://github.com/datadog/dd-trace-rb/issues/3053 for details).',
278
- suggested: [
279
- 'Try upgrading to the latest ddtrace, as this issue may have been',
280
- 'fixed by now.',
281
- ] + CONTACT_SUPPORT,
282
- )
283
-
284
- incompatible_with_3_3 if RUBY_VERSION.start_with?('3.3.')
285
- end
286
-
287
272
  # On some Rubies, we require the mjit header to be present. If Ruby was installed without MJIT support, we also skip
288
273
  # building the extension.
289
274
  private_class_method def self.expected_to_use_mjit_but_mjit_is_disabled?