ddtrace 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +9 -2
  4. data/ext/ddtrace_profiling_loader/extconf.rb +17 -0
  5. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +38 -2
  6. data/ext/ddtrace_profiling_native_extension/clock_id.h +1 -0
  7. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +1 -0
  8. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +517 -42
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +3 -0
  10. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +208 -30
  11. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +156 -46
  12. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +11 -2
  13. data/ext/ddtrace_profiling_native_extension/extconf.rb +11 -1
  14. data/ext/ddtrace_profiling_native_extension/http_transport.c +83 -64
  15. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +4 -4
  16. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +3 -2
  17. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +59 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  19. data/ext/ddtrace_profiling_native_extension/profiling.c +10 -0
  20. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +0 -1
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +4 -2
  22. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +45 -29
  23. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +7 -7
  24. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +4 -0
  25. data/lib/datadog/appsec/event.rb +6 -0
  26. data/lib/datadog/core/configuration/components.rb +20 -14
  27. data/lib/datadog/core/configuration/settings.rb +42 -4
  28. data/lib/datadog/core/diagnostics/environment_logger.rb +5 -1
  29. data/lib/datadog/core/utils/compression.rb +5 -1
  30. data/lib/datadog/core.rb +0 -54
  31. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +12 -2
  32. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +5 -3
  33. data/lib/datadog/profiling/exporter.rb +2 -4
  34. data/lib/datadog/profiling/http_transport.rb +1 -1
  35. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  36. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +2 -0
  37. data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
  38. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -0
  39. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +2 -0
  40. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -0
  41. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +2 -0
  42. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +2 -0
  43. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -0
  44. data/lib/datadog/tracing/contrib/ext.rb +6 -0
  45. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -0
  46. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +5 -0
  47. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +7 -1
  48. data/lib/datadog/tracing/contrib/grpc/ext.rb +2 -0
  49. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
  50. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +22 -0
  51. data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
  52. data/lib/datadog/tracing/contrib/hanami/integration.rb +44 -0
  53. data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
  54. data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
  55. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
  56. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
  57. data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -0
  58. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +2 -0
  59. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -0
  60. data/lib/datadog/tracing/contrib/mongodb/ext.rb +7 -0
  61. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -0
  62. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +12 -0
  63. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
  64. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -0
  65. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +12 -0
  66. data/lib/datadog/tracing/contrib/pg/ext.rb +2 -1
  67. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +34 -18
  68. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +43 -0
  69. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +32 -0
  70. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
  71. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +49 -0
  72. data/lib/datadog/tracing/contrib/rack/middlewares.rb +11 -5
  73. data/lib/datadog/tracing/contrib/redis/ext.rb +2 -0
  74. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +4 -2
  75. data/lib/datadog/tracing/contrib/redis/patcher.rb +41 -0
  76. data/lib/datadog/tracing/contrib/redis/tags.rb +5 -0
  77. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +2 -0
  78. data/lib/datadog/tracing/contrib/sinatra/env.rb +12 -23
  79. data/lib/datadog/tracing/contrib/sinatra/ext.rb +7 -3
  80. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +2 -2
  81. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +8 -80
  82. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +14 -9
  83. data/lib/datadog/tracing/contrib.rb +1 -0
  84. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
  85. data/lib/datadog/tracing/distributed/headers/datadog.rb +122 -30
  86. data/lib/datadog/tracing/distributed/headers/ext.rb +2 -0
  87. data/lib/datadog/tracing/flush.rb +1 -1
  88. data/lib/datadog/tracing/metadata/ext.rb +8 -0
  89. data/lib/datadog/tracing/propagation/http.rb +9 -1
  90. data/lib/datadog/tracing/sampling/ext.rb +31 -0
  91. data/lib/datadog/tracing/sampling/priority_sampler.rb +46 -4
  92. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +8 -9
  93. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +29 -5
  94. data/lib/datadog/tracing/sampling/rate_sampler.rb +10 -3
  95. data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -3
  96. data/lib/datadog/tracing/sampling/span/ext.rb +0 -4
  97. data/lib/datadog/tracing/sampling/span/rule.rb +1 -1
  98. data/lib/datadog/tracing/sampling/span/sampler.rb +14 -3
  99. data/lib/datadog/tracing/trace_digest.rb +3 -0
  100. data/lib/datadog/tracing/trace_operation.rb +10 -0
  101. data/lib/datadog/tracing/trace_segment.rb +6 -0
  102. data/lib/datadog/tracing/tracer.rb +3 -1
  103. data/lib/datadog/tracing/writer.rb +7 -0
  104. data/lib/ddtrace/transport/trace_formatter.rb +7 -0
  105. data/lib/ddtrace/transport/traces.rb +1 -1
  106. data/lib/ddtrace/version.rb +2 -2
  107. metadata +18 -14
  108. data/lib/datadog/profiling/old_ext.rb +0 -42
  109. data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
  110. data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
  111. data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
  112. data/lib/datadog/profiling/transport/http/api.rb +0 -45
  113. data/lib/datadog/profiling/transport/http/builder.rb +0 -30
  114. data/lib/datadog/profiling/transport/http/client.rb +0 -37
  115. data/lib/datadog/profiling/transport/http/response.rb +0 -21
  116. data/lib/datadog/profiling/transport/http.rb +0 -118
@@ -1,6 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/thread.h>
3
- #include <ddprof/ffi.h>
3
+ #include <datadog/profiling.h>
4
4
  #include "helpers.h"
5
5
  #include "libdatadog_helpers.h"
6
6
  #include "ruby_helpers.h"
@@ -17,22 +17,23 @@ static ID agent_id; // id of :agent in Ruby
17
17
  static ID log_failure_to_process_tag_id; // id of :log_failure_to_process_tag in Ruby
18
18
 
19
19
  static VALUE http_transport_class = Qnil;
20
+ static VALUE library_version_string = Qnil;
20
21
 
21
22
  struct call_exporter_without_gvl_arguments {
22
- ddprof_ffi_ProfileExporterV3 *exporter;
23
- ddprof_ffi_Request *request;
24
- ddprof_ffi_CancellationToken *cancel_token;
25
- ddprof_ffi_SendResult result;
23
+ ddog_ProfileExporter *exporter;
24
+ ddog_Request *request;
25
+ ddog_CancellationToken *cancel_token;
26
+ ddog_SendResult result;
26
27
  bool send_ran;
27
28
  };
28
29
 
29
- inline static ddprof_ffi_ByteSlice byte_slice_from_ruby_string(VALUE string);
30
+ inline static ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
30
31
  static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
31
- static ddprof_ffi_NewProfileExporterV3Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
32
- static VALUE handle_exporter_failure(ddprof_ffi_NewProfileExporterV3Result exporter_result);
33
- static ddprof_ffi_EndpointV3 endpoint_from(VALUE exporter_configuration);
34
- static ddprof_ffi_Vec_tag convert_tags(VALUE tags_as_array);
35
- static void safely_log_failure_to_process_tag(ddprof_ffi_Vec_tag tags, VALUE err_details);
32
+ static ddog_NewProfileExporterResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
33
+ static VALUE handle_exporter_failure(ddog_NewProfileExporterResult exporter_result);
34
+ static ddog_Endpoint endpoint_from(VALUE exporter_configuration);
35
+ static ddog_Vec_tag convert_tags(VALUE tags_as_array);
36
+ static void safely_log_failure_to_process_tag(ddog_Vec_tag tags, VALUE err_details);
36
37
  static VALUE _native_do_export(
37
38
  VALUE self,
38
39
  VALUE exporter_configuration,
@@ -49,6 +50,7 @@ static VALUE _native_do_export(
49
50
  );
50
51
  static void *call_exporter_without_gvl(void *call_args);
51
52
  static void interrupt_exporter_call(void *cancel_token);
53
+ static VALUE ddtrace_version(void);
52
54
 
53
55
  void http_transport_init(VALUE profiling_module) {
54
56
  http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
@@ -61,57 +63,64 @@ void http_transport_init(VALUE profiling_module) {
61
63
  agentless_id = rb_intern_const("agentless");
62
64
  agent_id = rb_intern_const("agent");
63
65
  log_failure_to_process_tag_id = rb_intern_const("log_failure_to_process_tag");
66
+
67
+ library_version_string = ddtrace_version();
68
+ rb_global_variable(&library_version_string);
64
69
  }
65
70
 
66
- inline static ddprof_ffi_ByteSlice byte_slice_from_ruby_string(VALUE string) {
71
+ inline static ddog_ByteSlice byte_slice_from_ruby_string(VALUE string) {
67
72
  ENFORCE_TYPE(string, T_STRING);
68
- ddprof_ffi_ByteSlice byte_slice = {.ptr = (uint8_t *) StringValuePtr(string), .len = RSTRING_LEN(string)};
73
+ ddog_ByteSlice byte_slice = {.ptr = (uint8_t *) StringValuePtr(string), .len = RSTRING_LEN(string)};
69
74
  return byte_slice;
70
75
  }
71
76
 
72
77
  static VALUE _native_validate_exporter(DDTRACE_UNUSED VALUE _self, VALUE exporter_configuration) {
73
78
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
74
- ddprof_ffi_NewProfileExporterV3Result exporter_result = create_exporter(exporter_configuration, rb_ary_new());
79
+ ddog_NewProfileExporterResult exporter_result = create_exporter(exporter_configuration, rb_ary_new());
75
80
 
76
81
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
77
82
  if (!NIL_P(failure_tuple)) return failure_tuple;
78
83
 
79
84
  // We don't actually need the exporter for now -- we just wanted to validate that we could create it with the
80
85
  // settings we were given
81
- ddprof_ffi_NewProfileExporterV3Result_drop(exporter_result);
86
+ ddog_NewProfileExporterResult_drop(exporter_result);
82
87
 
83
88
  return rb_ary_new_from_args(2, ok_symbol, Qnil);
84
89
  }
85
90
 
86
- static ddprof_ffi_NewProfileExporterV3Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
91
+ static ddog_NewProfileExporterResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
87
92
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
88
93
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
89
94
 
90
- // This needs to be called BEFORE convert_tags since it can raise an exception and thus cause the ddprof_ffi_Vec_tag
95
+ // This needs to be called BEFORE convert_tags since it can raise an exception and thus cause the ddog_Vec_tag
91
96
  // to be leaked.
92
- ddprof_ffi_EndpointV3 endpoint = endpoint_from(exporter_configuration);
97
+ ddog_Endpoint endpoint = endpoint_from(exporter_configuration);
98
+
99
+ ddog_Vec_tag tags = convert_tags(tags_as_array);
93
100
 
94
- ddprof_ffi_Vec_tag tags = convert_tags(tags_as_array);
101
+ ddog_CharSlice library_name = DDOG_CHARSLICE_C("dd-trace-rb");
102
+ ddog_CharSlice library_version = char_slice_from_ruby_string(library_version_string);
103
+ ddog_CharSlice profiling_family = DDOG_CHARSLICE_C("ruby");
95
104
 
96
- ddprof_ffi_NewProfileExporterV3Result exporter_result =
97
- ddprof_ffi_ProfileExporterV3_new(DDPROF_FFI_CHARSLICE_C("ruby"), &tags, endpoint);
105
+ ddog_NewProfileExporterResult exporter_result =
106
+ ddog_ProfileExporter_new(library_name, library_version, profiling_family, &tags, endpoint);
98
107
 
99
- ddprof_ffi_Vec_tag_drop(tags);
108
+ ddog_Vec_tag_drop(tags);
100
109
 
101
110
  return exporter_result;
102
111
  }
103
112
 
104
- static VALUE handle_exporter_failure(ddprof_ffi_NewProfileExporterV3Result exporter_result) {
105
- if (exporter_result.tag == DDPROF_FFI_NEW_PROFILE_EXPORTER_V3_RESULT_OK) return Qnil;
113
+ static VALUE handle_exporter_failure(ddog_NewProfileExporterResult exporter_result) {
114
+ if (exporter_result.tag == DDOG_NEW_PROFILE_EXPORTER_RESULT_OK) return Qnil;
106
115
 
107
116
  VALUE err_details = ruby_string_from_vec_u8(exporter_result.err);
108
117
 
109
- ddprof_ffi_NewProfileExporterV3Result_drop(exporter_result);
118
+ ddog_NewProfileExporterResult_drop(exporter_result);
110
119
 
111
120
  return rb_ary_new_from_args(2, error_symbol, err_details);
112
121
  }
113
122
 
114
- static ddprof_ffi_EndpointV3 endpoint_from(VALUE exporter_configuration) {
123
+ static ddog_Endpoint endpoint_from(VALUE exporter_configuration) {
115
124
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
116
125
 
117
126
  ID working_mode = SYM2ID(rb_ary_entry(exporter_configuration, 0)); // SYM2ID verifies its input so we can do this safely
@@ -126,27 +135,27 @@ static ddprof_ffi_EndpointV3 endpoint_from(VALUE exporter_configuration) {
126
135
  ENFORCE_TYPE(site, T_STRING);
127
136
  ENFORCE_TYPE(api_key, T_STRING);
128
137
 
129
- return ddprof_ffi_EndpointV3_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
138
+ return ddog_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
130
139
  } else { // agent_id
131
140
  VALUE base_url = rb_ary_entry(exporter_configuration, 1);
132
141
  ENFORCE_TYPE(base_url, T_STRING);
133
142
 
134
- return ddprof_ffi_EndpointV3_agent(char_slice_from_ruby_string(base_url));
143
+ return ddog_Endpoint_agent(char_slice_from_ruby_string(base_url));
135
144
  }
136
145
  }
137
146
 
138
147
  __attribute__((warn_unused_result))
139
- static ddprof_ffi_Vec_tag convert_tags(VALUE tags_as_array) {
148
+ static ddog_Vec_tag convert_tags(VALUE tags_as_array) {
140
149
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
141
150
 
142
151
  long tags_count = RARRAY_LEN(tags_as_array);
143
- ddprof_ffi_Vec_tag tags = ddprof_ffi_Vec_tag_new();
152
+ ddog_Vec_tag tags = ddog_Vec_tag_new();
144
153
 
145
154
  for (long i = 0; i < tags_count; i++) {
146
155
  VALUE name_value_pair = rb_ary_entry(tags_as_array, i);
147
156
 
148
157
  if (!RB_TYPE_P(name_value_pair, T_ARRAY)) {
149
- ddprof_ffi_Vec_tag_drop(tags);
158
+ ddog_Vec_tag_drop(tags);
150
159
  ENFORCE_TYPE(name_value_pair, T_ARRAY);
151
160
  }
152
161
 
@@ -155,23 +164,23 @@ static ddprof_ffi_Vec_tag convert_tags(VALUE tags_as_array) {
155
164
  VALUE tag_value = rb_ary_entry(name_value_pair, 1);
156
165
 
157
166
  if (!(RB_TYPE_P(tag_name, T_STRING) && RB_TYPE_P(tag_value, T_STRING))) {
158
- ddprof_ffi_Vec_tag_drop(tags);
167
+ ddog_Vec_tag_drop(tags);
159
168
  ENFORCE_TYPE(tag_name, T_STRING);
160
169
  ENFORCE_TYPE(tag_value, T_STRING);
161
170
  }
162
171
 
163
- ddprof_ffi_PushTagResult push_result =
164
- ddprof_ffi_Vec_tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));
172
+ ddog_PushTagResult push_result =
173
+ ddog_Vec_tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));
165
174
 
166
- if (push_result.tag == DDPROF_FFI_PUSH_TAG_RESULT_ERR) {
175
+ if (push_result.tag == DDOG_PUSH_TAG_RESULT_ERR) {
167
176
  VALUE err_details = ruby_string_from_vec_u8(push_result.err);
168
- ddprof_ffi_PushTagResult_drop(push_result);
177
+ ddog_PushTagResult_drop(push_result);
169
178
 
170
179
  // libdatadog validates tags and may catch invalid tags that ddtrace didn't actually catch.
171
180
  // We warn users about such tags, and then just ignore them.
172
181
  safely_log_failure_to_process_tag(tags, err_details);
173
182
  } else {
174
- ddprof_ffi_PushTagResult_drop(push_result);
183
+ ddog_PushTagResult_drop(push_result);
175
184
  }
176
185
  }
177
186
 
@@ -184,12 +193,12 @@ static VALUE log_failure_to_process_tag(VALUE err_details) {
184
193
 
185
194
  // Since we are calling into Ruby code, it may raise an exception. This method ensure that dynamically-allocated tags
186
195
  // get cleaned before propagating the exception.
187
- static void safely_log_failure_to_process_tag(ddprof_ffi_Vec_tag tags, VALUE err_details) {
196
+ static void safely_log_failure_to_process_tag(ddog_Vec_tag tags, VALUE err_details) {
188
197
  int exception_state;
189
198
  rb_protect(log_failure_to_process_tag, err_details, &exception_state);
190
199
 
191
200
  if (exception_state) { // An exception was raised
192
- ddprof_ffi_Vec_tag_drop(tags); // clean up
201
+ ddog_Vec_tag_drop(tags); // clean up
193
202
  rb_jump_tag(exception_state); // "Re-raise" exception
194
203
  }
195
204
  }
@@ -197,17 +206,17 @@ static void safely_log_failure_to_process_tag(ddprof_ffi_Vec_tag tags, VALUE err
197
206
  // Note: This function handles a bunch of libdatadog dynamically-allocated objects, so it MUST not use any Ruby APIs
198
207
  // which can raise exceptions, otherwise the objects will be leaked.
199
208
  static VALUE perform_export(
200
- ddprof_ffi_NewProfileExporterV3Result valid_exporter_result, // Must be called with a valid exporter result
201
- ddprof_ffi_Timespec start,
202
- ddprof_ffi_Timespec finish,
203
- ddprof_ffi_Slice_file slice_files,
204
- ddprof_ffi_Vec_tag *additional_tags,
209
+ ddog_NewProfileExporterResult valid_exporter_result, // Must be called with a valid exporter result
210
+ ddog_Timespec start,
211
+ ddog_Timespec finish,
212
+ ddog_Slice_file slice_files,
213
+ ddog_Vec_tag *additional_tags,
205
214
  uint64_t timeout_milliseconds
206
215
  ) {
207
- ddprof_ffi_ProfileExporterV3 *exporter = valid_exporter_result.ok;
208
- ddprof_ffi_CancellationToken *cancel_token = ddprof_ffi_CancellationToken_new();
209
- ddprof_ffi_Request *request =
210
- ddprof_ffi_ProfileExporterV3_build(exporter, start, finish, slice_files, additional_tags, timeout_milliseconds);
216
+ ddog_ProfileExporter *exporter = valid_exporter_result.ok;
217
+ ddog_CancellationToken *cancel_token = ddog_CancellationToken_new();
218
+ ddog_Request *request =
219
+ ddog_ProfileExporter_build(exporter, start, finish, slice_files, additional_tags, timeout_milliseconds);
211
220
 
212
221
  // We'll release the Global VM Lock while we're calling send, so that the Ruby VM can continue to work while this
213
222
  // is pending
@@ -236,24 +245,24 @@ static VALUE perform_export(
236
245
  }
237
246
 
238
247
  // Cleanup exporter and token, no longer needed
239
- ddprof_ffi_CancellationToken_drop(cancel_token);
240
- ddprof_ffi_NewProfileExporterV3Result_drop(valid_exporter_result);
248
+ ddog_CancellationToken_drop(cancel_token);
249
+ ddog_NewProfileExporterResult_drop(valid_exporter_result);
241
250
 
242
251
  if (pending_exception) {
243
252
  // If we got here send did not run, so we need to explicitly dispose of the request
244
- ddprof_ffi_Request_drop(request);
253
+ ddog_Request_drop(request);
245
254
 
246
255
  // Let Ruby propagate the exception. This will not return.
247
256
  rb_jump_tag(pending_exception);
248
257
  }
249
258
 
250
- ddprof_ffi_SendResult result = args.result;
251
- bool success = result.tag == DDPROF_FFI_SEND_RESULT_HTTP_RESPONSE;
259
+ ddog_SendResult result = args.result;
260
+ bool success = result.tag == DDOG_SEND_RESULT_HTTP_RESPONSE;
252
261
 
253
262
  VALUE ruby_status = success ? ok_symbol : error_symbol;
254
263
  VALUE ruby_result = success ? UINT2NUM(result.http_response.code) : ruby_string_from_vec_u8(result.err);
255
264
 
256
- ddprof_ffi_SendResult_drop(args.result);
265
+ ddog_SendResult_drop(args.result);
257
266
  // The request itself does not need to be freed as libdatadog takes care of it as part of sending.
258
267
 
259
268
  return rb_ary_new_from_args(2, ruby_status, ruby_result);
@@ -288,29 +297,29 @@ static VALUE _native_do_export(
288
297
 
289
298
  uint64_t timeout_milliseconds = NUM2ULONG(upload_timeout_milliseconds);
290
299
 
291
- ddprof_ffi_Timespec start =
300
+ ddog_Timespec start =
292
301
  {.seconds = NUM2LONG(start_timespec_seconds), .nanoseconds = NUM2UINT(start_timespec_nanoseconds)};
293
- ddprof_ffi_Timespec finish =
302
+ ddog_Timespec finish =
294
303
  {.seconds = NUM2LONG(finish_timespec_seconds), .nanoseconds = NUM2UINT(finish_timespec_nanoseconds)};
295
304
 
296
305
  int files_to_report = 1 + (have_code_provenance ? 1 : 0);
297
- ddprof_ffi_File files[files_to_report];
298
- ddprof_ffi_Slice_file slice_files = {.ptr = files, .len = files_to_report};
306
+ ddog_File files[files_to_report];
307
+ ddog_Slice_file slice_files = {.ptr = files, .len = files_to_report};
299
308
 
300
- files[0] = (ddprof_ffi_File) {
309
+ files[0] = (ddog_File) {
301
310
  .name = char_slice_from_ruby_string(pprof_file_name),
302
311
  .file = byte_slice_from_ruby_string(pprof_data)
303
312
  };
304
313
  if (have_code_provenance) {
305
- files[1] = (ddprof_ffi_File) {
314
+ files[1] = (ddog_File) {
306
315
  .name = char_slice_from_ruby_string(code_provenance_file_name),
307
316
  .file = byte_slice_from_ruby_string(code_provenance_data)
308
317
  };
309
318
  }
310
319
 
311
- ddprof_ffi_Vec_tag *null_additional_tags = NULL;
320
+ ddog_Vec_tag *null_additional_tags = NULL;
312
321
 
313
- ddprof_ffi_NewProfileExporterV3Result exporter_result = create_exporter(exporter_configuration, tags_as_array);
322
+ ddog_NewProfileExporterResult exporter_result = create_exporter(exporter_configuration, tags_as_array);
314
323
  // Note: Do not add anything that can raise exceptions after this line, as otherwise the exporter memory will leak
315
324
 
316
325
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
@@ -322,7 +331,7 @@ static VALUE _native_do_export(
322
331
  static void *call_exporter_without_gvl(void *call_args) {
323
332
  struct call_exporter_without_gvl_arguments *args = (struct call_exporter_without_gvl_arguments*) call_args;
324
333
 
325
- args->result = ddprof_ffi_ProfileExporterV3_send(args->exporter, args->request, args->cancel_token);
334
+ args->result = ddog_ProfileExporter_send(args->exporter, args->request, args->cancel_token);
326
335
  args->send_ran = true;
327
336
 
328
337
  return NULL; // Unused
@@ -330,5 +339,15 @@ static void *call_exporter_without_gvl(void *call_args) {
330
339
 
331
340
  // Called by Ruby when it wants to interrupt call_exporter_without_gvl above, e.g. when the app wants to exit cleanly
332
341
  static void interrupt_exporter_call(void *cancel_token) {
333
- ddprof_ffi_CancellationToken_cancel((ddprof_ffi_CancellationToken *) cancel_token);
342
+ ddog_CancellationToken_cancel((ddog_CancellationToken *) cancel_token);
343
+ }
344
+
345
+ static VALUE ddtrace_version(void) {
346
+ VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("DDTrace"));
347
+ ENFORCE_TYPE(ddtrace_module, T_MODULE);
348
+ VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION"));
349
+ ENFORCE_TYPE(version_module, T_MODULE);
350
+ VALUE version_string = rb_const_get(version_module, rb_intern("STRING"));
351
+ ENFORCE_TYPE(version_string, T_STRING);
352
+ return version_string;
334
353
  }
@@ -1,14 +1,14 @@
1
1
  #pragma once
2
2
 
3
- #include <ddprof/ffi.h>
3
+ #include <datadog/profiling.h>
4
4
  #include "ruby_helpers.h"
5
5
 
6
- inline static ddprof_ffi_CharSlice char_slice_from_ruby_string(VALUE string) {
6
+ inline static ddog_CharSlice char_slice_from_ruby_string(VALUE string) {
7
7
  ENFORCE_TYPE(string, T_STRING);
8
- ddprof_ffi_CharSlice char_slice = {.ptr = StringValuePtr(string), .len = RSTRING_LEN(string)};
8
+ ddog_CharSlice char_slice = {.ptr = StringValuePtr(string), .len = RSTRING_LEN(string)};
9
9
  return char_slice;
10
10
  }
11
11
 
12
- inline static VALUE ruby_string_from_vec_u8(ddprof_ffi_Vec_u8 string) {
12
+ inline static VALUE ruby_string_from_vec_u8(ddog_Vec_u8 string) {
13
13
  return rb_str_new((char *) string.ptr, string.len);
14
14
  }
@@ -31,8 +31,9 @@ module Datadog
31
31
  # This runpath gets hardcoded at native library linking time. You can look at it using the `readelf` tool in
32
32
  # Linux: e.g. `readelf -d ddtrace_profiling_native_extension.2.7.3_x86_64-linux.so`.
33
33
  #
34
- # In ddtrace 1.1.0, we only set as runpath an absolute path to libdatadog. (This gets set automatically by the call
35
- # to `pkg_config('ddprof_ffi_with_rpath')` in `extconf.rb`). This worked fine as long as libdatadog was **NOT**
34
+ # In older versions of ddtrace, we only set as runpath an absolute path to libdatadog.
35
+ # (This gets set automatically by the call
36
+ # to `pkg_config('datadog_profiling_with_rpath')` in `extconf.rb`). This worked fine as long as libdatadog was **NOT**
36
37
  # moved from the folder it was present at ddtrace installation/linking time.
37
38
  #
38
39
  # Unfortunately, environments such as Heroku and AWS Elastic Beanstalk move gems around in the filesystem after
@@ -49,6 +49,40 @@ rb_nativethread_id_t pthread_id_for(VALUE thread) {
49
49
  #endif
50
50
  }
51
51
 
52
+ // Taken from upstream vm_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
53
+ // Copyright (C) 2004-2007 Koichi Sasada
54
+ // to support tid_for (see below)
55
+ // Modifications: None
56
+ #if defined(__linux__) || defined(__FreeBSD__)
57
+ # define RB_THREAD_T_HAS_NATIVE_ID
58
+ #endif
59
+
60
+ uint64_t native_thread_id_for(VALUE thread) {
61
+ // The tid is only available on Ruby >= 3.1 + Linux (and FreeBSD). It's the same as `gettid()` aka the task id as seen in /proc
62
+ #if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
63
+ #ifndef NO_RB_NATIVE_THREAD
64
+ return thread_struct_from_object(thread)->nt->tid;
65
+ #else
66
+ return thread_struct_from_object(thread)->tid;
67
+ #endif
68
+ #else
69
+ rb_nativethread_id_t pthread_id = pthread_id_for(thread);
70
+
71
+ #ifdef __APPLE__
72
+ uint64_t result;
73
+ // On macOS, this gives us the same identifier that shows up in activity monitor
74
+ int error = pthread_threadid_np(pthread_id, &result);
75
+ if (error) rb_syserr_fail(error, "Unexpected failure in pthread_threadid_np");
76
+ return result;
77
+ #else
78
+ // Fallback, when we have nothing better (e.g. on Ruby < 3.1 on Linux)
79
+ // @ivoanjo: In the future we may want to explore some potential hacks to get the actual tid on linux
80
+ // (e.g. https://stackoverflow.com/questions/558469/how-do-i-get-a-thread-id-from-an-arbitrary-pthread-t )
81
+ return (uint64_t) pthread_id;
82
+ #endif
83
+ #endif
84
+ }
85
+
52
86
  // Returns the stack depth by using the same approach as rb_profile_frames and backtrace_each: get the positions
53
87
  // of the end and current frame pointers and subtracting them.
54
88
  ptrdiff_t stack_depth_for(VALUE thread) {
@@ -690,3 +724,28 @@ int ruby_thread_has_gvl_p(void) {
690
724
  return 0;
691
725
  }
692
726
  #endif // NO_THREAD_HAS_GVL
727
+
728
+ #ifndef NO_RACTORS
729
+ // This API and definition are exported as a public symbol by the VM BUT the function header is not defined in any public header, so we
730
+ // repeat it here to be able to use in our code.
731
+ bool rb_ractor_main_p_(void);
732
+ extern struct rb_ractor_struct *ruby_single_main_ractor;
733
+
734
+ // Taken from upstream ractor_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
735
+ // to allow us to ensure that we're always operating on the main ractor (if Ruby has ractors)
736
+ // Modifications:
737
+ // * None
738
+ bool ddtrace_rb_ractor_main_p(void)
739
+ {
740
+ if (ruby_single_main_ractor) {
741
+ return true;
742
+ }
743
+ else {
744
+ return rb_ractor_main_p_();
745
+ }
746
+ }
747
+ #else
748
+ // Simplify callers on older Rubies, instead of having them probe if the VM supports Ractors we just tell them that yes
749
+ // they're always on the main Ractor
750
+ bool ddtrace_rb_ractor_main_p(void) { return true; }
751
+ #endif // NO_RACTORS
@@ -12,12 +12,15 @@
12
12
  #include "extconf.h"
13
13
 
14
14
  rb_nativethread_id_t pthread_id_for(VALUE thread);
15
+ uint64_t native_thread_id_for(VALUE thread);
15
16
  ptrdiff_t stack_depth_for(VALUE thread);
16
17
  VALUE ddtrace_thread_list(void);
17
18
  bool is_thread_alive(VALUE thread);
18
19
  VALUE thread_name_for(VALUE thread);
19
20
 
20
21
  int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines, bool* is_ruby_frame);
22
+ // Returns true if the current thread belongs to the main Ractor or if Ruby has no Ractor support
23
+ bool ddtrace_rb_ractor_main_p(void);
21
24
 
22
25
  // Ruby 3.0 finally added support for showing CFUNC frames (frames for methods written using native code)
23
26
  // in stack traces gathered via `rb_profile_frames` (https://github.com/ruby/ruby/pull/3299).
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include "clock_id.h"
4
4
  #include "helpers.h"
5
+ #include "private_vm_api_access.h"
5
6
 
6
7
  // Each class/module here is implemented in their separate file
7
8
  void collectors_cpu_and_wall_time_init(VALUE profiling_module);
@@ -11,6 +12,7 @@ void http_transport_init(VALUE profiling_module);
11
12
  void stack_recorder_init(VALUE profiling_module);
12
13
 
13
14
  static VALUE native_working_p(VALUE self);
15
+ static VALUE _native_ddtrace_rb_ractor_main_p(DDTRACE_UNUSED VALUE _self);
14
16
 
15
17
  void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {
16
18
  VALUE datadog_module = rb_define_module("Datadog");
@@ -27,6 +29,10 @@ void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {
27
29
  collectors_stack_init(profiling_module);
28
30
  http_transport_init(profiling_module);
29
31
  stack_recorder_init(profiling_module);
32
+
33
+ // Hosts methods used for testing the native code using RSpec
34
+ VALUE testing_module = rb_define_module_under(native_extension_module, "Testing");
35
+ rb_define_singleton_method(testing_module, "_native_ddtrace_rb_ractor_main_p", _native_ddtrace_rb_ractor_main_p, 0);
30
36
  }
31
37
 
32
38
  static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
@@ -34,3 +40,7 @@ static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
34
40
 
35
41
  return Qtrue;
36
42
  }
43
+
44
+ static VALUE _native_ddtrace_rb_ractor_main_p(DDTRACE_UNUSED VALUE _self) {
45
+ return ddtrace_rb_ractor_main_p() ? Qtrue : Qfalse;
46
+ }
@@ -2,7 +2,6 @@
2
2
 
3
3
  void raise_unexpected_type(
4
4
  VALUE value,
5
- DDTRACE_UNUSED enum ruby_value_type _type,
6
5
  const char *value_name,
7
6
  const char *type_name,
8
7
  const char *file,
@@ -45,12 +45,14 @@ static inline int check_if_pending_exception(void) {
45
45
  // Ruby has a Check_Type(value, type) that is roughly equivalent to this BUT Ruby's version is rather cryptic when it fails
46
46
  // e.g. "wrong argument type nil (expected String)". This is a replacement that prints more information to help debugging.
47
47
  #define ENFORCE_TYPE(value, type) \
48
- { if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, type, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
48
+ { if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
49
+
50
+ #define ENFORCE_BOOLEAN(value) \
51
+ { if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
49
52
 
50
53
  // Called by ENFORCE_TYPE; should not be used directly
51
54
  NORETURN(void raise_unexpected_type(
52
55
  VALUE value,
53
- enum ruby_value_type type,
54
56
  const char *value_name,
55
57
  const char *type_name,
56
58
  const char *file,