ddtrace 1.20.0 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -1
  3. data/LICENSE-3rdparty.csv +1 -1
  4. data/bin/ddprofrb +15 -0
  5. data/bin/ddtracerb +3 -1
  6. data/ext/{ddtrace_profiling_loader/ddtrace_profiling_loader.c → datadog_profiling_loader/datadog_profiling_loader.c} +2 -2
  7. data/ext/{ddtrace_profiling_loader → datadog_profiling_loader}/extconf.rb +3 -3
  8. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_cpu_and_wall_time_worker.c +238 -61
  9. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_discrete_dynamic_sampler.c +145 -72
  10. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_discrete_dynamic_sampler.h +17 -5
  11. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.c +97 -4
  12. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/extconf.rb +2 -2
  13. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.c +45 -3
  14. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.h +7 -1
  15. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/http_transport.c +15 -19
  16. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/native_extension_helpers.rb +4 -4
  17. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.c +14 -0
  18. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.h +4 -0
  19. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/profiling.c +1 -1
  20. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.c +10 -0
  21. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.h +2 -0
  22. data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.c +7 -9
  23. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -13
  24. data/lib/datadog/appsec/event.rb +1 -1
  25. data/lib/datadog/auto_instrument.rb +3 -0
  26. data/lib/datadog/core/configuration/components.rb +7 -6
  27. data/lib/datadog/core/configuration/option.rb +8 -6
  28. data/lib/datadog/core/configuration/settings.rb +130 -63
  29. data/lib/datadog/core/configuration.rb +20 -4
  30. data/lib/datadog/core/diagnostics/environment_logger.rb +4 -3
  31. data/lib/datadog/core/environment/git.rb +25 -0
  32. data/lib/datadog/core/environment/identity.rb +18 -48
  33. data/lib/datadog/core/environment/platform.rb +7 -1
  34. data/lib/datadog/core/git/ext.rb +2 -23
  35. data/lib/datadog/core/remote/client/capabilities.rb +1 -1
  36. data/lib/datadog/core/remote/negotiation.rb +2 -2
  37. data/lib/datadog/core/remote/transport/http/config.rb +1 -1
  38. data/lib/datadog/core/remote/worker.rb +7 -4
  39. data/lib/datadog/core/telemetry/client.rb +18 -10
  40. data/lib/datadog/core/telemetry/emitter.rb +9 -13
  41. data/lib/datadog/core/telemetry/event.rb +247 -57
  42. data/lib/datadog/core/telemetry/ext.rb +1 -0
  43. data/lib/datadog/core/telemetry/heartbeat.rb +1 -3
  44. data/lib/datadog/core/telemetry/http/ext.rb +4 -1
  45. data/lib/datadog/core/telemetry/http/transport.rb +9 -4
  46. data/lib/datadog/core/telemetry/request.rb +59 -0
  47. data/lib/datadog/core/transport/ext.rb +2 -0
  48. data/lib/datadog/core/utils/url.rb +25 -0
  49. data/lib/datadog/profiling/collectors/code_provenance.rb +10 -4
  50. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -0
  51. data/lib/datadog/profiling/collectors/info.rb +101 -0
  52. data/lib/datadog/profiling/component.rb +34 -28
  53. data/lib/datadog/profiling/exporter.rb +19 -5
  54. data/lib/datadog/profiling/ext.rb +2 -0
  55. data/lib/datadog/profiling/flush.rb +6 -3
  56. data/lib/datadog/profiling/http_transport.rb +5 -1
  57. data/lib/datadog/profiling/load_native_extension.rb +19 -6
  58. data/lib/datadog/profiling/native_extension.rb +1 -1
  59. data/lib/datadog/profiling/tag_builder.rb +5 -0
  60. data/lib/datadog/profiling/tasks/exec.rb +3 -3
  61. data/lib/datadog/profiling/tasks/help.rb +3 -3
  62. data/lib/datadog/profiling.rb +13 -2
  63. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +1 -1
  64. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +11 -4
  65. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +20 -0
  66. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +11 -1
  67. data/lib/datadog/tracing/contrib/configurable.rb +1 -1
  68. data/lib/datadog/tracing/contrib/extensions.rb +6 -2
  69. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +11 -4
  70. data/lib/datadog/tracing/sampling/matcher.rb +23 -3
  71. data/lib/datadog/tracing/sampling/rule.rb +7 -2
  72. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  73. data/lib/datadog/tracing/trace_operation.rb +1 -2
  74. data/lib/datadog/tracing/transport/http.rb +1 -0
  75. data/lib/datadog/tracing/transport/trace_formatter.rb +31 -0
  76. data/lib/ddtrace/version.rb +1 -1
  77. metadata +55 -62
  78. data/ext/ddtrace_profiling_native_extension/pid_controller.c +0 -57
  79. data/ext/ddtrace_profiling_native_extension/pid_controller.h +0 -45
  80. data/lib/datadog/core/telemetry/collector.rb +0 -250
  81. data/lib/datadog/core/telemetry/v1/app_event.rb +0 -59
  82. data/lib/datadog/core/telemetry/v1/application.rb +0 -92
  83. data/lib/datadog/core/telemetry/v1/configuration.rb +0 -25
  84. data/lib/datadog/core/telemetry/v1/dependency.rb +0 -43
  85. data/lib/datadog/core/telemetry/v1/host.rb +0 -59
  86. data/lib/datadog/core/telemetry/v1/install_signature.rb +0 -38
  87. data/lib/datadog/core/telemetry/v1/integration.rb +0 -64
  88. data/lib/datadog/core/telemetry/v1/product.rb +0 -36
  89. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +0 -106
  90. data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +0 -41
  91. data/lib/datadog/core/telemetry/v2/request.rb +0 -29
  92. data/lib/datadog/profiling/diagnostics/environment_logger.rb +0 -39
  93. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/NativeExtensionDesign.md +0 -0
  94. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id.h +0 -0
  95. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_from_pthread.c +0 -0
  96. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_noop.c +0 -0
  97. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.c +0 -0
  98. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.h +0 -0
  99. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_gc_profiling_helper.c +0 -0
  100. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_gc_profiling_helper.h +0 -0
  101. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.c +0 -0
  102. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.h +0 -0
  103. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.c +0 -0
  104. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.h +0 -0
  105. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.h +0 -0
  106. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/helpers.h +0 -0
  107. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.c +0 -0
  108. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.h +0 -0
  109. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.c +0 -0
  110. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.h +0 -0
  111. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.h +0 -0
  112. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.c +0 -0
  113. /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.h +0 -0
@@ -100,7 +100,7 @@ add_compiler_flag '-Wno-declaration-after-statement'
100
100
  add_compiler_flag '-Werror-implicit-function-declaration'
101
101
 
102
102
  # The native extension is not intended to expose any symbols/functions for other native libraries to use;
103
- # the sole exception being `Init_ddtrace_profiling_native_extension` which needs to be visible for Ruby to call it when
103
+ # the sole exception being `Init_datadog_profiling_native_extension` which needs to be visible for Ruby to call it when
104
104
  # it `dlopen`s the library.
105
105
  #
106
106
  # By setting this compiler flag, we tell it to assume that everything is private unless explicitly stated.
@@ -237,7 +237,7 @@ Logging.message("[ddtrace] After pkg-config $LDFLAGS were set to: #{$LDFLAGS.ins
237
237
  # This makes it easier for development (avoids "oops I forgot to rebuild when I switched my Ruby") and ensures that
238
238
  # the wrong library is never loaded.
239
239
  # When requiring, we need to use the exact same string, including the version and the platform.
240
- EXTENSION_NAME = "ddtrace_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}".freeze
240
+ EXTENSION_NAME = "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}".freeze
241
241
 
242
242
  if Datadog::Profiling::NativeExtensionHelpers::CAN_USE_MJIT_HEADER
243
243
  mjit_header_file_name = "rb_mjit_min_header-#{RUBY_VERSION}.h"
@@ -10,6 +10,13 @@
10
10
  #define CAN_APPLY_GC_FORCE_RECYCLE_BUG_WORKAROUND
11
11
  #endif
12
12
 
13
+ // Minimum age (in GC generations) of heap objects we want to include in heap
14
+ // recorder iterations. Object with age 0 represent objects that have yet to undergo
15
+ // a GC and, thus, may just be noise/trash at instant of iteration and are usually not
16
+ // relevant for heap profiles as the great majority should be trivially reclaimed
17
+ // during the next GC.
18
+ #define ITERATION_MIN_AGE 1
19
+
13
20
  // A compact representation of a stacktrace frame for a heap allocation.
14
21
  typedef struct {
15
22
  char *name;
@@ -137,6 +144,11 @@ struct heap_recorder {
137
144
  // mutation of the data so iteration can occur without acquiring a lock.
138
145
  // NOTE: Contrary to object_records, this table has no ownership of its data.
139
146
  st_table *object_records_snapshot;
147
+ // The GC gen/epoch/count in which we prepared the current iteration.
148
+ //
149
+ // This enables us to calculate the age of iterated objects in the above snapshot by
150
+ // comparing it against an object's alloc_gen.
151
+ size_t iteration_gen;
140
152
 
141
153
  // Data for a heap recording that was started but not yet ended
142
154
  recording active_recording;
@@ -353,6 +365,8 @@ void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
353
365
  return;
354
366
  }
355
367
 
368
+ heap_recorder->iteration_gen = rb_gc_count();
369
+
356
370
  if (heap_recorder->object_records_snapshot != NULL) {
357
371
  // we could trivially handle this but we raise to highlight and catch unexpected usages.
358
372
  rb_raise(rb_eRuntimeError, "New heap recorder iteration prepared without the previous one having been finished.");
@@ -459,6 +473,13 @@ static int st_object_record_entry_free(DDTRACE_UNUSED st_data_t key, st_data_t v
459
473
  return ST_DELETE;
460
474
  }
461
475
 
476
+ // Check to see if an object should not be included in a heap recorder iteration.
477
+ // This centralizes the checking logic to ensure it's equally applied between
478
+ // preparation and iteration codepaths.
479
+ static inline bool should_exclude_from_iteration(object_record *obj_record) {
480
+ return obj_record->object_data.gen_age < ITERATION_MIN_AGE;
481
+ }
482
+
462
483
  static int st_object_record_update(st_data_t key, st_data_t value, st_data_t extra_arg) {
463
484
  long obj_id = (long) key;
464
485
  object_record *record = (object_record*) value;
@@ -466,6 +487,19 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
466
487
 
467
488
  VALUE ref;
468
489
 
490
+ size_t iteration_gen = recorder->iteration_gen;
491
+ size_t alloc_gen = record->object_data.alloc_gen;
492
+ // Guard against potential overflows given unsigned types here.
493
+ record->object_data.gen_age = alloc_gen < iteration_gen ? iteration_gen - alloc_gen : 0;
494
+
495
+ if (should_exclude_from_iteration(record)) {
496
+ // If an object won't be included in the current iteration, there's
497
+ // no point checking for liveness or updating its size, so exit early.
498
+ // NOTE: This means that there should be an equivalent check during actual
499
+ // iteration otherwise we'd iterate/expose stale object data.
500
+ return ST_CONTINUE;
501
+ }
502
+
469
503
  if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) {
470
504
  // Id no longer associated with a valid ref. Need to delete this object record!
471
505
  on_committed_object_record_cleanup(recorder, record);
@@ -525,8 +559,16 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
525
559
  const heap_stack *stack = record->heap_record->stack;
526
560
  iteration_context *context = (iteration_context*) extra;
527
561
 
528
- ddog_prof_Location *locations = context->heap_recorder->reusable_locations;
562
+ const heap_recorder *recorder = context->heap_recorder;
563
+
564
+ if (should_exclude_from_iteration(record)) {
565
+ // Skip objects that should not be included in iteration
566
+ // NOTE: This matches the short-circuiting condition in st_object_record_update
567
+ // and prevents iteration over stale objects.
568
+ return ST_CONTINUE;
569
+ }
529
570
 
571
+ ddog_prof_Location *locations = recorder->reusable_locations;
530
572
  for (uint16_t i = 0; i < stack->frames_len; i++) {
531
573
  const heap_frame *frame = &stack->frames[i];
532
574
  ddog_prof_Location *location = &locations[i];
@@ -725,9 +767,9 @@ void object_record_free(object_record *record) {
725
767
 
726
768
  VALUE object_record_inspect(object_record *record) {
727
769
  heap_frame top_frame = record->heap_record->stack->frames[0];
728
- VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%s:%d alloc_gen=%zu ",
770
+ VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%s:%d alloc_gen=%zu gen_age=%zu ",
729
771
  record->obj_id, record->object_data.weight, record->object_data.size, top_frame.filename,
730
- (int) top_frame.line, record->object_data.alloc_gen);
772
+ (int) top_frame.line, record->object_data.alloc_gen, record->object_data.gen_age);
731
773
 
732
774
  const char *class = record->object_data.class;
733
775
  if (class != NULL) {
@@ -27,7 +27,9 @@ typedef struct live_object_data {
27
27
  // could be seen as being representative of 50 objects.
28
28
  unsigned int weight;
29
29
 
30
- // Size of this object on last flush/update.
30
+ // Size of this object in memory.
31
+ // NOTE: This only gets updated during heap_recorder_prepare_iteration and only
32
+ // for those objects that meet the minimum iteration age requirements.
31
33
  size_t size;
32
34
 
33
35
  // The class of the object that we're tracking.
@@ -39,6 +41,10 @@ typedef struct live_object_data {
39
41
  // This enables us to calculate the age of this object in terms of GC executions.
40
42
  size_t alloc_gen;
41
43
 
44
+ // The age of this object in terms of GC generations.
45
+ // NOTE: This only gets updated during heap_recorder_prepare_iteration
46
+ size_t gen_age;
47
+
42
48
  // Whether this object was previously seen as being frozen. If this is the case,
43
49
  // we'll skip any further size updates since frozen objects are supposed to be
44
50
  // immutable.
@@ -30,7 +30,7 @@ inline static ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
30
30
  static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
31
31
  static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
32
32
  static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
33
- static ddog_Endpoint endpoint_from(VALUE exporter_configuration);
33
+ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);
34
34
  static ddog_Vec_Tag convert_tags(VALUE tags_as_array);
35
35
  static void safely_log_failure_to_process_tag(ddog_Vec_Tag tags, VALUE err_details);
36
36
  static VALUE _native_do_export(
@@ -46,17 +46,17 @@ static VALUE _native_do_export(
46
46
  VALUE code_provenance_file_name,
47
47
  VALUE code_provenance_data,
48
48
  VALUE tags_as_array,
49
- VALUE internal_metadata_json
49
+ VALUE internal_metadata_json,
50
+ VALUE info_json
50
51
  );
51
52
  static void *call_exporter_without_gvl(void *call_args);
52
53
  static void interrupt_exporter_call(void *cancel_token);
53
- static VALUE ddtrace_version(void);
54
54
 
55
55
  void http_transport_init(VALUE profiling_module) {
56
56
  VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
57
57
 
58
58
  rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
59
- rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 12);
59
+ rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 13);
60
60
 
61
61
  ok_symbol = ID2SYM(rb_intern_const("ok"));
62
62
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -94,7 +94,7 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
94
94
 
95
95
  // This needs to be called BEFORE convert_tags since it can raise an exception and thus cause the ddog_Vec_Tag
96
96
  // to be leaked.
97
- ddog_Endpoint endpoint = endpoint_from(exporter_configuration);
97
+ ddog_prof_Endpoint endpoint = endpoint_from(exporter_configuration);
98
98
 
99
99
  ddog_Vec_Tag tags = convert_tags(tags_as_array);
100
100
 
@@ -116,7 +116,7 @@ static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_resul
116
116
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&exporter_result.err));
117
117
  }
118
118
 
119
- static ddog_Endpoint endpoint_from(VALUE exporter_configuration) {
119
+ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
120
120
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
121
121
 
122
122
  ID working_mode = SYM2ID(rb_ary_entry(exporter_configuration, 0)); // SYM2ID verifies its input so we can do this safely
@@ -131,12 +131,12 @@ static ddog_Endpoint endpoint_from(VALUE exporter_configuration) {
131
131
  ENFORCE_TYPE(site, T_STRING);
132
132
  ENFORCE_TYPE(api_key, T_STRING);
133
133
 
134
- return ddog_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
134
+ return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
135
135
  } else { // agent_id
136
136
  VALUE base_url = rb_ary_entry(exporter_configuration, 1);
137
137
  ENFORCE_TYPE(base_url, T_STRING);
138
138
 
139
- return ddog_Endpoint_agent(char_slice_from_ruby_string(base_url));
139
+ return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
140
140
  }
141
141
  }
142
142
 
@@ -208,6 +208,7 @@ static VALUE perform_export(
208
208
  ddog_prof_Exporter_Slice_File files_to_export_unmodified,
209
209
  ddog_Vec_Tag *additional_tags,
210
210
  ddog_CharSlice internal_metadata,
211
+ ddog_CharSlice info,
211
212
  uint64_t timeout_milliseconds
212
213
  ) {
213
214
  ddog_prof_ProfiledEndpointsStats *endpoints_stats = NULL; // Not in use yet
@@ -220,6 +221,7 @@ static VALUE perform_export(
220
221
  additional_tags,
221
222
  endpoints_stats,
222
223
  &internal_metadata,
224
+ &info,
223
225
  timeout_milliseconds
224
226
  );
225
227
 
@@ -290,7 +292,8 @@ static VALUE _native_do_export(
290
292
  VALUE code_provenance_file_name,
291
293
  VALUE code_provenance_data,
292
294
  VALUE tags_as_array,
293
- VALUE internal_metadata_json
295
+ VALUE internal_metadata_json,
296
+ VALUE info_json
294
297
  ) {
295
298
  ENFORCE_TYPE(upload_timeout_milliseconds, T_FIXNUM);
296
299
  ENFORCE_TYPE(start_timespec_seconds, T_FIXNUM);
@@ -301,6 +304,7 @@ static VALUE _native_do_export(
301
304
  ENFORCE_TYPE(pprof_data, T_STRING);
302
305
  ENFORCE_TYPE(code_provenance_file_name, T_STRING);
303
306
  ENFORCE_TYPE(internal_metadata_json, T_STRING);
307
+ ENFORCE_TYPE(info_json, T_STRING);
304
308
 
305
309
  // Code provenance can be disabled and in that case will be set to nil
306
310
  bool have_code_provenance = !NIL_P(code_provenance_data);
@@ -335,6 +339,7 @@ static VALUE _native_do_export(
335
339
 
336
340
  ddog_Vec_Tag *null_additional_tags = NULL;
337
341
  ddog_CharSlice internal_metadata = char_slice_from_ruby_string(internal_metadata_json);
342
+ ddog_CharSlice info = char_slice_from_ruby_string(info_json);
338
343
 
339
344
  ddog_prof_Exporter_NewResult exporter_result = create_exporter(exporter_configuration, tags_as_array);
340
345
  // Note: Do not add anything that can raise exceptions after this line, as otherwise the exporter memory will leak
@@ -350,6 +355,7 @@ static VALUE _native_do_export(
350
355
  files_to_export_unmodified,
351
356
  null_additional_tags,
352
357
  internal_metadata,
358
+ info,
353
359
  timeout_milliseconds
354
360
  );
355
361
  }
@@ -367,13 +373,3 @@ static void *call_exporter_without_gvl(void *call_args) {
367
373
  static void interrupt_exporter_call(void *cancel_token) {
368
374
  ddog_CancellationToken_cancel((ddog_CancellationToken *) cancel_token);
369
375
  }
370
-
371
- static VALUE ddtrace_version(void) {
372
- VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("DDTrace"));
373
- ENFORCE_TYPE(ddtrace_module, T_MODULE);
374
- VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION"));
375
- ENFORCE_TYPE(version_module, T_MODULE);
376
- VALUE version_string = rb_const_get(version_module, rb_intern("STRING"));
377
- ENFORCE_TYPE(version_string, T_STRING);
378
- return version_string;
379
- }
@@ -15,7 +15,7 @@ module Datadog
15
15
  # The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on debase-ruby_core_source
16
16
  CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?('2.6', '2.7', '3.0.', '3.1.', '3.2.')
17
17
 
18
- LIBDATADOG_VERSION = '~> 5.0.0.1.0'
18
+ LIBDATADOG_VERSION = '~> 7.0.0.1.0'
19
19
 
20
20
  def self.fail_install_if_missing_extension?
21
21
  ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == 'true'
@@ -29,7 +29,7 @@ module Datadog
29
29
  # native extension), we need to add a "runpath" -- a list of folders to search for libdatadog.
30
30
  #
31
31
  # This runpath gets hardcoded at native library linking time. You can look at it using the `readelf` tool in
32
- # Linux: e.g. `readelf -d ddtrace_profiling_native_extension.2.7.3_x86_64-linux.so`.
32
+ # Linux: e.g. `readelf -d datadog_profiling_native_extension.2.7.3_x86_64-linux.so`.
33
33
  #
34
34
  # In older versions of ddtrace, we only set as runpath an absolute path to libdatadog.
35
35
  # (This gets set automatically by the call
@@ -305,8 +305,8 @@ module Datadog
305
305
  no_binaries_for_current_platform = explain_issue(
306
306
  'the `libdatadog` gem installed on your system is missing binaries for your',
307
307
  'platform variant.',
308
- "(Your platform: `#{Gem::Platform.local}`)",
309
- '(Available binaries: ',
308
+ "(Your platform: `#{Libdatadog.current_platform}`)",
309
+ '(Available binaries:',
310
310
  "`#{Libdatadog.available_binaries.join('`, `')}`)",
311
311
  suggested: CONTACT_SUPPORT,
312
312
  )
@@ -876,3 +876,17 @@ static inline int ddtrace_imemo_type(VALUE imemo) {
876
876
  return NULL;
877
877
  }
878
878
  #endif
879
+
880
+ // This is used to workaround a VM bug. See "handle_sampling_signal" in "collectors_cpu_and_wall_time_worker" for details.
881
+ #ifdef NO_POSTPONED_TRIGGER
882
+ void *objspace_ptr_for_gc_finalize_deferred_workaround(void) {
883
+ rb_vm_t *vm =
884
+ #ifndef NO_GET_VM // TODO: Inline GET_VM below once we drop support in dd-trace-rb 2.x for < Ruby 2.5
885
+ GET_VM();
886
+ #else
887
+ thread_struct_from_object(rb_thread_current())->vm;
888
+ #endif
889
+
890
+ return vm->objspace;
891
+ }
892
+ #endif
@@ -55,3 +55,7 @@ void self_test_mn_enabled(void);
55
55
 
56
56
  // Provides more specific information on what kind an imemo is
57
57
  const char *imemo_kind(VALUE imemo);
58
+
59
+ #ifdef NO_POSTPONED_TRIGGER
60
+ void *objspace_ptr_for_gc_finalize_deferred_workaround(void);
61
+ #endif
@@ -38,7 +38,7 @@ static VALUE _native_enforce_success(DDTRACE_UNUSED VALUE _self, VALUE syserr_er
38
38
  static void *trigger_enforce_success(void *trigger_args);
39
39
  static VALUE _native_malloc_stats(DDTRACE_UNUSED VALUE _self);
40
40
 
41
- void DDTRACE_EXPORT Init_ddtrace_profiling_native_extension(void) {
41
+ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
42
42
  VALUE datadog_module = rb_define_module("Datadog");
43
43
  VALUE profiling_module = rb_define_module_under(datadog_module, "Profiling");
44
44
  VALUE native_extension_module = rb_define_module_under(profiling_module, "NativeExtension");
@@ -255,3 +255,13 @@ VALUE ruby_safe_inspect(VALUE obj) {
255
255
  return rb_str_new_cstr("(Not inspectable)");
256
256
  }
257
257
  }
258
+
259
+ VALUE ddtrace_version(void) {
260
+ VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("DDTrace"));
261
+ ENFORCE_TYPE(ddtrace_module, T_MODULE);
262
+ VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION"));
263
+ ENFORCE_TYPE(version_module, T_MODULE);
264
+ VALUE version_string = rb_const_get(version_module, rb_intern("STRING"));
265
+ ENFORCE_TYPE(version_string, T_STRING);
266
+ return version_string;
267
+ }
@@ -115,3 +115,5 @@ size_t ruby_obj_memsize_of(VALUE obj);
115
115
  // return a string with the result of that call. Elsif the object responds to
116
116
  // 'to_s', return a string with the result of that call. Otherwise, return Qnil.
117
117
  VALUE ruby_safe_inspect(VALUE obj);
118
+
119
+ VALUE ddtrace_version(void);
@@ -196,7 +196,6 @@ struct call_serialize_without_gvl_arguments {
196
196
  // Set by caller
197
197
  struct stack_recorder_state *state;
198
198
  ddog_Timespec finish_timestamp;
199
- size_t gc_count_before_serialize;
200
199
 
201
200
  // Set by callee
202
201
  ddog_prof_Profile *profile;
@@ -489,7 +488,6 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
489
488
  struct call_serialize_without_gvl_arguments args = {
490
489
  .state = state,
491
490
  .finish_timestamp = finish_timestamp,
492
- .gc_count_before_serialize = rb_gc_count(),
493
491
  .serialize_ran = false
494
492
  };
495
493
 
@@ -613,8 +611,6 @@ typedef struct heap_recorder_iteration_context {
613
611
 
614
612
  bool error;
615
613
  char error_msg[MAX_LEN_HEAP_ITERATION_ERROR_MSG];
616
-
617
- size_t profile_gen;
618
614
  } heap_recorder_iteration_context;
619
615
 
620
616
  static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteration_data iteration_data, void *extra_arg) {
@@ -643,7 +639,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
643
639
  }
644
640
  labels[label_offset++] = (ddog_prof_Label) {
645
641
  .key = DDOG_CHARSLICE_C("gc gen age"),
646
- .num = context->profile_gen - object_data->alloc_gen,
642
+ .num = object_data->gen_age,
647
643
  };
648
644
 
649
645
  ddog_prof_Profile_Result result = ddog_prof_Profile_add(
@@ -670,13 +666,12 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
670
666
  return true;
671
667
  }
672
668
 
673
- static void build_heap_profile_without_gvl(struct stack_recorder_state *state, ddog_prof_Profile *profile, size_t gc_count_before_serialize) {
669
+ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, ddog_prof_Profile *profile) {
674
670
  heap_recorder_iteration_context iteration_context = {
675
671
  .state = state,
676
672
  .profile = profile,
677
673
  .error = false,
678
674
  .error_msg = {0},
679
- .profile_gen = gc_count_before_serialize,
680
675
  };
681
676
  bool iterated = heap_recorder_for_each_live_object(state->heap_recorder, add_heap_sample_to_active_profile_without_gvl, (void*) &iteration_context);
682
677
  // We wait until we're out of the iteration to grab the gvl and raise. This is important because during
@@ -698,7 +693,7 @@ static void *call_serialize_without_gvl(void *call_args) {
698
693
 
699
694
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
700
695
  // without needing to race with the active sampler
701
- build_heap_profile_without_gvl(args->state, args->profile, args->gc_count_before_serialize);
696
+ build_heap_profile_without_gvl(args->state, args->profile);
702
697
 
703
698
  // Note: The profile gets reset by the serialize call
704
699
  args->result = ddog_prof_Profile_serialize(args->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
@@ -918,10 +913,13 @@ static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recor
918
913
  #pragma GCC diagnostic push
919
914
  // rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
920
915
  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
916
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
921
917
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
922
918
  // It SHOULD NOT be used for other purposes.
923
919
  static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
924
- rb_gc_force_recycle(obj);
920
+ #ifdef HAVE_WORKING_RB_GC_FORCE_RECYCLE
921
+ rb_gc_force_recycle(obj);
922
+ #endif
925
923
  return Qnil;
926
924
  }
927
925
  #pragma GCC diagnostic pop
@@ -13,6 +13,18 @@ module Datadog
13
13
  module AppSec
14
14
  module Contrib
15
15
  module Rack
16
+ # Create an array of lowercased headers
17
+ WAF_VENDOR_HEADERS_TAGS = %w[
18
+ X-Amzn-Trace-Id
19
+ Cloudfront-Viewer-Ja3-Fingerprint
20
+ Cf-Ray
21
+ X-Cloud-Trace-Context
22
+ X-Appgw-Trace-id
23
+ X-SigSci-RequestID
24
+ X-SigSci-Tags
25
+ Akamai-User-Risk
26
+ ].map(&:downcase).freeze
27
+
16
28
  # Topmost Rack middleware for AppSec
17
29
  # This should be inserted just below Datadog::Tracing::Contrib::Rack::TraceMiddleware
18
30
  class RequestMiddleware
@@ -20,6 +32,7 @@ module Datadog
20
32
  @app = app
21
33
 
22
34
  @oneshot_tags_sent = false
35
+ @rack_headers = {}
23
36
  end
24
37
 
25
38
  # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
@@ -54,7 +67,8 @@ module Datadog
54
67
 
55
68
  gateway_request = Gateway::Request.new(env)
56
69
 
57
- add_appsec_tags(processor, scope, env)
70
+ add_appsec_tags(processor, scope)
71
+ add_request_tags(scope, env)
58
72
 
59
73
  request_return, request_response = catch(::Datadog::AppSec::Ext::INTERRUPT) do
60
74
  Instrumentation.gateway.push('rack.request', gateway_request) do
@@ -129,7 +143,7 @@ module Datadog
129
143
  Datadog::Tracing.active_span
130
144
  end
131
145
 
132
- def add_appsec_tags(processor, scope, env)
146
+ def add_appsec_tags(processor, scope)
133
147
  span = scope.service_entry_span
134
148
  trace = scope.trace
135
149
 
@@ -139,17 +153,6 @@ module Datadog
139
153
  span.set_tag('_dd.runtime_family', 'ruby')
140
154
  span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
141
155
 
142
- if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
143
- request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
144
-
145
- # always collect client ip, as this is part of AppSec provided functionality
146
- Datadog::Tracing::ClientIp.set_client_ip_tag!(
147
- span,
148
- headers: request_header_collection,
149
- remote_ip: env['REMOTE_ADDR']
150
- )
151
- end
152
-
153
156
  if processor.diagnostics
154
157
  diagnostics = processor.diagnostics
155
158
 
@@ -175,6 +178,29 @@ module Datadog
175
178
  end
176
179
  end
177
180
 
181
+ def add_request_tags(scope, env)
182
+ span = scope.service_entry_span
183
+
184
+ return unless span
185
+
186
+ # Always add WAF vendors headers
187
+ WAF_VENDOR_HEADERS_TAGS.each do |lowercase_header|
188
+ rack_header = to_rack_header(lowercase_header)
189
+ span.set_tag("http.request.headers.#{lowercase_header}", env[rack_header]) if env[rack_header]
190
+ end
191
+
192
+ if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
193
+ request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
194
+
195
+ # always collect client ip, as this is part of AppSec provided functionality
196
+ Datadog::Tracing::ClientIp.set_client_ip_tag!(
197
+ span,
198
+ headers: request_header_collection,
199
+ remote_ip: env['REMOTE_ADDR']
200
+ )
201
+ end
202
+ end
203
+
178
204
  def add_waf_runtime_tags(scope)
179
205
  span = scope.service_entry_span
180
206
  context = scope.processor_context
@@ -187,6 +213,10 @@ module Datadog
187
213
  span.set_tag('_dd.appsec.waf.duration', context.time_ns / 1000.0)
188
214
  span.set_tag('_dd.appsec.waf.duration_ext', context.time_ext_ns / 1000.0)
189
215
  end
216
+
217
+ def to_rack_header(header)
218
+ @rack_headers[header] ||= Datadog::Tracing::Contrib::Rack::Header.to_rack_header(header)
219
+ end
190
220
  end
191
221
  end
192
222
  end
@@ -138,7 +138,7 @@ module Datadog
138
138
  private
139
139
 
140
140
  def compressed_and_base64_encoded(value)
141
- Base64.encode64(gzip(value))
141
+ Base64.strict_encode64(gzip(value))
142
142
  rescue TypeError => e
143
143
  Datadog.logger.debug do
144
144
  "Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}"
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../ddtrace/auto_instrument'
@@ -62,7 +62,8 @@ module Datadog
62
62
 
63
63
  Telemetry::Client.new(
64
64
  enabled: enabled,
65
- heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds
65
+ heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
66
+ dependency_collection: settings.telemetry.dependency_collection
66
67
  )
67
68
  end
68
69
  end
@@ -81,6 +82,7 @@ module Datadog
81
82
 
82
83
  def initialize(settings)
83
84
  @logger = self.class.build_logger(settings)
85
+ @environment_logger_extra = {}
84
86
 
85
87
  # This agent_settings is intended for use within Core. If you require
86
88
  # agent_settings within a product outside of core you should extend
@@ -90,11 +92,13 @@ module Datadog
90
92
  @remote = Remote::Component.build(settings, agent_settings)
91
93
  @tracer = self.class.build_tracer(settings, logger: @logger)
92
94
 
93
- @profiler = Datadog::Profiling::Component.build_profiler_component(
95
+ @profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component(
94
96
  settings: settings,
95
97
  agent_settings: agent_settings,
96
98
  optional_tracer: @tracer,
97
99
  )
100
+ @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
101
+
98
102
  @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
99
103
  @health_metrics = self.class.build_health_metrics(settings)
100
104
  @telemetry = self.class.build_telemetry(settings, agent_settings, logger)
@@ -105,18 +109,15 @@ module Datadog
105
109
  def startup!(settings)
106
110
  if settings.profiling.enabled
107
111
  if profiler
108
- @logger.debug('Profiling started')
109
112
  profiler.start
110
113
  else
111
114
  # Display a warning for users who expected profiling to be enabled
112
115
  unsupported_reason = Profiling.unsupported_reason
113
116
  logger.warn("Profiling was requested but is not supported, profiling disabled: #{unsupported_reason}")
114
117
  end
115
- else
116
- @logger.debug('Profiling is disabled')
117
118
  end
118
119
 
119
- Core::Diagnostics::EnvironmentLogger.collect_and_log!
120
+ Core::Diagnostics::EnvironmentLogger.collect_and_log!(@environment_logger_extra)
120
121
  end
121
122
 
122
123
  # Shuts down all the components in use.
@@ -8,7 +8,13 @@ module Datadog
8
8
  # Represents an instance of an integration configuration option
9
9
  # @public_api
10
10
  class Option
11
- attr_reader :definition
11
+ # @!attribute [r] definition
12
+ # The definition object that matches this option.
13
+ # @return [Configuration::OptionDefinition]
14
+ # @!attribute [r] precedence_set
15
+ # When this option was last set, what was the value precedence used?
16
+ # @return [Precedence::Value]
17
+ attr_reader :definition, :precedence_set
12
18
 
13
19
  # Option setting precedence.
14
20
  module Precedence
@@ -264,7 +270,7 @@ module Datadog
264
270
  # when restoring a value from `@value_per_precedence`, and we are only running `definition.setter`
265
271
  # on the original value, not on a valud that has already been processed by `definition.setter`.
266
272
  @value_per_precedence[precedence] = value
267
- context_exec(v, old_value, &definition.after_set) if definition.after_set
273
+ context_exec(v, old_value, precedence, &definition.after_set) if definition.after_set
268
274
  end
269
275
  end
270
276
 
@@ -303,10 +309,6 @@ module Datadog
303
309
  ['true', '1'].include?(ENV.fetch('DD_EXPERIMENTAL_SKIP_CONFIGURATION_VALIDATION', '').strip)
304
310
  end
305
311
 
306
- # Used for testing
307
- attr_reader :precedence_set
308
- private :precedence_set
309
-
310
312
  # Anchor object that represents a value that is not set.
311
313
  # This is necessary because `nil` is a valid value to be set.
312
314
  UNSET = Object.new