datadog 2.16.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  8. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  9. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  10. data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
  13. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  14. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  15. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  16. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
  17. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
  18. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
  19. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  20. data/ext/datadog_profiling_native_extension/stack_recorder.c +156 -60
  21. data/ext/libdatadog_api/crashtracker.c +10 -3
  22. data/ext/libdatadog_api/extconf.rb +2 -2
  23. data/ext/libdatadog_api/library_config.c +54 -12
  24. data/ext/libdatadog_api/library_config.h +6 -0
  25. data/ext/libdatadog_api/macos_development.md +3 -3
  26. data/ext/libdatadog_api/process_discovery.c +2 -7
  27. data/ext/libdatadog_extconf_helpers.rb +2 -2
  28. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  29. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  30. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  31. data/lib/datadog/appsec/api_security.rb +23 -0
  32. data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
  33. data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
  34. data/lib/datadog/appsec/component.rb +30 -54
  35. data/lib/datadog/appsec/configuration/settings.rb +60 -2
  36. data/lib/datadog/appsec/context.rb +6 -6
  37. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  38. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
  39. data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
  40. data/lib/datadog/appsec/remote.rb +15 -55
  41. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  42. data/lib/datadog/appsec/security_engine/runner.rb +10 -11
  43. data/lib/datadog/appsec.rb +4 -7
  44. data/lib/datadog/core/buffer/random.rb +18 -2
  45. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  46. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -46
  47. data/lib/datadog/core/configuration/components.rb +31 -24
  48. data/lib/datadog/core/configuration/components_state.rb +23 -0
  49. data/lib/datadog/core/configuration/option.rb +27 -27
  50. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  51. data/lib/datadog/core/configuration/options.rb +1 -1
  52. data/lib/datadog/core/configuration/settings.rb +32 -20
  53. data/lib/datadog/core/configuration/stable_config.rb +1 -2
  54. data/lib/datadog/core/configuration.rb +16 -16
  55. data/lib/datadog/core/crashtracking/component.rb +2 -1
  56. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  57. data/lib/datadog/core/encoding.rb +1 -1
  58. data/lib/datadog/core/environment/cgroup.rb +10 -12
  59. data/lib/datadog/core/environment/container.rb +38 -40
  60. data/lib/datadog/core/environment/ext.rb +6 -6
  61. data/lib/datadog/core/environment/identity.rb +3 -3
  62. data/lib/datadog/core/environment/platform.rb +3 -3
  63. data/lib/datadog/core/error.rb +11 -9
  64. data/lib/datadog/core/logger.rb +2 -2
  65. data/lib/datadog/core/metrics/client.rb +12 -14
  66. data/lib/datadog/core/metrics/logging.rb +5 -5
  67. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  68. data/lib/datadog/core/process_discovery.rb +5 -1
  69. data/lib/datadog/core/rate_limiter.rb +4 -2
  70. data/lib/datadog/core/remote/client.rb +32 -31
  71. data/lib/datadog/core/remote/component.rb +3 -3
  72. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  73. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  74. data/lib/datadog/core/remote/configuration/repository.rb +12 -0
  75. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  76. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  77. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  78. data/lib/datadog/core/runtime/metrics.rb +3 -3
  79. data/lib/datadog/core/tag_builder.rb +56 -0
  80. data/lib/datadog/core/telemetry/component.rb +39 -24
  81. data/lib/datadog/core/telemetry/emitter.rb +7 -1
  82. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  83. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  84. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  85. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  86. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  87. data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
  88. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  89. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  90. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  91. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  92. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  93. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  94. data/lib/datadog/core/telemetry/event.rb +17 -475
  95. data/lib/datadog/core/telemetry/logger.rb +5 -4
  96. data/lib/datadog/core/telemetry/logging.rb +11 -5
  97. data/lib/datadog/core/telemetry/metric.rb +3 -3
  98. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -2
  99. data/lib/datadog/core/telemetry/transport/telemetry.rb +0 -1
  100. data/lib/datadog/core/telemetry/worker.rb +48 -27
  101. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  102. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  103. data/lib/datadog/core/transport/http/builder.rb +14 -14
  104. data/lib/datadog/core/transport/http/env.rb +8 -0
  105. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  106. data/lib/datadog/core/utils/duration.rb +32 -32
  107. data/lib/datadog/core/utils/forking.rb +2 -2
  108. data/lib/datadog/core/utils/network.rb +6 -6
  109. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  110. data/lib/datadog/core/utils/time.rb +10 -2
  111. data/lib/datadog/core/utils/truncation.rb +21 -0
  112. data/lib/datadog/core/utils.rb +7 -0
  113. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  114. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  115. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  116. data/lib/datadog/core/worker.rb +1 -1
  117. data/lib/datadog/core/workers/async.rb +9 -10
  118. data/lib/datadog/di/instrumenter.rb +52 -2
  119. data/lib/datadog/di/probe_notification_builder.rb +31 -41
  120. data/lib/datadog/di/probe_notifier_worker.rb +9 -1
  121. data/lib/datadog/di/serializer.rb +6 -2
  122. data/lib/datadog/di/transport/http/input.rb +10 -0
  123. data/lib/datadog/di/transport/input.rb +10 -2
  124. data/lib/datadog/error_tracking/component.rb +2 -2
  125. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  126. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  127. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  128. data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
  129. data/lib/datadog/profiling/component.rb +7 -9
  130. data/lib/datadog/profiling/ext.rb +0 -13
  131. data/lib/datadog/profiling/flush.rb +1 -1
  132. data/lib/datadog/profiling/http_transport.rb +3 -8
  133. data/lib/datadog/profiling/profiler.rb +2 -0
  134. data/lib/datadog/profiling/scheduler.rb +10 -2
  135. data/lib/datadog/profiling/stack_recorder.rb +5 -5
  136. data/lib/datadog/profiling/tag_builder.rb +5 -41
  137. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  138. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  139. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  140. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  141. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  142. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  143. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  144. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  145. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  146. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  147. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  148. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  149. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  150. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  151. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  152. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  153. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  154. data/lib/datadog/tracing/contrib/support.rb +28 -0
  155. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  156. data/lib/datadog/tracing/sync_writer.rb +1 -1
  157. data/lib/datadog/tracing/trace_operation.rb +12 -4
  158. data/lib/datadog/tracing/tracer.rb +6 -2
  159. data/lib/datadog/version.rb +1 -1
  160. metadata +31 -12
  161. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
  162. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
  163. data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
  164. data/lib/datadog/appsec/processor.rb +0 -107
@@ -34,7 +34,7 @@ typedef struct {
34
34
 
35
35
  // The class of the object that we're tracking.
36
36
  // NOTE: This is optional and will be set to NULL if not set.
37
- char* class;
37
+ ddog_prof_ManagedStringId class;
38
38
 
39
39
  // The GC allocation gen in which we saw this object being allocated.
40
40
  //
@@ -59,7 +59,7 @@ typedef struct {
59
59
  } heap_recorder_iteration_data;
60
60
 
61
61
  // Initialize a new heap recorder.
62
- heap_recorder* heap_recorder_new(void);
62
+ heap_recorder* heap_recorder_new(ddog_prof_ManagedStringStorage string_storage);
63
63
 
64
64
  // Free a previously initialized heap recorder.
65
65
  void heap_recorder_free(heap_recorder *heap_recorder);
@@ -164,10 +164,6 @@ VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder);
164
164
 
165
165
  // v--- TEST-ONLY APIs ---v
166
166
 
167
- // Assert internal hashing logic is valid for the provided locations and its
168
- // corresponding internal representations in heap recorder.
169
- void heap_recorder_testonly_assert_hash_matches(ddog_prof_Slice_Location locations);
170
-
171
167
  // Returns a Ruby string with a representation of internal data helpful to
172
168
  // troubleshoot issues such as unexpected test failures.
173
169
  VALUE heap_recorder_testonly_debug(heap_recorder *heap_recorder);
@@ -177,3 +173,5 @@ VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VA
177
173
 
178
174
  // Used to ensure that a GC actually triggers an update of the objects
179
175
  void heap_recorder_testonly_reset_last_update(heap_recorder *heap_recorder);
176
+
177
+ void heap_recorder_testonly_benchmark_intern(heap_recorder *heap_recorder, ddog_CharSlice string, int times, bool use_all);
@@ -15,26 +15,22 @@ static VALUE error_symbol = Qnil; // :error in Ruby
15
15
  static VALUE library_version_string = Qnil;
16
16
 
17
17
  typedef struct {
18
- ddog_prof_Exporter *exporter;
19
- ddog_prof_Exporter_Request_BuildResult *build_result;
18
+ ddog_prof_ProfileExporter *exporter;
19
+ ddog_prof_Request_Result *build_result;
20
20
  ddog_CancellationToken *cancel_token;
21
- ddog_prof_Exporter_SendResult result;
21
+ ddog_prof_Result_HttpStatus result;
22
22
  bool send_ran;
23
23
  } call_exporter_without_gvl_arguments;
24
24
 
25
25
  static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
26
26
  static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
27
- static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
28
- static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
27
+ static ddog_prof_ProfileExporter_Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
28
+ static VALUE handle_exporter_failure(ddog_prof_ProfileExporter_Result exporter_result);
29
29
  static VALUE _native_do_export(
30
30
  VALUE self,
31
31
  VALUE exporter_configuration,
32
32
  VALUE upload_timeout_milliseconds,
33
- VALUE flush,
34
- VALUE start_timespec_seconds,
35
- VALUE start_timespec_nanoseconds,
36
- VALUE finish_timespec_seconds,
37
- VALUE finish_timespec_nanoseconds
33
+ VALUE flush
38
34
  );
39
35
  static void *call_exporter_without_gvl(void *call_args);
40
36
  static void interrupt_exporter_call(void *cancel_token);
@@ -43,7 +39,7 @@ void http_transport_init(VALUE profiling_module) {
43
39
  VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
44
40
 
45
41
  rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
46
- rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 7);
42
+ rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 3);
47
43
 
48
44
  ok_symbol = ID2SYM(rb_intern_const("ok"));
49
45
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -60,14 +56,14 @@ static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string) {
60
56
 
61
57
  static VALUE _native_validate_exporter(DDTRACE_UNUSED VALUE _self, VALUE exporter_configuration) {
62
58
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
63
- ddog_prof_Exporter_NewResult exporter_result = create_exporter(exporter_configuration, rb_ary_new());
59
+ ddog_prof_ProfileExporter_Result exporter_result = create_exporter(exporter_configuration, rb_ary_new());
64
60
 
65
61
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
66
62
  if (!NIL_P(failure_tuple)) return failure_tuple;
67
63
 
68
64
  // We don't actually need the exporter for now -- we just wanted to validate that we could create it with the
69
65
  // settings we were given
70
- ddog_prof_Exporter_drop(exporter_result.ok);
66
+ ddog_prof_Exporter_drop(&exporter_result.ok);
71
67
 
72
68
  return rb_ary_new_from_args(2, ok_symbol, Qnil);
73
69
  }
@@ -93,7 +89,7 @@ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
93
89
  }
94
90
  }
95
91
 
96
- static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
92
+ static ddog_prof_ProfileExporter_Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
97
93
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
98
94
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
99
95
 
@@ -107,7 +103,7 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
107
103
  ddog_CharSlice library_version = char_slice_from_ruby_string(library_version_string);
108
104
  ddog_CharSlice profiling_family = DDOG_CHARSLICE_C("ruby");
109
105
 
110
- ddog_prof_Exporter_NewResult exporter_result =
106
+ ddog_prof_ProfileExporter_Result exporter_result =
111
107
  ddog_prof_Exporter_new(library_name, library_version, profiling_family, &tags, endpoint);
112
108
 
113
109
  ddog_Vec_Tag_drop(tags);
@@ -115,8 +111,12 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
115
111
  return exporter_result;
116
112
  }
117
113
 
118
- static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result) {
119
- return exporter_result.tag == DDOG_PROF_EXPORTER_NEW_RESULT_OK ?
114
+ static void validate_token(ddog_CancellationToken token, const char *file, int line) {
115
+ if (token.inner == NULL) rb_raise(rb_eRuntimeError, "Unexpected: Validation token was empty at %s:%d", file, line);
116
+ }
117
+
118
+ static VALUE handle_exporter_failure(ddog_prof_ProfileExporter_Result exporter_result) {
119
+ return exporter_result.tag == DDOG_PROF_PROFILE_EXPORTER_RESULT_OK_HANDLE_PROFILE_EXPORTER ?
120
120
  Qnil :
121
121
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&exporter_result.err));
122
122
  }
@@ -124,38 +124,37 @@ static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_resul
124
124
  // Note: This function handles a bunch of libdatadog dynamically-allocated objects, so it MUST not use any Ruby APIs
125
125
  // which can raise exceptions, otherwise the objects will be leaked.
126
126
  static VALUE perform_export(
127
- ddog_prof_Exporter *exporter,
128
- ddog_Timespec start,
129
- ddog_Timespec finish,
127
+ ddog_prof_ProfileExporter *exporter,
128
+ ddog_prof_EncodedProfile *profile,
130
129
  ddog_prof_Exporter_Slice_File files_to_compress_and_export,
131
- ddog_prof_Exporter_Slice_File files_to_export_unmodified,
132
130
  ddog_CharSlice internal_metadata,
133
131
  ddog_CharSlice info
134
132
  ) {
135
- ddog_prof_ProfiledEndpointsStats *endpoints_stats = NULL; // Not in use yet
136
- ddog_prof_Exporter_Request_BuildResult build_result = ddog_prof_Exporter_Request_build(
133
+ ddog_prof_Request_Result build_result = ddog_prof_Exporter_Request_build(
137
134
  exporter,
138
- start,
139
- finish,
135
+ profile,
140
136
  files_to_compress_and_export,
141
- files_to_export_unmodified,
137
+ /* files_to_export_unmodified: */ ddog_prof_Exporter_Slice_File_empty(),
142
138
  /* optional_additional_tags: */ NULL,
143
- endpoints_stats,
144
139
  &internal_metadata,
145
140
  &info
146
141
  );
147
142
 
148
- if (build_result.tag == DDOG_PROF_EXPORTER_REQUEST_BUILD_RESULT_ERR) {
143
+ if (build_result.tag == DDOG_PROF_REQUEST_RESULT_ERR_HANDLE_REQUEST) {
149
144
  ddog_prof_Exporter_drop(exporter);
150
145
  return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&build_result.err));
151
146
  }
152
147
 
153
- ddog_CancellationToken *cancel_token = ddog_CancellationToken_new();
148
+ ddog_CancellationToken cancel_token_request = ddog_CancellationToken_new();
149
+ ddog_CancellationToken cancel_token_interrupt = ddog_CancellationToken_clone(&cancel_token_request);
150
+
151
+ validate_token(cancel_token_request, __FILE__, __LINE__);
152
+ validate_token(cancel_token_interrupt, __FILE__, __LINE__);
154
153
 
155
154
  // We'll release the Global VM Lock while we're calling send, so that the Ruby VM can continue to work while this
156
155
  // is pending
157
156
  call_exporter_without_gvl_arguments args =
158
- {.exporter = exporter, .build_result = &build_result, .cancel_token = cancel_token, .send_ran = false};
157
+ {.exporter = exporter, .build_result = &build_result, .cancel_token = &cancel_token_request, .send_ran = false};
159
158
 
160
159
  // We use rb_thread_call_without_gvl2 instead of rb_thread_call_without_gvl as the gvl2 variant never raises any
161
160
  // exceptions.
@@ -172,14 +171,15 @@ static VALUE perform_export(
172
171
  int pending_exception = 0;
173
172
 
174
173
  while (!args.send_ran && !pending_exception) {
175
- rb_thread_call_without_gvl2(call_exporter_without_gvl, &args, interrupt_exporter_call, cancel_token);
174
+ rb_thread_call_without_gvl2(call_exporter_without_gvl, &args, interrupt_exporter_call, &cancel_token_interrupt);
176
175
 
177
176
  // To make sure we don't leak memory, we never check for pending exceptions if send ran
178
177
  if (!args.send_ran) pending_exception = check_if_pending_exception();
179
178
  }
180
179
 
181
180
  // Cleanup exporter and token, no longer needed
182
- ddog_CancellationToken_drop(cancel_token);
181
+ ddog_CancellationToken_drop(&cancel_token_request);
182
+ ddog_CancellationToken_drop(&cancel_token_interrupt);
183
183
  ddog_prof_Exporter_drop(exporter);
184
184
 
185
185
  if (pending_exception) {
@@ -192,10 +192,10 @@ static VALUE perform_export(
192
192
 
193
193
  // The request itself does not need to be freed as libdatadog takes ownership of it as part of sending.
194
194
 
195
- ddog_prof_Exporter_SendResult result = args.result;
195
+ ddog_prof_Result_HttpStatus result = args.result;
196
196
 
197
- return result.tag == DDOG_PROF_EXPORTER_SEND_RESULT_HTTP_RESPONSE ?
198
- rb_ary_new_from_args(2, ok_symbol, UINT2NUM(result.http_response.code)) :
197
+ return result.tag == DDOG_PROF_RESULT_HTTP_STATUS_OK_HTTP_STATUS ?
198
+ rb_ary_new_from_args(2, ok_symbol, UINT2NUM(result.ok.code)) :
199
199
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&result.err));
200
200
  }
201
201
 
@@ -203,11 +203,7 @@ static VALUE _native_do_export(
203
203
  DDTRACE_UNUSED VALUE _self,
204
204
  VALUE exporter_configuration,
205
205
  VALUE upload_timeout_milliseconds,
206
- VALUE flush,
207
- VALUE start_timespec_seconds,
208
- VALUE start_timespec_nanoseconds,
209
- VALUE finish_timespec_seconds,
210
- VALUE finish_timespec_nanoseconds
206
+ VALUE flush
211
207
  ) {
212
208
  VALUE encoded_profile = rb_funcall(flush, rb_intern("encoded_profile"), 0);
213
209
  VALUE code_provenance_file_name = rb_funcall(flush, rb_intern("code_provenance_file_name"), 0);
@@ -217,10 +213,6 @@ static VALUE _native_do_export(
217
213
  VALUE info_json = rb_funcall(flush, rb_intern("info_json"), 0);
218
214
 
219
215
  ENFORCE_TYPE(upload_timeout_milliseconds, T_FIXNUM);
220
- ENFORCE_TYPE(start_timespec_seconds, T_FIXNUM);
221
- ENFORCE_TYPE(start_timespec_nanoseconds, T_FIXNUM);
222
- ENFORCE_TYPE(finish_timespec_seconds, T_FIXNUM);
223
- ENFORCE_TYPE(finish_timespec_nanoseconds, T_FIXNUM);
224
216
  enforce_encoded_profile_instance(encoded_profile);
225
217
  ENFORCE_TYPE(code_provenance_file_name, T_STRING);
226
218
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
@@ -233,28 +225,9 @@ static VALUE _native_do_export(
233
225
 
234
226
  uint64_t timeout_milliseconds = NUM2ULONG(upload_timeout_milliseconds);
235
227
 
236
- ddog_Timespec start =
237
- {.seconds = NUM2LONG(start_timespec_seconds), .nanoseconds = NUM2UINT(start_timespec_nanoseconds)};
238
- ddog_Timespec finish =
239
- {.seconds = NUM2LONG(finish_timespec_seconds), .nanoseconds = NUM2UINT(finish_timespec_nanoseconds)};
240
-
241
228
  int to_compress_length = have_code_provenance ? 1 : 0;
242
229
  ddog_prof_Exporter_File to_compress[to_compress_length];
243
- int already_compressed_length = 1; // pprof
244
- ddog_prof_Exporter_File already_compressed[already_compressed_length];
245
-
246
230
  ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
247
- ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
248
-
249
- // TODO: Hardcoding the file name will go away with libdatadog 17
250
- VALUE pprof_file_name = rb_str_new_cstr("rubyprofile.pprof");
251
- VALUE pprof_data = rb_funcall(encoded_profile, rb_intern("_native_bytes"), 0);
252
- ENFORCE_TYPE(pprof_data, T_STRING);
253
-
254
- already_compressed[0] = (ddog_prof_Exporter_File) {
255
- .name = char_slice_from_ruby_string(pprof_file_name),
256
- .file = byte_slice_from_ruby_string(pprof_data),
257
- };
258
231
 
259
232
  if (have_code_provenance) {
260
233
  to_compress[0] = (ddog_prof_Exporter_File) {
@@ -266,27 +239,25 @@ static VALUE _native_do_export(
266
239
  ddog_CharSlice internal_metadata = char_slice_from_ruby_string(internal_metadata_json);
267
240
  ddog_CharSlice info = char_slice_from_ruby_string(info_json);
268
241
 
269
- ddog_prof_Exporter_NewResult exporter_result = create_exporter(exporter_configuration, tags_as_array);
242
+ ddog_prof_ProfileExporter_Result exporter_result = create_exporter(exporter_configuration, tags_as_array);
270
243
  // Note: Do not add anything that can raise exceptions after this line, as otherwise the exporter memory will leak
271
244
 
272
245
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
273
246
  if (!NIL_P(failure_tuple)) return failure_tuple;
274
247
 
275
- ddog_prof_MaybeError timeout_result = ddog_prof_Exporter_set_timeout(exporter_result.ok, timeout_milliseconds);
276
- if (timeout_result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
248
+ ddog_VoidResult timeout_result = ddog_prof_Exporter_set_timeout(&exporter_result.ok, timeout_milliseconds);
249
+ if (timeout_result.tag == DDOG_VOID_RESULT_ERR) {
277
250
  // NOTE: Seems a bit harsh to fail the upload if we can't set a timeout. OTOH, this is only expected to fail
278
251
  // if the exporter is not well built. Because such a situation should already be caught above I think it's
279
252
  // preferable to leave this here as a virtually unreachable exception rather than ignoring it.
280
- ddog_prof_Exporter_drop(exporter_result.ok);
281
- return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&timeout_result.some));
253
+ ddog_prof_Exporter_drop(&exporter_result.ok);
254
+ return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&timeout_result.err));
282
255
  }
283
256
 
284
257
  return perform_export(
285
- exporter_result.ok,
286
- start,
287
- finish,
258
+ &exporter_result.ok,
259
+ to_ddog_prof_EncodedProfile(encoded_profile),
288
260
  files_to_compress_and_export,
289
- files_to_export_unmodified,
290
261
  internal_metadata,
291
262
  info
292
263
  );
@@ -303,5 +274,7 @@ static void *call_exporter_without_gvl(void *call_args) {
303
274
 
304
275
  // Called by Ruby when it wants to interrupt call_exporter_without_gvl above, e.g. when the app wants to exit cleanly
305
276
  static void interrupt_exporter_call(void *cancel_token) {
277
+ // TODO: False here can mean two things: it was already cancelled OR it failed to cancel.
278
+ // Would be nice to change libdatadog to be able to distinguish between them...
306
279
  ddog_CancellationToken_cancel((ddog_CancellationToken *) cancel_token);
307
280
  }
@@ -60,3 +60,25 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
60
60
  ddog_Error_drop(error);
61
61
  return error_msg_size;
62
62
  }
63
+
64
+ ddog_prof_ManagedStringId intern_or_raise(ddog_prof_ManagedStringStorage string_storage, ddog_CharSlice string) {
65
+ if (string.len == 0) return (ddog_prof_ManagedStringId) { 0 }; // Id 0 is always an empty string, no need to ask
66
+
67
+ ddog_prof_ManagedStringStorageInternResult intern_result = ddog_prof_ManagedStringStorage_intern(string_storage, string);
68
+ if (intern_result.tag == DDOG_PROF_MANAGED_STRING_STORAGE_INTERN_RESULT_ERR) {
69
+ rb_raise(rb_eRuntimeError, "Failed to intern string: %"PRIsVALUE, get_error_details_and_drop(&intern_result.err));
70
+ }
71
+ return intern_result.ok;
72
+ }
73
+
74
+ void intern_all_or_raise(
75
+ ddog_prof_ManagedStringStorage string_storage,
76
+ ddog_prof_Slice_CharSlice strings,
77
+ ddog_prof_ManagedStringId *output_ids,
78
+ uintptr_t output_ids_size
79
+ ) {
80
+ ddog_prof_MaybeError result = ddog_prof_ManagedStringStorage_intern_all(string_storage, strings, output_ids, output_ids_size);
81
+ if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
82
+ rb_raise(rb_eRuntimeError, "Failed to intern_all: %"PRIsVALUE, get_error_details_and_drop(&result.some));
83
+ }
84
+ }
@@ -18,8 +18,11 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
18
18
  const char *ruby_value_type_to_string(enum ruby_value_type type);
19
19
  ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
20
20
 
21
- // Returns a dynamically allocated string from the provided char slice.
22
- // WARN: The returned string must be explicitly freed with ruby_xfree.
23
- static inline char* string_from_char_slice(ddog_CharSlice slice) {
24
- return ruby_strndup(slice.ptr, slice.len);
25
- }
21
+ ddog_prof_ManagedStringId intern_or_raise(ddog_prof_ManagedStringStorage string_storage, ddog_CharSlice string);
22
+
23
+ void intern_all_or_raise(
24
+ ddog_prof_ManagedStringStorage string_storage,
25
+ ddog_prof_Slice_CharSlice strings,
26
+ ddog_prof_ManagedStringId *output_ids,
27
+ uintptr_t output_ids_size
28
+ );
@@ -569,6 +569,7 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
569
569
 
570
570
  stack_buffer[i].as.native_frame.caching_cme = (VALUE)cme;
571
571
  stack_buffer[i].as.native_frame.method_id = cme->def->original_id;
572
+ stack_buffer[i].as.native_frame.function = cme->def->body.cfunc.func;
572
573
  stack_buffer[i].is_ruby_frame = false;
573
574
  i++;
574
575
  }
@@ -18,16 +18,19 @@ typedef struct {
18
18
  rb_nativethread_id_t owner;
19
19
  } current_gvl_owner;
20
20
 
21
+ // If a sample is kept around for later use, some of its fields need marking. Remember to
22
+ // update the marking code in `sampling_buffer_mark` if new fields are added.
21
23
  typedef struct {
22
24
  union {
23
25
  struct {
24
- VALUE iseq;
25
- void *caching_pc; // For caching only
26
+ VALUE iseq; // Needs marking if kept around
27
+ void *caching_pc; // For caching validation/invalidation only (does not need marking)
26
28
  int line;
27
29
  } ruby_frame;
28
30
  struct {
29
- VALUE caching_cme; // For caching only
31
+ VALUE caching_cme; // For caching validation/invalidation only (does not need marking)
30
32
  ID method_id;
33
+ void *function;
31
34
  } native_frame;
32
35
  } as;
33
36
  bool is_ruby_frame : 1;
@@ -103,16 +103,6 @@ void raise_syserr(
103
103
  }
104
104
  }
105
105
 
106
- char* ruby_strndup(const char *str, size_t size) {
107
- char *dup;
108
-
109
- dup = xmalloc(size + 1);
110
- memcpy(dup, str, size);
111
- dup[size] = '\0';
112
-
113
- return dup;
114
- }
115
-
116
106
  static VALUE _id2ref(VALUE obj_id) {
117
107
  // Call ::ObjectSpace._id2ref natively. It will raise if the id is no longer valid
118
108
  return rb_funcall(module_object_space, _id2ref_id, 1, obj_id);
@@ -122,9 +112,7 @@ static VALUE _id2ref_failure(DDTRACE_UNUSED VALUE _unused1, DDTRACE_UNUSED VALUE
122
112
  return Qfalse;
123
113
  }
124
114
 
125
- // Native wrapper to get an object ref from an id. Returns true on success and
126
- // writes the ref to the value pointer parameter if !NULL. False if id doesn't
127
- // reference a valid object (in which case value is not changed).
115
+ // See notes on header for important details
128
116
  bool ruby_ref_from_id(VALUE obj_id, VALUE *value) {
129
117
  // Call ::ObjectSpace._id2ref natively. It will raise if the id is no longer valid
130
118
  // so we need to call it via rb_rescue2
@@ -67,19 +67,11 @@ NORETURN(void raise_syserr(
67
67
  const char *function_name
68
68
  ));
69
69
 
70
- // Alternative to ruby_strdup that takes a size argument.
71
- // Similar to C's strndup but slightly less smart as size is expected to
72
- // be smaller or equal to the real size of str (minus null termination if it
73
- // exists).
74
- // A new string will be returned with size+1 bytes and last byte set to '\0'.
75
- // The returned string must be freed explicitly.
76
- //
77
- // WARN: Cannot be used during GC or outside the GVL.
78
- char* ruby_strndup(const char *str, size_t size);
79
-
80
70
  // Native wrapper to get an object ref from an id. Returns true on success and
81
71
  // writes the ref to the value pointer parameter if !NULL. False if id doesn't
82
72
  // reference a valid object (in which case value is not changed).
73
+ //
74
+ // Note: GVL can be released and other threads may get to run before this method returns
83
75
  bool ruby_ref_from_id(size_t id, VALUE *value);
84
76
 
85
77
  // Native wrapper to get the approximate/estimated current size of the passed