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
@@ -22,13 +22,37 @@ struct sampling_buffer {
22
22
  VALUE *stack_buffer;
23
23
  int *lines_buffer;
24
24
  bool *is_ruby_frame;
25
- ddprof_ffi_Location *locations;
26
- ddprof_ffi_Line *lines;
25
+ ddog_Location *locations;
26
+ ddog_Line *lines;
27
27
  }; // Note: typedef'd in the header to sampling_buffer
28
28
 
29
- static VALUE _native_sample(VALUE self, VALUE thread, VALUE recorder_instance, VALUE metric_values_hash, VALUE labels_array, VALUE max_frames);
29
+ static VALUE _native_sample(
30
+ VALUE self,
31
+ VALUE thread,
32
+ VALUE recorder_instance,
33
+ VALUE metric_values_hash,
34
+ VALUE labels_array,
35
+ VALUE max_frames,
36
+ VALUE in_gc
37
+ );
30
38
  static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size);
31
- static void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
39
+ static void record_placeholder_stack_in_native_code(
40
+ sampling_buffer* buffer,
41
+ VALUE recorder_instance,
42
+ ddog_Slice_i64 metric_values,
43
+ ddog_Slice_label labels,
44
+ sampling_buffer *record_buffer,
45
+ int extra_frames_in_record_buffer
46
+ );
47
+ static void sample_thread_internal(
48
+ VALUE thread,
49
+ sampling_buffer* buffer,
50
+ VALUE recorder_instance,
51
+ ddog_Slice_i64 metric_values,
52
+ ddog_Slice_label labels,
53
+ sampling_buffer *record_buffer,
54
+ int extra_frames_in_record_buffer
55
+ );
32
56
 
33
57
  void collectors_stack_init(VALUE profiling_module) {
34
58
  VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
@@ -36,7 +60,7 @@ void collectors_stack_init(VALUE profiling_module) {
36
60
  // Hosts methods used for testing the native code using RSpec
37
61
  VALUE testing_module = rb_define_module_under(collectors_stack_class, "Testing");
38
62
 
39
- rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 5);
63
+ rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 6);
40
64
 
41
65
  missing_string = rb_str_new2("");
42
66
  rb_global_variable(&missing_string);
@@ -44,7 +68,15 @@ void collectors_stack_init(VALUE profiling_module) {
44
68
 
45
69
  // This method exists only to enable testing Datadog::Profiling::Collectors::Stack behavior using RSpec.
46
70
  // It SHOULD NOT be used for other purposes.
47
- static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE thread, VALUE recorder_instance, VALUE metric_values_hash, VALUE labels_array, VALUE max_frames) {
71
+ static VALUE _native_sample(
72
+ DDTRACE_UNUSED VALUE _self,
73
+ VALUE thread,
74
+ VALUE recorder_instance,
75
+ VALUE metric_values_hash,
76
+ VALUE labels_array,
77
+ VALUE max_frames,
78
+ VALUE in_gc
79
+ ) {
48
80
  ENFORCE_TYPE(metric_values_hash, T_HASH);
49
81
  ENFORCE_TYPE(labels_array, T_ARRAY);
50
82
 
@@ -64,12 +96,12 @@ static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE thread, VALUE reco
64
96
  }
65
97
 
66
98
  long labels_count = RARRAY_LEN(labels_array);
67
- ddprof_ffi_Label labels[labels_count];
99
+ ddog_Label labels[labels_count];
68
100
 
69
101
  for (int i = 0; i < labels_count; i++) {
70
102
  VALUE key_str_pair = rb_ary_entry(labels_array, i);
71
103
 
72
- labels[i] = (ddprof_ffi_Label) {
104
+ labels[i] = (ddog_Label) {
73
105
  .key = char_slice_from_ruby_string(rb_ary_entry(key_str_pair, 0)),
74
106
  .str = char_slice_from_ruby_string(rb_ary_entry(key_str_pair, 1))
75
107
  };
@@ -84,8 +116,9 @@ static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE thread, VALUE reco
84
116
  thread,
85
117
  buffer,
86
118
  recorder_instance,
87
- (ddprof_ffi_Slice_i64) {.ptr = metric_values, .len = ENABLED_VALUE_TYPES_COUNT},
88
- (ddprof_ffi_Slice_label) {.ptr = labels, .len = labels_count}
119
+ (ddog_Slice_i64) {.ptr = metric_values, .len = ENABLED_VALUE_TYPES_COUNT},
120
+ (ddog_Slice_label) {.ptr = labels, .len = labels_count},
121
+ RTEST(in_gc) ? SAMPLE_IN_GC : SAMPLE_REGULAR
89
122
  );
90
123
 
91
124
  sampling_buffer_free(buffer);
@@ -93,7 +126,78 @@ static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE thread, VALUE reco
93
126
  return Qtrue;
94
127
  }
95
128
 
96
- void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
129
+ void sample_thread(
130
+ VALUE thread,
131
+ sampling_buffer* buffer,
132
+ VALUE recorder_instance,
133
+ ddog_Slice_i64 metric_values,
134
+ ddog_Slice_label labels,
135
+ sample_type type
136
+ ) {
137
+ // Samples thread into recorder
138
+ if (type == SAMPLE_REGULAR) {
139
+ sampling_buffer *record_buffer = buffer;
140
+ int extra_frames_in_record_buffer = 0;
141
+ sample_thread_internal(thread, buffer, recorder_instance, metric_values, labels, record_buffer, extra_frames_in_record_buffer);
142
+ return;
143
+ }
144
+
145
+ // Samples thread into recorder, including as a top frame in the stack a frame named "Garbage Collection"
146
+ if (type == SAMPLE_IN_GC) {
147
+ buffer->lines[0] = (ddog_Line) {
148
+ .function = (ddog_Function) {
149
+ .name = DDOG_CHARSLICE_C(""),
150
+ .filename = DDOG_CHARSLICE_C("Garbage Collection")
151
+ },
152
+ .line = 0
153
+ };
154
+ // To avoid changing sample_thread_internal, we just prepare a new buffer struct that uses the same underlying storage as the
155
+ // original buffer, but has capacity one less, so that we can keep the above Garbage Collection frame untouched.
156
+ sampling_buffer thread_in_gc_buffer = (struct sampling_buffer) {
157
+ .max_frames = buffer->max_frames - 1,
158
+ .stack_buffer = buffer->stack_buffer + 1,
159
+ .lines_buffer = buffer->lines_buffer + 1,
160
+ .is_ruby_frame = buffer->is_ruby_frame + 1,
161
+ .locations = buffer->locations + 1,
162
+ .lines = buffer->lines + 1
163
+ };
164
+ sampling_buffer *record_buffer = buffer; // We pass in the original buffer as the record_buffer, but not as the regular buffer
165
+ int extra_frames_in_record_buffer = 1;
166
+ sample_thread_internal(thread, &thread_in_gc_buffer, recorder_instance, metric_values, labels, record_buffer, extra_frames_in_record_buffer);
167
+ return;
168
+ }
169
+
170
+ rb_raise(rb_eArgError, "Unexpected value for sample_type: %d", type);
171
+ }
172
+
173
+ // Idea: Should we release the global vm lock (GVL) after we get the data from `rb_profile_frames`? That way other Ruby threads
174
+ // could continue making progress while the sample was ingested into the profile.
175
+ //
176
+ // Other things to take into consideration if we go in that direction:
177
+ // * Is it safe to call `rb_profile_frame_...` methods on things from the `stack_buffer` without the GVL acquired?
178
+ // * We need to make `VALUE` references in the `stack_buffer` visible to the Ruby GC
179
+ // * Should we move this into a different thread entirely?
180
+ // * If we don't move it into a different thread, does releasing the GVL on a Ruby thread mean that we're introducing
181
+ // a new thread switch point where there previously was none?
182
+ //
183
+ // ---
184
+ //
185
+ // Why the weird extra record_buffer and extra_frames_in_record_buffer?
186
+ // The answer is: to support both sample_thread() and sample_thread_in_gc().
187
+ //
188
+ // For sample_thread(), buffer == record_buffer and extra_frames_in_record_buffer == 0, so it's a no-op.
189
+ // For sample_thread_in_gc(), the buffer is a special buffer that is the same as the record_buffer, but with every
190
+ // pointer shifted forward extra_frames_in_record_buffer elements, so that the caller can actually inject those extra
191
+ // frames, and this function doesn't have to care about it.
192
+ static void sample_thread_internal(
193
+ VALUE thread,
194
+ sampling_buffer* buffer,
195
+ VALUE recorder_instance,
196
+ ddog_Slice_i64 metric_values,
197
+ ddog_Slice_label labels,
198
+ sampling_buffer *record_buffer,
199
+ int extra_frames_in_record_buffer
200
+ ) {
97
201
  int captured_frames = ddtrace_rb_profile_frames(
98
202
  thread,
99
203
  0 /* stack starting depth */,
@@ -103,15 +207,17 @@ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instanc
103
207
  buffer->is_ruby_frame
104
208
  );
105
209
 
106
- // Idea: Should we release the global vm lock (GVL) after we get the data from `rb_profile_frames`? That way other Ruby threads
107
- // could continue making progress while the sample was ingested into the profile.
108
- //
109
- // Other things to take into consideration if we go in that direction:
110
- // * Is it safe to call `rb_profile_frame_...` methods on things from the `stack_buffer` without the GVL acquired?
111
- // * We need to make `VALUE` references in the `stack_buffer` visible to the Ruby GC
112
- // * Should we move this into a different thread entirely?
113
- // * If we don't move it into a different thread, does releasing the GVL on a Ruby thread mean that we're introducing
114
- // a new thread switch point where there previously was none?
210
+ if (captured_frames == PLACEHOLDER_STACK_IN_NATIVE_CODE) {
211
+ record_placeholder_stack_in_native_code(
212
+ buffer,
213
+ recorder_instance,
214
+ metric_values,
215
+ labels,
216
+ record_buffer,
217
+ extra_frames_in_record_buffer
218
+ );
219
+ return;
220
+ }
115
221
 
116
222
  // Ruby does not give us path and line number for methods implemented using native code.
117
223
  // The convention in Kernel#caller_locations is to instead use the path and line number of the first Ruby frame
@@ -121,11 +227,6 @@ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instanc
121
227
  VALUE last_ruby_frame = Qnil;
122
228
  int last_ruby_line = 0;
123
229
 
124
- if (captured_frames == PLACEHOLDER_STACK_IN_NATIVE_CODE) {
125
- record_placeholder_stack_in_native_code(recorder_instance, metric_values, labels);
126
- return;
127
- }
128
-
129
230
  for (int i = captured_frames - 1; i >= 0; i--) {
130
231
  VALUE name, filename;
131
232
  int line;
@@ -157,15 +258,13 @@ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instanc
157
258
  name = NIL_P(name) ? missing_string : name;
158
259
  filename = NIL_P(filename) ? missing_string : filename;
159
260
 
160
- buffer->lines[i] = (ddprof_ffi_Line) {
161
- .function = (ddprof_ffi_Function) {
261
+ buffer->lines[i] = (ddog_Line) {
262
+ .function = (ddog_Function) {
162
263
  .name = char_slice_from_ruby_string(name),
163
264
  .filename = char_slice_from_ruby_string(filename)
164
265
  },
165
266
  .line = line,
166
267
  };
167
-
168
- buffer->locations[i] = (ddprof_ffi_Location) {.lines = (ddprof_ffi_Slice_line) {.ptr = &buffer->lines[i], .len = 1}};
169
268
  }
170
269
 
171
270
  // Used below; since we want to stack-allocate this, we must do it here rather than in maybe_add_placeholder_frames_omitted
@@ -180,8 +279,8 @@ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instanc
180
279
 
181
280
  record_sample(
182
281
  recorder_instance,
183
- (ddprof_ffi_Sample) {
184
- .locations = (ddprof_ffi_Slice_location) {.ptr = buffer->locations, .len = captured_frames},
282
+ (ddog_Sample) {
283
+ .locations = (ddog_Slice_location) {.ptr = record_buffer->locations, .len = captured_frames + extra_frames_in_record_buffer},
185
284
  .values = metric_values,
186
285
  .labels = labels,
187
286
  }
@@ -201,10 +300,10 @@ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer*
201
300
 
202
301
  // Important note: `frames_omitted_message` MUST have a lifetime that is at least as long as the call to
203
302
  // `record_sample`. So be careful where it gets allocated. (We do have tests for this, at least!)
204
- buffer->lines[buffer->max_frames - 1] = (ddprof_ffi_Line) {
205
- .function = (ddprof_ffi_Function) {
206
- .name = DDPROF_FFI_CHARSLICE_C(""),
207
- .filename = ((ddprof_ffi_CharSlice) {.ptr = frames_omitted_message, .len = strlen(frames_omitted_message)})
303
+ buffer->lines[buffer->max_frames - 1] = (ddog_Line) {
304
+ .function = (ddog_Function) {
305
+ .name = DDOG_CHARSLICE_C(""),
306
+ .filename = ((ddog_CharSlice) {.ptr = frames_omitted_message, .len = strlen(frames_omitted_message)})
208
307
  },
209
308
  .line = 0,
210
309
  };
@@ -230,21 +329,26 @@ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer*
230
329
  //
231
330
  // To give customers visibility into these threads, rather than reporting an empty stack, we replace the empty stack
232
331
  // with one containing a placeholder frame, so that these threads are properly represented in the UX.
233
- static void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
234
- ddprof_ffi_Line placeholder_stack_in_native_code_line = {
235
- .function = (ddprof_ffi_Function) {
236
- .name = DDPROF_FFI_CHARSLICE_C(""),
237
- .filename = DDPROF_FFI_CHARSLICE_C("In native code")
332
+ static void record_placeholder_stack_in_native_code(
333
+ sampling_buffer* buffer,
334
+ VALUE recorder_instance,
335
+ ddog_Slice_i64 metric_values,
336
+ ddog_Slice_label labels,
337
+ sampling_buffer *record_buffer,
338
+ int extra_frames_in_record_buffer
339
+ ) {
340
+ buffer->lines[0] = (ddog_Line) {
341
+ .function = (ddog_Function) {
342
+ .name = DDOG_CHARSLICE_C(""),
343
+ .filename = DDOG_CHARSLICE_C("In native code")
238
344
  },
239
345
  .line = 0
240
346
  };
241
- ddprof_ffi_Location placeholder_stack_in_native_code_location =
242
- {.lines = (ddprof_ffi_Slice_line) {.ptr = &placeholder_stack_in_native_code_line, .len = 1}};
243
347
 
244
348
  record_sample(
245
349
  recorder_instance,
246
- (ddprof_ffi_Sample) {
247
- .locations = (ddprof_ffi_Slice_location) {.ptr = &placeholder_stack_in_native_code_location, .len = 1},
350
+ (ddog_Sample) {
351
+ .locations = (ddog_Slice_location) {.ptr = record_buffer->locations, .len = 1 + extra_frames_in_record_buffer},
248
352
  .values = metric_values,
249
353
  .labels = labels,
250
354
  }
@@ -263,8 +367,14 @@ sampling_buffer *sampling_buffer_new(unsigned int max_frames) {
263
367
  buffer->stack_buffer = ruby_xcalloc(max_frames, sizeof(VALUE));
264
368
  buffer->lines_buffer = ruby_xcalloc(max_frames, sizeof(int));
265
369
  buffer->is_ruby_frame = ruby_xcalloc(max_frames, sizeof(bool));
266
- buffer->locations = ruby_xcalloc(max_frames, sizeof(ddprof_ffi_Location));
267
- buffer->lines = ruby_xcalloc(max_frames, sizeof(ddprof_ffi_Line));
370
+ buffer->locations = ruby_xcalloc(max_frames, sizeof(ddog_Location));
371
+ buffer->lines = ruby_xcalloc(max_frames, sizeof(ddog_Line));
372
+
373
+ // Currently we have a 1-to-1 correspondence between lines and locations, so we just initialize the locations once
374
+ // here and then only mutate the contents of the lines.
375
+ for (unsigned int i = 0; i < max_frames; i++) {
376
+ buffer->locations[i] = (ddog_Location) {.lines = (ddog_Slice_line) {.ptr = &buffer->lines[i], .len = 1}};
377
+ }
268
378
 
269
379
  return buffer;
270
380
  }
@@ -1,9 +1,18 @@
1
1
  #pragma once
2
2
 
3
- #include <ddprof/ffi.h>
3
+ #include <datadog/profiling.h>
4
4
 
5
5
  typedef struct sampling_buffer sampling_buffer;
6
6
 
7
- void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
7
+ typedef enum { SAMPLE_REGULAR, SAMPLE_IN_GC } sample_type;
8
+
9
+ void sample_thread(
10
+ VALUE thread,
11
+ sampling_buffer* buffer,
12
+ VALUE recorder_instance,
13
+ ddog_Slice_i64 metric_values,
14
+ ddog_Slice_label labels,
15
+ sample_type type
16
+ );
8
17
  sampling_buffer *sampling_buffer_new(unsigned int max_frames);
9
18
  void sampling_buffer_free(sampling_buffer *buffer);
@@ -77,6 +77,10 @@ def add_compiler_flag(flag)
77
77
  end
78
78
  end
79
79
 
80
+ # Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
81
+ # But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
82
+ add_compiler_flag '-Werror' if ENV['CI'] == 'true'
83
+
80
84
  # Older gcc releases may not default to C99 and we need to ask for this. This is also used:
81
85
  # * by upstream Ruby -- search for gnu99 in the codebase
82
86
  # * by msgpack, another ddtrace dependency
@@ -122,9 +126,15 @@ end
122
126
  # On older Rubies, there was no struct rb_native_thread. See private_vm_api_acccess.c for details.
123
127
  $defs << '-DNO_RB_NATIVE_THREAD' if RUBY_VERSION < '3.2'
124
128
 
129
+ # On older Rubies, there was no tid member in the internal thread structure
130
+ $defs << '-DNO_THREAD_TID' if RUBY_VERSION < '3.1'
131
+
125
132
  # On older Rubies, we need to use a backported version of this function. See private_vm_api_access.h for details.
126
133
  $defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
127
134
 
135
+ # On older Rubies, there are no Ractors
136
+ $defs << '-DNO_RACTORS' if RUBY_VERSION < '3'
137
+
128
138
  # On older Rubies, we need to use rb_thread_t instead of rb_execution_context_t
129
139
  $defs << '-DUSE_THREAD_INSTEAD_OF_EXECUTION_CONTEXT' if RUBY_VERSION < '2.5'
130
140
 
@@ -152,7 +162,7 @@ end
152
162
  ENV['PKG_CONFIG_PATH'] = "#{ENV['PKG_CONFIG_PATH']}:#{Libdatadog.pkgconfig_folder}"
153
163
  Logging.message(" [ddtrace] PKG_CONFIG_PATH set to #{ENV['PKG_CONFIG_PATH'].inspect}\n")
154
164
 
155
- unless pkg_config('ddprof_ffi_with_rpath')
165
+ unless pkg_config('datadog_profiling_with_rpath')
156
166
  skip_building_extension!(
157
167
  if Datadog::Profiling::NativeExtensionHelpers::Supported.pkg_config_missing?
158
168
  Datadog::Profiling::NativeExtensionHelpers::Supported::PKG_CONFIG_IS_MISSING