ddtrace 1.20.0 → 1.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +115 -1
- data/LICENSE-3rdparty.csv +1 -1
- data/bin/ddprofrb +15 -0
- data/bin/ddtracerb +3 -1
- data/ext/{ddtrace_profiling_loader/ddtrace_profiling_loader.c → datadog_profiling_loader/datadog_profiling_loader.c} +2 -2
- data/ext/{ddtrace_profiling_loader → datadog_profiling_loader}/extconf.rb +3 -3
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_cpu_and_wall_time_worker.c +238 -61
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_discrete_dynamic_sampler.c +145 -72
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_discrete_dynamic_sampler.h +17 -5
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.c +97 -4
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/extconf.rb +2 -2
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.c +45 -3
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.h +7 -1
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/http_transport.c +15 -19
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/native_extension_helpers.rb +4 -4
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.c +14 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.h +4 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/profiling.c +1 -1
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.c +10 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.h +2 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.c +7 -9
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -13
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/components.rb +7 -6
- data/lib/datadog/core/configuration/option.rb +8 -6
- data/lib/datadog/core/configuration/settings.rb +130 -63
- data/lib/datadog/core/configuration.rb +20 -4
- data/lib/datadog/core/diagnostics/environment_logger.rb +4 -3
- data/lib/datadog/core/environment/git.rb +25 -0
- data/lib/datadog/core/environment/identity.rb +18 -48
- data/lib/datadog/core/environment/platform.rb +7 -1
- data/lib/datadog/core/git/ext.rb +2 -23
- data/lib/datadog/core/remote/client/capabilities.rb +1 -1
- data/lib/datadog/core/remote/negotiation.rb +2 -2
- data/lib/datadog/core/remote/transport/http/config.rb +1 -1
- data/lib/datadog/core/remote/worker.rb +7 -4
- data/lib/datadog/core/telemetry/client.rb +18 -10
- data/lib/datadog/core/telemetry/emitter.rb +9 -13
- data/lib/datadog/core/telemetry/event.rb +247 -57
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/heartbeat.rb +1 -3
- data/lib/datadog/core/telemetry/http/ext.rb +4 -1
- data/lib/datadog/core/telemetry/http/transport.rb +9 -4
- data/lib/datadog/core/telemetry/request.rb +59 -0
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/utils/url.rb +25 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +10 -4
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -0
- data/lib/datadog/profiling/collectors/info.rb +101 -0
- data/lib/datadog/profiling/component.rb +34 -28
- data/lib/datadog/profiling/exporter.rb +19 -5
- data/lib/datadog/profiling/ext.rb +2 -0
- data/lib/datadog/profiling/flush.rb +6 -3
- data/lib/datadog/profiling/http_transport.rb +5 -1
- data/lib/datadog/profiling/load_native_extension.rb +19 -6
- data/lib/datadog/profiling/native_extension.rb +1 -1
- data/lib/datadog/profiling/tag_builder.rb +5 -0
- data/lib/datadog/profiling/tasks/exec.rb +3 -3
- data/lib/datadog/profiling/tasks/help.rb +3 -3
- data/lib/datadog/profiling.rb +13 -2
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +11 -4
- data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +20 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +11 -1
- data/lib/datadog/tracing/contrib/configurable.rb +1 -1
- data/lib/datadog/tracing/contrib/extensions.rb +6 -2
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +11 -4
- data/lib/datadog/tracing/sampling/matcher.rb +23 -3
- data/lib/datadog/tracing/sampling/rule.rb +7 -2
- data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
- data/lib/datadog/tracing/trace_operation.rb +1 -2
- data/lib/datadog/tracing/transport/http.rb +1 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +31 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +55 -62
- data/ext/ddtrace_profiling_native_extension/pid_controller.c +0 -57
- data/ext/ddtrace_profiling_native_extension/pid_controller.h +0 -45
- data/lib/datadog/core/telemetry/collector.rb +0 -250
- data/lib/datadog/core/telemetry/v1/app_event.rb +0 -59
- data/lib/datadog/core/telemetry/v1/application.rb +0 -92
- data/lib/datadog/core/telemetry/v1/configuration.rb +0 -25
- data/lib/datadog/core/telemetry/v1/dependency.rb +0 -43
- data/lib/datadog/core/telemetry/v1/host.rb +0 -59
- data/lib/datadog/core/telemetry/v1/install_signature.rb +0 -38
- data/lib/datadog/core/telemetry/v1/integration.rb +0 -64
- data/lib/datadog/core/telemetry/v1/product.rb +0 -36
- data/lib/datadog/core/telemetry/v1/telemetry_request.rb +0 -106
- data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +0 -41
- data/lib/datadog/core/telemetry/v2/request.rb +0 -29
- data/lib/datadog/profiling/diagnostics/environment_logger.rb +0 -39
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/NativeExtensionDesign.md +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_from_pthread.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_noop.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_gc_profiling_helper.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_gc_profiling_helper.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/helpers.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.h +0 -0
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/extconf.rb
RENAMED
@@ -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 `
|
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 = "
|
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"
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.c
RENAMED
@@ -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
|
-
|
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) {
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.h
RENAMED
@@ -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
|
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.
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/http_transport.c
RENAMED
@@ -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
|
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,
|
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
|
-
|
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
|
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
|
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
|
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 = '~>
|
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
|
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: `#{
|
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
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/profiling.c
RENAMED
@@ -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
|
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");
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.c
RENAMED
@@ -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
|
+
}
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.h
RENAMED
@@ -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);
|
data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.c
RENAMED
@@ -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 =
|
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
|
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
|
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
|
-
|
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
|
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
|
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
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -138,7 +138,7 @@ module Datadog
|
|
138
138
|
private
|
139
139
|
|
140
140
|
def compressed_and_base64_encoded(value)
|
141
|
-
Base64.
|
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}"
|
@@ -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
|
-
|
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
|