ddtrace 1.5.2 → 1.6.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 (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
@@ -7,7 +7,7 @@
7
7
  #include "libdatadog_helpers.h"
8
8
  #include "ruby_helpers.h"
9
9
 
10
- // Used to wrap a ddprof_ffi_Profile in a Ruby object and expose Ruby-level serialization APIs
10
+ // Used to wrap a ddog_Profile in a Ruby object and expose Ruby-level serialization APIs
11
11
  // This file implements the native bits of the Datadog::Profiling::StackRecorder class
12
12
 
13
13
  // ---
@@ -24,7 +24,7 @@
24
24
  // 2. The thread that serializes and reports profiles, let's call it the **serializer thread**. We enforce that there
25
25
  // cannot be more than one thread attempting to serialize profiles at a time.
26
26
  //
27
- // If both the sampler and serializer threads are trying to access the same `ddprof_ffi_Profile` in parallel, we will
27
+ // If both the sampler and serializer threads are trying to access the same `ddog_Profile` in parallel, we will
28
28
  // have a concurrency issue. Thus, the StackRecorder has an added mechanism to avoid this.
29
29
  //
30
30
  // As an additional constraint, the **sampler thread** has absolute priority and must never block while
@@ -32,7 +32,7 @@
32
32
  //
33
33
  // ### The solution: Keep two profiles at the same time
34
34
  //
35
- // To solve for the constraints above, the StackRecorder keeps two `ddprof_ffi_Profile` profile instances inside itself.
35
+ // To solve for the constraints above, the StackRecorder keeps two `ddog_Profile` profile instances inside itself.
36
36
  // They are called the `slot_one_profile` and `slot_two_profile`.
37
37
  //
38
38
  // Each profile is paired with its own mutex. `slot_one_profile` is protected by `slot_one_mutex` and `slot_two_profile`
@@ -135,10 +135,10 @@ static VALUE stack_recorder_class = Qnil;
135
135
  // Contains native state for each instance
136
136
  struct stack_recorder_state {
137
137
  pthread_mutex_t slot_one_mutex;
138
- ddprof_ffi_Profile *slot_one_profile;
138
+ ddog_Profile *slot_one_profile;
139
139
 
140
140
  pthread_mutex_t slot_two_mutex;
141
- ddprof_ffi_Profile *slot_two_profile;
141
+ ddog_Profile *slot_two_profile;
142
142
 
143
143
  short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
144
144
  };
@@ -146,7 +146,7 @@ struct stack_recorder_state {
146
146
  // Used to return a pair of values from sampler_lock_active_profile()
147
147
  struct active_slot_pair {
148
148
  pthread_mutex_t *mutex;
149
- ddprof_ffi_Profile *profile;
149
+ ddog_Profile *profile;
150
150
  };
151
151
 
152
152
  struct call_serialize_without_gvl_arguments {
@@ -154,8 +154,8 @@ struct call_serialize_without_gvl_arguments {
154
154
  struct stack_recorder_state *state;
155
155
 
156
156
  // Set by callee
157
- ddprof_ffi_Profile *profile;
158
- ddprof_ffi_SerializeResult result;
157
+ ddog_Profile *profile;
158
+ ddog_SerializeResult result;
159
159
 
160
160
  // Set by both
161
161
  bool serialize_ran;
@@ -164,15 +164,16 @@ struct call_serialize_without_gvl_arguments {
164
164
  static VALUE _native_new(VALUE klass);
165
165
  static void stack_recorder_typed_data_free(void *data);
166
166
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
167
- static VALUE ruby_time_from(ddprof_ffi_Timespec ddprof_time);
167
+ static VALUE ruby_time_from(ddog_Timespec ddprof_time);
168
168
  static void *call_serialize_without_gvl(void *call_args);
169
169
  static struct active_slot_pair sampler_lock_active_profile();
170
170
  static void sampler_unlock_active_profile(struct active_slot_pair active_slot);
171
- static ddprof_ffi_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
171
+ static ddog_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state, ddog_Timespec start_timestamp_for_next_profile);
172
172
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
173
173
  static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
174
174
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
175
175
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
176
+ static ddog_Timespec time_now();
176
177
 
177
178
  void stack_recorder_init(VALUE profiling_module) {
178
179
  stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
@@ -199,7 +200,7 @@ void stack_recorder_init(VALUE profiling_module) {
199
200
  ruby_time_from_id = rb_intern_const("ruby_time_from");
200
201
  }
201
202
 
202
- // This structure is used to define a Ruby object that stores a pointer to a ddprof_ffi_Profile instance
203
+ // This structure is used to define a Ruby object that stores a pointer to a ddog_Profile instance
203
204
  // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
204
205
  static const rb_data_type_t stack_recorder_typed_data = {
205
206
  .wrap_struct_name = "Datadog::Profiling::StackRecorder",
@@ -214,7 +215,7 @@ static const rb_data_type_t stack_recorder_typed_data = {
214
215
  static VALUE _native_new(VALUE klass) {
215
216
  struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
216
217
 
217
- ddprof_ffi_Slice_value_type sample_types = {.ptr = enabled_value_types, .len = ENABLED_VALUE_TYPES_COUNT};
218
+ ddog_Slice_value_type sample_types = {.ptr = enabled_value_types, .len = ENABLED_VALUE_TYPES_COUNT};
218
219
 
219
220
  state->slot_one_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
220
221
  state->slot_two_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
@@ -227,8 +228,8 @@ static VALUE _native_new(VALUE klass) {
227
228
 
228
229
  // Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
229
230
 
230
- state->slot_one_profile = ddprof_ffi_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
231
- state->slot_two_profile = ddprof_ffi_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
231
+ state->slot_one_profile = ddog_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
232
+ state->slot_two_profile = ddog_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
232
233
 
233
234
  return TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
234
235
  }
@@ -237,10 +238,10 @@ static void stack_recorder_typed_data_free(void *state_ptr) {
237
238
  struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
238
239
 
239
240
  pthread_mutex_destroy(&state->slot_one_mutex);
240
- ddprof_ffi_Profile_free(state->slot_one_profile);
241
+ ddog_Profile_free(state->slot_one_profile);
241
242
 
242
243
  pthread_mutex_destroy(&state->slot_two_mutex);
243
- ddprof_ffi_Profile_free(state->slot_two_profile);
244
+ ddog_Profile_free(state->slot_two_profile);
244
245
 
245
246
  ruby_xfree(state);
246
247
  }
@@ -267,33 +268,33 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
267
268
  rb_thread_call_without_gvl2(call_serialize_without_gvl, &args, NULL /* No interruption function needed in this case */, NULL /* Not needed */);
268
269
  }
269
270
 
270
- ddprof_ffi_SerializeResult serialized_profile = args.result;
271
+ ddog_SerializeResult serialized_profile = args.result;
271
272
 
272
- if (serialized_profile.tag == DDPROF_FFI_SERIALIZE_RESULT_ERR) {
273
+ if (serialized_profile.tag == DDOG_SERIALIZE_RESULT_ERR) {
273
274
  VALUE err_details = ruby_string_from_vec_u8(serialized_profile.err);
274
- ddprof_ffi_SerializeResult_drop(serialized_profile);
275
+ ddog_SerializeResult_drop(serialized_profile);
275
276
  return rb_ary_new_from_args(2, error_symbol, err_details);
276
277
  }
277
278
 
278
279
  VALUE encoded_pprof = ruby_string_from_vec_u8(serialized_profile.ok.buffer);
279
280
 
280
- ddprof_ffi_Timespec ddprof_start = serialized_profile.ok.start;
281
- ddprof_ffi_Timespec ddprof_finish = serialized_profile.ok.end;
281
+ ddog_Timespec ddprof_start = serialized_profile.ok.start;
282
+ ddog_Timespec ddprof_finish = serialized_profile.ok.end;
282
283
 
283
284
  // Clean up libdatadog object to avoid leaking in case ruby_time_from raises an exception
284
- ddprof_ffi_SerializeResult_drop(serialized_profile);
285
+ ddog_SerializeResult_drop(serialized_profile);
285
286
 
286
287
  VALUE start = ruby_time_from(ddprof_start);
287
288
  VALUE finish = ruby_time_from(ddprof_finish);
288
289
 
289
- if (!ddprof_ffi_Profile_reset(args.profile, NULL /* start_time is optional */ )) {
290
+ if (!ddog_Profile_reset(args.profile, NULL /* start_time is optional */ )) {
290
291
  return rb_ary_new_from_args(2, error_symbol, rb_str_new_cstr("Failed to reset profile"));
291
292
  }
292
293
 
293
294
  return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(3, start, finish, encoded_pprof));
294
295
  }
295
296
 
296
- static VALUE ruby_time_from(ddprof_ffi_Timespec ddprof_time) {
297
+ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
297
298
  #ifndef NO_RB_TIME_TIMESPEC_NEW // Modern Rubies
298
299
  const int utc = INT_MAX - 1; // From Ruby sources
299
300
  struct timespec time = {.tv_sec = ddprof_time.seconds, .tv_nsec = ddprof_time.nanoseconds};
@@ -303,13 +304,13 @@ static VALUE ruby_time_from(ddprof_ffi_Timespec ddprof_time) {
303
304
  #endif
304
305
  }
305
306
 
306
- void record_sample(VALUE recorder_instance, ddprof_ffi_Sample sample) {
307
+ void record_sample(VALUE recorder_instance, ddog_Sample sample) {
307
308
  struct stack_recorder_state *state;
308
309
  TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
309
310
 
310
311
  struct active_slot_pair active_slot = sampler_lock_active_profile(state);
311
312
 
312
- ddprof_ffi_Profile_add(active_slot.profile, sample);
313
+ ddog_Profile_add(active_slot.profile, sample);
313
314
 
314
315
  sampler_unlock_active_profile(active_slot);
315
316
  }
@@ -317,8 +318,10 @@ void record_sample(VALUE recorder_instance, ddprof_ffi_Sample sample) {
317
318
  static void *call_serialize_without_gvl(void *call_args) {
318
319
  struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
319
320
 
320
- args->profile = serializer_flip_active_and_inactive_slots(args->state);
321
- args->result = ddprof_ffi_Profile_serialize(args->profile, NULL /* end_time is optional */, NULL /* duration_nanos is optional */);
321
+ ddog_Timespec finish_timestamp = time_now();
322
+
323
+ args->profile = serializer_flip_active_and_inactive_slots(args->state, finish_timestamp);
324
+ args->result = ddog_Profile_serialize(args->profile, &finish_timestamp, NULL /* duration_nanos is optional */);
322
325
  args->serialize_ran = true;
323
326
 
324
327
  return NULL; // Unused
@@ -357,7 +360,7 @@ static void sampler_unlock_active_profile(struct active_slot_pair active_slot) {
357
360
  if (error != 0) rb_syserr_fail(error, "Unexpected failure in sampler_unlock_active_profile");
358
361
  }
359
362
 
360
- static ddprof_ffi_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
363
+ static ddog_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state, ddog_Timespec start_timestamp_for_next_profile) {
361
364
  int error;
362
365
  int previously_active_slot = state->active_slot;
363
366
 
@@ -368,6 +371,10 @@ static ddprof_ffi_Profile *serializer_flip_active_and_inactive_slots(struct stac
368
371
  pthread_mutex_t *previously_active = (previously_active_slot == 1) ? &state->slot_one_mutex : &state->slot_two_mutex;
369
372
  pthread_mutex_t *previously_inactive = (previously_active_slot == 1) ? &state->slot_two_mutex : &state->slot_one_mutex;
370
373
 
374
+ // Before making this profile active, we reset it so that it uses the correct timestamp for its start
375
+ ddog_Profile *previously_inactive_profile = (previously_active_slot == 1) ? state->slot_two_profile : state->slot_one_profile;
376
+ if (!ddog_Profile_reset(previously_inactive_profile, &start_timestamp_for_next_profile)) rb_raise(rb_eRuntimeError, "Failed to reset profile");
377
+
371
378
  // Release the lock, thus making this slot active
372
379
  error = pthread_mutex_unlock(previously_inactive);
373
380
  if (error) rb_syserr_fail(error, "Unexpected failure during serializer_flip_active_and_inactive_slots for previously_inactive");
@@ -420,3 +427,12 @@ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
420
427
  rb_syserr_fail(error, "Unexpected failure when checking mutex state");
421
428
  }
422
429
  }
430
+
431
+ // Note that this is using CLOCK_REALTIME (e.g. actual time since unix epoch) and not the CLOCK_MONOTONIC as we use in other parts of the codebase
432
+ static ddog_Timespec time_now() {
433
+ struct timespec current_time;
434
+
435
+ if (clock_gettime(CLOCK_REALTIME, &current_time) != 0) rb_sys_fail("Failed to read CLOCK_REALTIME");
436
+
437
+ return (ddog_Timespec) {.seconds = current_time.tv_sec, .nanoseconds = (uint32_t) current_time.tv_nsec};
438
+ }
@@ -1,16 +1,16 @@
1
1
  #pragma once
2
2
 
3
- #include <ddprof/ffi.h>
3
+ #include <datadog/profiling.h>
4
4
 
5
- // Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDPROF_FFI_CHARSLICE_C`.
5
+ // Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
6
6
  // `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
7
7
  // tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
8
- // `DDPROF_FFI_CHARSLICE_C` with the following error:
8
+ // `DDOG_CHARSLICE_C` with the following error:
9
9
  //
10
10
  // ```
11
11
  // compiling ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c
12
12
  // ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c:23:1: error: initializer element is not constant
13
- // static const ddprof_ffi_ValueType enabled_value_types[] = {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE};
13
+ // static const ddog_ValueType enabled_value_types[] = {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE};
14
14
  // ^
15
15
  // ```
16
16
  #define VALUE_STRING(string) {.ptr = "" string, .len = sizeof(string) - 1}
@@ -23,7 +23,7 @@
23
23
  #define HEAP_LIVE_SIZE_VALUE {.type_ = VALUE_STRING("heap-live-size"), .unit = VALUE_STRING("bytes")}
24
24
  #define HEAP_LIVE_SAMPLES_VALUE {.type_ = VALUE_STRING("heap-live-samples"), .unit = VALUE_STRING("count")}
25
25
 
26
- static const ddprof_ffi_ValueType enabled_value_types[] = {
26
+ static const ddog_ValueType enabled_value_types[] = {
27
27
  #define CPU_TIME_VALUE_POS 0
28
28
  CPU_TIME_VALUE,
29
29
  #define CPU_SAMPLES_VALUE_POS 1
@@ -32,7 +32,7 @@ static const ddprof_ffi_ValueType enabled_value_types[] = {
32
32
  WALL_TIME_VALUE
33
33
  };
34
34
 
35
- #define ENABLED_VALUE_TYPES_COUNT (sizeof(enabled_value_types) / sizeof(ddprof_ffi_ValueType))
35
+ #define ENABLED_VALUE_TYPES_COUNT (sizeof(enabled_value_types) / sizeof(ddog_ValueType))
36
36
 
37
- void record_sample(VALUE recorder_instance, ddprof_ffi_Sample sample);
37
+ void record_sample(VALUE recorder_instance, ddog_Sample sample);
38
38
  VALUE enforce_recorder_instance(VALUE object);
@@ -114,6 +114,10 @@ module Datadog
114
114
 
115
115
  # Ensure these tags reach the backend
116
116
  trace.keep!
117
+ trace.set_tag(
118
+ Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
119
+ Datadog::Tracing::Sampling::Ext::Decision::ASM
120
+ )
117
121
  end
118
122
  end
119
123
  end
@@ -51,6 +51,7 @@ module Datadog
51
51
  end
52
52
  end
53
53
 
54
+ # rubocop:disable Metrics/MethodLength
54
55
  def self.record_via_span(*events) # rubocop:disable Metrics/AbcSize
55
56
  events.group_by { |e| e[:trace] }.each do |trace, event_group|
56
57
  unless trace
@@ -59,6 +60,10 @@ module Datadog
59
60
  end
60
61
 
61
62
  trace.keep!
63
+ trace.set_tag(
64
+ Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
65
+ Datadog::Tracing::Sampling::Ext::Decision::ASM
66
+ )
62
67
 
63
68
  # prepare and gather tags to apply
64
69
  trace_tags = event_group.each_with_object({}) do |event, tags|
@@ -106,6 +111,7 @@ module Datadog
106
111
  end
107
112
  end
108
113
  end
114
+ # rubocop:enable Metrics/MethodLength
109
115
  end
110
116
  end
111
117
  end
@@ -181,7 +181,7 @@ module Datadog
181
181
 
182
182
  next unless response && !response.internal_error? && response.service_rates
183
183
 
184
- sampler.update(response.service_rates)
184
+ sampler.update(response.service_rates, decision: Tracing::Sampling::Ext::Decision::AGENT_RATE)
185
185
  end
186
186
  end
187
187
 
@@ -251,7 +251,9 @@ module Datadog
251
251
  recorder = Datadog::Profiling::StackRecorder.new
252
252
  collector = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
253
253
  recorder: recorder,
254
- max_frames: settings.profiling.advanced.max_frames
254
+ max_frames: settings.profiling.advanced.max_frames,
255
+ tracer: tracer,
256
+ gc_profiling_enabled: should_enable_gc_profiling?(settings)
255
257
  )
256
258
  else
257
259
  trace_identifiers_helper = Profiling::TraceIdentifiers::Helper.new(
@@ -320,18 +322,6 @@ module Datadog
320
322
 
321
323
  def build_profiler_transport(settings, agent_settings)
322
324
  settings.profiling.exporter.transport ||
323
- if settings.profiling.advanced.legacy_transport_enabled
324
- require_relative '../../profiling/transport/http'
325
-
326
- Datadog.logger.warn('Using legacy profiling transport. Do not use unless instructed to by support.')
327
-
328
- Profiling::Transport::HTTP.default(
329
- agent_settings: agent_settings,
330
- site: settings.site,
331
- api_key: settings.api_key,
332
- profiling_upload_timeout_seconds: settings.profiling.upload.timeout_seconds
333
- )
334
- end ||
335
325
  Profiling::HttpTransport.new(
336
326
  agent_settings: agent_settings,
337
327
  site: settings.site,
@@ -339,6 +329,22 @@ module Datadog
339
329
  upload_timeout_seconds: settings.profiling.upload.timeout_seconds,
340
330
  )
341
331
  end
332
+
333
+ def should_enable_gc_profiling?(settings)
334
+ return true if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3')
335
+
336
+ # See comments on the setting definition for more context on why it exists.
337
+ if settings.profiling.advanced.force_enable_gc_profiling
338
+ Datadog.logger.debug(
339
+ 'Profiling time/resources spent in Garbage Collection force enabled. Do not use Ractors in combination ' \
340
+ 'with this option as profiles will be incomplete.'
341
+ )
342
+
343
+ true
344
+ else
345
+ false
346
+ end
347
+ end
342
348
  end
343
349
 
344
350
  attr_reader \
@@ -234,11 +234,17 @@ module Datadog
234
234
  # categorization of stack traces.
235
235
  option :code_provenance_enabled, default: true
236
236
 
237
- # Use legacy transport code instead of HttpTransport. Temporarily added for migration to HttpTransport,
238
- # and will be removed soon. Do not use unless instructed to by support.
237
+ # No longer does anything, and will be removed on dd-trace-rb 2.0.
238
+ #
239
+ # This was added as a temporary support option in case of issues with the new `Profiling::HttpTransport` class
240
+ # but we're now confident it's working nicely so we've removed the old code path.
239
241
  option :legacy_transport_enabled do |o|
240
- o.default { env_to_bool('DD_PROFILING_LEGACY_TRANSPORT_ENABLED', false) }
241
- o.lazy
242
+ o.on_set do
243
+ Datadog.logger.warn(
244
+ 'The profiling.advanced.legacy_transport_enabled setting has been deprecated for removal and no ' \
245
+ 'longer does anything. Please remove it from your Datadog.configure block.'
246
+ )
247
+ end
242
248
  end
243
249
 
244
250
  # Forces enabling the new profiler. We do not yet recommend turning on this option.
@@ -250,6 +256,25 @@ module Datadog
250
256
  o.default { env_to_bool('DD_PROFILING_FORCE_ENABLE_NEW', false) }
251
257
  o.lazy
252
258
  end
259
+
260
+ # Forces enabling of profiling of time/resources spent in Garbage Collection.
261
+ #
262
+ # Note that setting this to "false" (or not setting it) will not prevent the feature from being
263
+ # being automatically enabled in the future.
264
+ #
265
+ # This toggle was added because, although this feature is safe and enabled by default on Ruby 2.x,
266
+ # on Ruby 3.x it can break in applications that make use of Ractors due to two Ruby VM bugs:
267
+ # https://bugs.ruby-lang.org/issues/19112 AND https://bugs.ruby-lang.org/issues/18464.
268
+ #
269
+ # If you use Ruby 3.x and your application does not use Ractors (or if your Ruby has been patched), the
270
+ # feature is fully safe to enable and this toggle can be used to do so.
271
+ #
272
+ # We expect that once the above issue is patched, we'll automatically re-enable the feature on fixed Ruby
273
+ # versions.
274
+ option :force_enable_gc_profiling do |o|
275
+ o.default { env_to_bool('DD_PROFILING_FORCE_ENABLE_GC', false) }
276
+ o.lazy
277
+ end
253
278
  end
254
279
 
255
280
  # @public_api
@@ -700,6 +725,19 @@ module Datadog
700
725
  o.lazy
701
726
  end
702
727
  end
728
+
729
+ # Maximum size for the `x-datadog-tags` distributed trace tags header.
730
+ #
731
+ # If the serialized size of distributed trace tags is larger than this value, it will
732
+ # not be parsed if incoming, nor exported if outgoing. An error message will be logged
733
+ # in this case.
734
+ #
735
+ # @default `DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH` environment variable, otherwise `512`
736
+ # @return [Integer]
737
+ option :x_datadog_tags_max_length do |o|
738
+ o.default { env_to_int(Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH, 512) }
739
+ o.lazy
740
+ end
703
741
  end
704
742
 
705
743
  # The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/).
@@ -106,10 +106,14 @@ module Datadog
106
106
  Datadog.configuration.version
107
107
  end
108
108
 
109
- # @return [String] target agent URL for trace flushing
109
+ # @return [String, nil] target agent URL for trace flushing
110
110
  def agent_url
111
111
  # Retrieve the effect agent URL, regardless of how it was configured
112
112
  transport = Tracing.send(:tracer).writer.transport
113
+
114
+ # return `nil` with IO transport
115
+ return unless transport.respond_to?(:client)
116
+
113
117
  adapter = transport.client.api.adapter
114
118
  adapter.url
115
119
  end
@@ -6,10 +6,13 @@ require 'zlib'
6
6
  module Datadog
7
7
  module Core
8
8
  module Utils
9
- # Common database-related utility functions.
9
+ # Compression/decompression utility functions.
10
+ #
11
+ # @deprecated This is no longer used by ddtrace and will be removed in 2.0.
10
12
  module Compression
11
13
  module_function
12
14
 
15
+ # @deprecated This is no longer used by ddtrace and will be removed in 2.0.
13
16
  def gzip(string, level: nil, strategy: nil)
14
17
  sio = StringIO.new
15
18
  sio.binmode
@@ -19,6 +22,7 @@ module Datadog
19
22
  sio.string
20
23
  end
21
24
 
25
+ # @deprecated This is no longer used by ddtrace and will be removed in 2.0.
22
26
  def gunzip(string, encoding = ::Encoding::ASCII_8BIT)
23
27
  sio = StringIO.new(string)
24
28
  gz = Zlib::GzipReader.new(sio, encoding: encoding)
data/lib/datadog/core.rb CHANGED
@@ -1,59 +1,5 @@
1
1
  # typed: strict
2
2
 
3
- # TODO: Move these requires to smaller modules.
4
- # Would be better to lazy load these; not
5
- # all of these components will be used in
6
- # every application.
7
- # require_relative 'core/buffer/cruby'
8
- # require_relative 'core/buffer/random'
9
- # require_relative 'core/buffer/thread_safe'
10
- # require_relative 'core/chunker'
11
- # require_relative 'core/configuration'
12
- # require_relative 'core/diagnostics/environment_logger'
13
- # require_relative 'core/diagnostics/ext'
14
- # require_relative 'core/diagnostics/health'
15
- # require_relative 'core/encoding'
16
- # require_relative 'core/environment/cgroup'
17
- # require_relative 'core/environment/class_count'
18
- # require_relative 'core/environment/container'
19
- # require_relative 'core/environment/ext'
20
- # require_relative 'core/environment/gc'
21
- # require_relative 'core/environment/identity'
22
- # require_relative 'core/environment/socket'
23
- # require_relative 'core/environment/thread_count'
24
- # require_relative 'core/environment/variable_helpers'
25
- # require_relative 'core/environment/vm_cache'
26
- # require_relative 'core/error'
27
- # require_relative 'core/event'
28
- # require_relative 'core/git/ext'
29
- # require_relative 'core/logger'
30
- # require_relative 'core/metrics/client'
31
- # require_relative 'core/metrics/ext'
32
- # require_relative 'core/metrics/helpers'
33
- # require_relative 'core/metrics/logging'
34
- # require_relative 'core/metrics/metric'
35
- # require_relative 'core/metrics/options'
36
- # require_relative 'core/pin'
37
- # require_relative 'core/quantization/hash'
38
- # require_relative 'core/quantization/http'
39
- # require_relative 'core/runtime/ext'
40
- # require_relative 'core/runtime/metrics'
41
- # require_relative 'core/utils'
42
- # require_relative 'core/utils/compression'
43
- # require_relative 'core/utils/database'
44
- # require_relative 'core/utils/forking'
45
- # require_relative 'core/utils/object_set'
46
- # require_relative 'core/utils/only_once'
47
- # require_relative 'core/utils/sequence'
48
- # require_relative 'core/utils/string_table'
49
- # require_relative 'core/utils/time'
50
- # require_relative 'core/worker'
51
- # require_relative 'core/workers/async'
52
- # require_relative 'core/workers/interval_loop'
53
- # require_relative 'core/workers/polling'
54
- # require_relative 'core/workers/queue'
55
- # require_relative 'core/workers/runtime_metrics'
56
-
57
3
  require_relative 'core/extensions'
58
4
 
59
5
  # We must load core extensions to make certain global APIs
@@ -11,8 +11,9 @@ module Datadog
11
11
  #
12
12
  # Methods prefixed with _native_ are implemented in `collectors_cpu_and_wall_time.c`
13
13
  class CpuAndWallTime
14
- def initialize(recorder:, max_frames:)
15
- self.class._native_initialize(self, recorder, max_frames)
14
+ def initialize(recorder:, max_frames:, tracer:)
15
+ tracer_context_key = safely_extract_context_key_from(tracer)
16
+ self.class._native_initialize(self, recorder, max_frames, tracer_context_key)
16
17
  end
17
18
 
18
19
  def inspect
@@ -21,6 +22,15 @@ module Datadog
21
22
  result[-1] = "#{self.class._native_inspect(self)}>"
22
23
  result
23
24
  end
25
+
26
+ private
27
+
28
+ def safely_extract_context_key_from(tracer)
29
+ tracer &&
30
+ tracer.respond_to?(:provider) &&
31
+ # NOTE: instance_variable_get always works, even on nil -- it just returns nil if the variable doesn't exist
32
+ tracer.provider.instance_variable_get(:@context).instance_variable_get(:@key)
33
+ end
24
34
  end
25
35
  end
26
36
  end
@@ -18,9 +18,11 @@ module Datadog
18
18
  def initialize(
19
19
  recorder:,
20
20
  max_frames:,
21
- cpu_and_wall_time_collector: CpuAndWallTime.new(recorder: recorder, max_frames: max_frames)
21
+ tracer:,
22
+ gc_profiling_enabled:,
23
+ cpu_and_wall_time_collector: CpuAndWallTime.new(recorder: recorder, max_frames: max_frames, tracer: tracer)
22
24
  )
23
- self.class._native_initialize(self, cpu_and_wall_time_collector)
25
+ self.class._native_initialize(self, cpu_and_wall_time_collector, gc_profiling_enabled)
24
26
  @worker_thread = nil
25
27
  @failure_exception = nil
26
28
  @start_stop_mutex = Mutex.new
@@ -28,7 +30,7 @@ module Datadog
28
30
 
29
31
  def start
30
32
  @start_stop_mutex.synchronize do
31
- return if @worker_thread
33
+ return if @worker_thread && @worker_thread.alive?
32
34
 
33
35
  Datadog.logger.debug { "Starting thread for: #{self}" }
34
36
  @worker_thread = Thread.new do
@@ -1,7 +1,6 @@
1
1
  # typed: true
2
2
 
3
3
  require_relative 'ext'
4
- require_relative '../core/utils/compression'
5
4
  require_relative 'tag_builder'
6
5
 
7
6
  module Datadog
@@ -60,10 +59,9 @@ module Datadog
60
59
  start: start,
61
60
  finish: finish,
62
61
  pprof_file_name: Datadog::Profiling::Ext::Transport::HTTP::PPROF_DEFAULT_FILENAME,
63
- pprof_data: Datadog::Core::Utils::Compression.gzip(uncompressed_pprof),
62
+ pprof_data: uncompressed_pprof.to_s,
64
63
  code_provenance_file_name: Datadog::Profiling::Ext::Transport::HTTP::CODE_PROVENANCE_FILENAME,
65
- code_provenance_data:
66
- (Datadog::Core::Utils::Compression.gzip(uncompressed_code_provenance) if uncompressed_code_provenance),
64
+ code_provenance_data: uncompressed_code_provenance,
67
65
  tags_as_array: Datadog::Profiling::TagBuilder.call(settings: Datadog.configuration).to_a,
68
66
  )
69
67
  end
@@ -58,7 +58,7 @@ module Datadog
58
58
  end
59
59
  end
60
60
 
61
- # Used to log soft failures in `ddprof_ffi_Vec_tag_push` (e.g. we still report the profile in these cases)
61
+ # Used to log soft failures in `ddog_Vec_tag_push` (e.g. we still report the profile in these cases)
62
62
  # Called from native code
63
63
  def self.log_failure_to_process_tag(failure_details)
64
64
  Datadog.logger.warn("Failed to add tag to profiling request: #{failure_details}")
@@ -21,6 +21,7 @@ module Datadog
21
21
  PROPAGATION_STYLE_B3_SINGLE_HEADER = 'B3 single header'.freeze
22
22
  ENV_PROPAGATION_STYLE_INJECT = 'DD_PROPAGATION_STYLE_INJECT'.freeze
23
23
  ENV_PROPAGATION_STYLE_EXTRACT = 'DD_PROPAGATION_STYLE_EXTRACT'.freeze
24
+ ENV_X_DATADOG_TAGS_MAX_LENGTH = 'DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH'.freeze
24
25
  end
25
26
 
26
27
  # @public_api
@@ -33,6 +33,8 @@ module Datadog
33
33
  span.name = Ext::SPAN_COMMAND
34
34
  span.resource = context.safely(:resource)
35
35
 
36
+ span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
37
+
36
38
  span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
37
39
  span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_COMMAND)
38
40
 
@@ -17,6 +17,7 @@ module Datadog
17
17
  TAG_COMMAND = 'memcached.command'.freeze
18
18
  TAG_COMPONENT = 'dalli'.freeze
19
19
  TAG_OPERATION_COMMAND = 'command'.freeze
20
+ TAG_SYSTEM = 'memcached'.freeze
20
21
  end
21
22
  end
22
23
  end
@@ -3,6 +3,7 @@
3
3
  require_relative '../../metadata/ext'
4
4
  require_relative '../analytics'
5
5
  require_relative 'ext'
6
+ require_relative '../ext'
6
7
  require_relative 'quantize'
7
8
 
8
9
  module Datadog
@@ -37,6 +38,9 @@ module Datadog
37
38
 
38
39
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, hostname)
39
40
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port)
41
+
42
+ span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)
43
+
40
44
  cmd = Quantize.format_command(op, args)
41
45
  span.set_tag(Ext::TAG_COMMAND, cmd)
42
46