ddtrace 1.20.0 → 1.23.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 +130 -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 +226 -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 +115 -14
- 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 +81 -4
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/heap_recorder.h +12 -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 +5 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.c +161 -62
- 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/response.rb +4 -0
- 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 +23 -6
- 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/stack_recorder.rb +6 -2
- 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 +58 -65
- 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
@@ -82,6 +82,9 @@ static ID at_id_id; // id of :@id in Ruby
|
|
82
82
|
static ID at_resource_id; // id of :@resource in Ruby
|
83
83
|
static ID at_root_span_id; // id of :@root_span in Ruby
|
84
84
|
static ID at_type_id; // id of :@type in Ruby
|
85
|
+
static ID at_otel_values_id; // id of :@otel_values in Ruby
|
86
|
+
static ID at_parent_span_id_id; // id of :@parent_span_id in Ruby
|
87
|
+
static ID at_datadog_trace_id; // id of :@datadog_trace in Ruby
|
85
88
|
|
86
89
|
// Contains state for a single ThreadContext instance
|
87
90
|
struct thread_context_collector_state {
|
@@ -114,6 +117,8 @@ struct thread_context_collector_state {
|
|
114
117
|
monotonic_to_system_epoch_state time_converter_state;
|
115
118
|
// Used to identify the main thread, to give it a fallback name
|
116
119
|
VALUE main_thread;
|
120
|
+
// Used when extracting trace identifiers from otel spans. Lazily initialized.
|
121
|
+
VALUE otel_current_span_key;
|
117
122
|
|
118
123
|
struct stats {
|
119
124
|
// Track how many garbage collection samples we've taken.
|
@@ -212,12 +217,20 @@ static long thread_id_for(VALUE thread);
|
|
212
217
|
static VALUE _native_stats(VALUE self, VALUE collector_instance);
|
213
218
|
static VALUE _native_gc_tracking(VALUE self, VALUE collector_instance);
|
214
219
|
static void trace_identifiers_for(struct thread_context_collector_state *state, VALUE thread, struct trace_identifiers *trace_identifiers_result);
|
215
|
-
static bool should_collect_resource(VALUE
|
220
|
+
static bool should_collect_resource(VALUE root_span);
|
216
221
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
217
222
|
static VALUE thread_list(struct thread_context_collector_state *state);
|
218
223
|
static VALUE _native_sample_allocation(DDTRACE_UNUSED VALUE self, VALUE collector_instance, VALUE sample_weight, VALUE new_object);
|
219
224
|
static VALUE _native_new_empty_thread(VALUE self);
|
220
225
|
static ddog_CharSlice ruby_value_type_to_class_name(enum ruby_value_type type);
|
226
|
+
static void ddtrace_otel_trace_identifiers_for(
|
227
|
+
struct thread_context_collector_state *state,
|
228
|
+
VALUE *active_trace,
|
229
|
+
VALUE *root_span,
|
230
|
+
VALUE *numeric_span_id,
|
231
|
+
VALUE active_span,
|
232
|
+
VALUE otel_values
|
233
|
+
);
|
221
234
|
|
222
235
|
void collectors_thread_context_init(VALUE profiling_module) {
|
223
236
|
VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
|
@@ -255,6 +268,9 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
255
268
|
at_resource_id = rb_intern_const("@resource");
|
256
269
|
at_root_span_id = rb_intern_const("@root_span");
|
257
270
|
at_type_id = rb_intern_const("@type");
|
271
|
+
at_otel_values_id = rb_intern_const("@otel_values");
|
272
|
+
at_parent_span_id_id = rb_intern_const("@parent_span_id");
|
273
|
+
at_datadog_trace_id = rb_intern_const("@datadog_trace");
|
258
274
|
|
259
275
|
gc_profiling_init();
|
260
276
|
}
|
@@ -282,6 +298,7 @@ static void thread_context_collector_typed_data_mark(void *state_ptr) {
|
|
282
298
|
st_foreach(state->hash_map_per_thread_context, hash_map_per_thread_context_mark, 0 /* unused */);
|
283
299
|
rb_gc_mark(state->thread_list_buffer);
|
284
300
|
rb_gc_mark(state->main_thread);
|
301
|
+
rb_gc_mark(state->otel_current_span_key);
|
285
302
|
}
|
286
303
|
|
287
304
|
static void thread_context_collector_typed_data_free(void *state_ptr) {
|
@@ -334,6 +351,7 @@ static VALUE _native_new(VALUE klass) {
|
|
334
351
|
state->allocation_type_enabled = true;
|
335
352
|
state->time_converter_state = (monotonic_to_system_epoch_state) MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER;
|
336
353
|
state->main_thread = rb_thread_main();
|
354
|
+
state->otel_current_span_key = Qnil;
|
337
355
|
state->gc_tracking.wall_time_at_previous_gc_ns = INVALID_TIME;
|
338
356
|
state->gc_tracking.wall_time_at_last_flushed_gc_event_ns = 0;
|
339
357
|
|
@@ -603,11 +621,14 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
|
|
603
621
|
// Let the caller know if it should schedule a flush or not. Returning true every time would cause a lot of overhead
|
604
622
|
// on the application (see GC tracking introduction at the top of the file), so instead we try to accumulate a few
|
605
623
|
// samples first.
|
606
|
-
bool finished_major_gc = gc_profiling_has_major_gc_finished();
|
607
624
|
bool over_flush_time_treshold =
|
608
625
|
(wall_time_at_finish_ns - state->gc_tracking.wall_time_at_last_flushed_gc_event_ns) >= TIME_BETWEEN_GC_EVENTS_NS;
|
609
626
|
|
610
|
-
|
627
|
+
if (over_flush_time_treshold) {
|
628
|
+
return true;
|
629
|
+
} else {
|
630
|
+
return gc_profiling_has_major_gc_finished();
|
631
|
+
}
|
611
632
|
}
|
612
633
|
|
613
634
|
// This function gets called after one or more GC work steps (calls to on_gc_start/on_gc_finish).
|
@@ -917,6 +938,7 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
|
|
917
938
|
));
|
918
939
|
rb_str_concat(result, rb_sprintf(" main_thread=%"PRIsVALUE, state->main_thread));
|
919
940
|
rb_str_concat(result, rb_sprintf(" gc_tracking=%"PRIsVALUE, gc_tracking_as_ruby_hash(state)));
|
941
|
+
rb_str_concat(result, rb_sprintf(" otel_current_span_key=%"PRIsVALUE, state->otel_current_span_key));
|
920
942
|
|
921
943
|
return result;
|
922
944
|
}
|
@@ -1104,10 +1126,19 @@ static void trace_identifiers_for(struct thread_context_collector_state *state,
|
|
1104
1126
|
|
1105
1127
|
VALUE root_span = rb_ivar_get(active_trace, at_root_span_id /* @root_span */);
|
1106
1128
|
VALUE active_span = rb_ivar_get(active_trace, at_active_span_id /* @active_span */);
|
1107
|
-
|
1129
|
+
// Note: On Ruby 3.x `rb_attr_get` is exactly the same as `rb_ivar_get`. For Ruby 2.x, the difference is that
|
1130
|
+
// `rb_ivar_get` can trigger "warning: instance variable @otel_values not initialized" if warnings are enabled and
|
1131
|
+
// opentelemetry is not in use, whereas `rb_attr_get` does the lookup without generating the warning.
|
1132
|
+
VALUE otel_values = rb_attr_get(active_trace, at_otel_values_id /* @otel_values */);
|
1133
|
+
|
1134
|
+
VALUE numeric_span_id = Qnil;
|
1135
|
+
|
1136
|
+
if (otel_values != Qnil) ddtrace_otel_trace_identifiers_for(state, &active_trace, &root_span, &numeric_span_id, active_span, otel_values);
|
1137
|
+
|
1138
|
+
if (root_span == Qnil || (active_span == Qnil && numeric_span_id == Qnil)) return;
|
1108
1139
|
|
1109
1140
|
VALUE numeric_local_root_span_id = rb_ivar_get(root_span, at_id_id /* @id */);
|
1110
|
-
|
1141
|
+
if (active_span != Qnil && numeric_span_id == Qnil) numeric_span_id = rb_ivar_get(active_span, at_id_id /* @id */);
|
1111
1142
|
if (numeric_local_root_span_id == Qnil || numeric_span_id == Qnil) return;
|
1112
1143
|
|
1113
1144
|
trace_identifiers_result->local_root_span_id = NUM2ULL(numeric_local_root_span_id);
|
@@ -1115,10 +1146,7 @@ static void trace_identifiers_for(struct thread_context_collector_state *state,
|
|
1115
1146
|
|
1116
1147
|
trace_identifiers_result->valid = true;
|
1117
1148
|
|
1118
|
-
if (!state->endpoint_collection_enabled) return;
|
1119
|
-
|
1120
|
-
VALUE root_span_type = rb_ivar_get(root_span, at_type_id /* @type */);
|
1121
|
-
if (root_span_type == Qnil || !should_collect_resource(root_span_type)) return;
|
1149
|
+
if (!state->endpoint_collection_enabled || !should_collect_resource(root_span)) return;
|
1122
1150
|
|
1123
1151
|
VALUE trace_resource = rb_ivar_get(active_trace, at_resource_id /* @resource */);
|
1124
1152
|
if (RB_TYPE_P(trace_resource, T_STRING)) {
|
@@ -1129,21 +1157,32 @@ static void trace_identifiers_for(struct thread_context_collector_state *state,
|
|
1129
1157
|
}
|
1130
1158
|
}
|
1131
1159
|
|
1132
|
-
// We
|
1160
|
+
// We opt-in to collecting the resource for spans of types:
|
1133
1161
|
// * 'web', for web requests
|
1134
|
-
// * proxy', used by the rack integration with request_queuing: true (e.g. also represents a web request)
|
1162
|
+
// * 'proxy', used by the rack integration with request_queuing: true (e.g. also represents a web request)
|
1163
|
+
// * 'worker', used for sidekiq and similar background job processors
|
1135
1164
|
//
|
1136
|
-
//
|
1165
|
+
// Over time, this list may be expanded.
|
1137
1166
|
// Resources MUST NOT include personal identifiable information (PII); this should not be the case with
|
1138
1167
|
// ddtrace integrations, but worth mentioning just in case :)
|
1139
|
-
static bool should_collect_resource(VALUE
|
1168
|
+
static bool should_collect_resource(VALUE root_span) {
|
1169
|
+
VALUE root_span_type = rb_ivar_get(root_span, at_type_id /* @type */);
|
1170
|
+
if (root_span_type == Qnil) return false;
|
1140
1171
|
ENFORCE_TYPE(root_span_type, T_STRING);
|
1141
1172
|
|
1142
1173
|
int root_span_type_length = RSTRING_LEN(root_span_type);
|
1143
1174
|
const char *root_span_type_value = StringValuePtr(root_span_type);
|
1144
1175
|
|
1145
|
-
|
1176
|
+
bool is_web_request =
|
1177
|
+
(root_span_type_length == strlen("web") && (memcmp("web", root_span_type_value, strlen("web")) == 0)) ||
|
1146
1178
|
(root_span_type_length == strlen("proxy") && (memcmp("proxy", root_span_type_value, strlen("proxy")) == 0));
|
1179
|
+
|
1180
|
+
if (is_web_request) return true;
|
1181
|
+
|
1182
|
+
bool is_worker_request =
|
1183
|
+
(root_span_type_length == strlen("worker") && (memcmp("worker", root_span_type_value, strlen("worker")) == 0));
|
1184
|
+
|
1185
|
+
return is_worker_request;
|
1147
1186
|
}
|
1148
1187
|
|
1149
1188
|
// After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
|
@@ -1299,3 +1338,65 @@ static ddog_CharSlice ruby_value_type_to_class_name(enum ruby_value_type type) {
|
|
1299
1338
|
default: return DDOG_CHARSLICE_C("(VM Internal, Missing class)");
|
1300
1339
|
}
|
1301
1340
|
}
|
1341
|
+
|
1342
|
+
static VALUE get_otel_current_span_key(struct thread_context_collector_state *state) {
|
1343
|
+
if (state->otel_current_span_key == Qnil) {
|
1344
|
+
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
1345
|
+
VALUE opentelemetry_module = rb_const_get(datadog_module, rb_intern("OpenTelemetry"));
|
1346
|
+
VALUE api_module = rb_const_get(opentelemetry_module, rb_intern("API"));
|
1347
|
+
VALUE context_module = rb_const_get(api_module, rb_intern_const("Context"));
|
1348
|
+
VALUE current_span_key = rb_const_get(context_module, rb_intern_const("CURRENT_SPAN_KEY"));
|
1349
|
+
|
1350
|
+
if (current_span_key == Qnil) {
|
1351
|
+
rb_raise(rb_eRuntimeError, "Unexpected: Missing Datadog::OpenTelemetry::API::Context::CURRENT_SPAN_KEY");
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
state->otel_current_span_key = current_span_key;
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
return state->otel_current_span_key;
|
1358
|
+
}
|
1359
|
+
|
1360
|
+
// This method gets used when ddtrace is being used indirectly via the otel APIs. Information gets stored slightly
|
1361
|
+
// differently, and this codepath handles it.
|
1362
|
+
static void ddtrace_otel_trace_identifiers_for(
|
1363
|
+
struct thread_context_collector_state *state,
|
1364
|
+
VALUE *active_trace,
|
1365
|
+
VALUE *root_span,
|
1366
|
+
VALUE *numeric_span_id,
|
1367
|
+
VALUE active_span,
|
1368
|
+
VALUE otel_values
|
1369
|
+
) {
|
1370
|
+
VALUE resolved_numeric_span_id =
|
1371
|
+
active_span == Qnil ?
|
1372
|
+
// For traces started from otel spans, the span id will be empty, and the @parent_span_id has the right value
|
1373
|
+
rb_ivar_get(*active_trace, at_parent_span_id_id /* @parent_span_id */) :
|
1374
|
+
// Regular span created by ddtrace
|
1375
|
+
rb_ivar_get(active_span, at_id_id /* @id */);
|
1376
|
+
|
1377
|
+
if (resolved_numeric_span_id == Qnil) return;
|
1378
|
+
|
1379
|
+
VALUE otel_current_span_key = get_otel_current_span_key(state);
|
1380
|
+
VALUE current_trace = *active_trace;
|
1381
|
+
|
1382
|
+
// ddtrace uses a different structure when spans are created from otel, where each otel span will have a unique ddtrace
|
1383
|
+
// trace and span representing it. Each ddtrace trace is then connected to the previous otel span, forming a linked
|
1384
|
+
// list. The local root span is going to be the trace/span we find at the end of this linked list.
|
1385
|
+
while (otel_values != Qnil) {
|
1386
|
+
VALUE otel_span = rb_hash_lookup(otel_values, otel_current_span_key);
|
1387
|
+
if (otel_span == Qnil) break;
|
1388
|
+
VALUE next_trace = rb_ivar_get(otel_span, at_datadog_trace_id);
|
1389
|
+
if (next_trace == Qnil) break;
|
1390
|
+
|
1391
|
+
current_trace = next_trace;
|
1392
|
+
otel_values = rb_ivar_get(current_trace, at_otel_values_id /* @otel_values */);
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
// We found the last trace in the linked list. This contains the local root span
|
1396
|
+
VALUE resolved_root_span = rb_ivar_get(current_trace, at_root_span_id /* @root_span */);
|
1397
|
+
if (resolved_root_span == Qnil) return;
|
1398
|
+
|
1399
|
+
*root_span = resolved_root_span;
|
1400
|
+
*active_trace = current_trace;
|
1401
|
+
*numeric_span_id = resolved_numeric_span_id;
|
1402
|
+
}
|
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;
|
@@ -146,6 +158,13 @@ struct heap_recorder {
|
|
146
158
|
|
147
159
|
// Sampling state
|
148
160
|
uint num_recordings_skipped;
|
161
|
+
|
162
|
+
struct stats_last_update {
|
163
|
+
size_t objects_alive;
|
164
|
+
size_t objects_dead;
|
165
|
+
size_t objects_skipped;
|
166
|
+
size_t objects_frozen;
|
167
|
+
} stats_last_update;
|
149
168
|
};
|
150
169
|
static heap_record* get_or_create_heap_record(heap_recorder*, ddog_prof_Slice_Location);
|
151
170
|
static void cleanup_heap_record_if_unused(heap_recorder*, heap_record*);
|
@@ -353,11 +372,16 @@ void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
|
|
353
372
|
return;
|
354
373
|
}
|
355
374
|
|
375
|
+
heap_recorder->iteration_gen = rb_gc_count();
|
376
|
+
|
356
377
|
if (heap_recorder->object_records_snapshot != NULL) {
|
357
378
|
// we could trivially handle this but we raise to highlight and catch unexpected usages.
|
358
379
|
rb_raise(rb_eRuntimeError, "New heap recorder iteration prepared without the previous one having been finished.");
|
359
380
|
}
|
360
381
|
|
382
|
+
// Reset last update stats, we'll be building them from scratch during the st_foreach call below
|
383
|
+
heap_recorder->stats_last_update = (struct stats_last_update) {};
|
384
|
+
|
361
385
|
st_foreach(heap_recorder->object_records, st_object_record_update, (st_data_t) heap_recorder);
|
362
386
|
|
363
387
|
heap_recorder->object_records_snapshot = st_copy(heap_recorder->object_records);
|
@@ -413,6 +437,22 @@ bool heap_recorder_for_each_live_object(
|
|
413
437
|
return true;
|
414
438
|
}
|
415
439
|
|
440
|
+
VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder) {
|
441
|
+
VALUE arguments[] = {
|
442
|
+
ID2SYM(rb_intern("num_object_records")), /* => */ LONG2NUM(heap_recorder->object_records->num_entries),
|
443
|
+
ID2SYM(rb_intern("num_heap_records")), /* => */ LONG2NUM(heap_recorder->heap_records->num_entries),
|
444
|
+
|
445
|
+
// Stats as of last update
|
446
|
+
ID2SYM(rb_intern("last_update_objects_alive")), /* => */ LONG2NUM(heap_recorder->stats_last_update.objects_alive),
|
447
|
+
ID2SYM(rb_intern("last_update_objects_dead")), /* => */ LONG2NUM(heap_recorder->stats_last_update.objects_dead),
|
448
|
+
ID2SYM(rb_intern("last_update_objects_skipped")), /* => */ LONG2NUM(heap_recorder->stats_last_update.objects_skipped),
|
449
|
+
ID2SYM(rb_intern("last_update_objects_frozen")), /* => */ LONG2NUM(heap_recorder->stats_last_update.objects_frozen),
|
450
|
+
};
|
451
|
+
VALUE hash = rb_hash_new();
|
452
|
+
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(hash, arguments[i], arguments[i+1]);
|
453
|
+
return hash;
|
454
|
+
}
|
455
|
+
|
416
456
|
void heap_recorder_testonly_assert_hash_matches(ddog_prof_Slice_Location locations) {
|
417
457
|
heap_stack *stack = heap_stack_new(locations);
|
418
458
|
heap_record_key stack_based_key = (heap_record_key) {
|
@@ -459,6 +499,13 @@ static int st_object_record_entry_free(DDTRACE_UNUSED st_data_t key, st_data_t v
|
|
459
499
|
return ST_DELETE;
|
460
500
|
}
|
461
501
|
|
502
|
+
// Check to see if an object should not be included in a heap recorder iteration.
|
503
|
+
// This centralizes the checking logic to ensure it's equally applied between
|
504
|
+
// preparation and iteration codepaths.
|
505
|
+
static inline bool should_exclude_from_iteration(object_record *obj_record) {
|
506
|
+
return obj_record->object_data.gen_age < ITERATION_MIN_AGE;
|
507
|
+
}
|
508
|
+
|
462
509
|
static int st_object_record_update(st_data_t key, st_data_t value, st_data_t extra_arg) {
|
463
510
|
long obj_id = (long) key;
|
464
511
|
object_record *record = (object_record*) value;
|
@@ -466,9 +513,24 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
466
513
|
|
467
514
|
VALUE ref;
|
468
515
|
|
516
|
+
size_t iteration_gen = recorder->iteration_gen;
|
517
|
+
size_t alloc_gen = record->object_data.alloc_gen;
|
518
|
+
// Guard against potential overflows given unsigned types here.
|
519
|
+
record->object_data.gen_age = alloc_gen < iteration_gen ? iteration_gen - alloc_gen : 0;
|
520
|
+
|
521
|
+
if (should_exclude_from_iteration(record)) {
|
522
|
+
// If an object won't be included in the current iteration, there's
|
523
|
+
// no point checking for liveness or updating its size, so exit early.
|
524
|
+
// NOTE: This means that there should be an equivalent check during actual
|
525
|
+
// iteration otherwise we'd iterate/expose stale object data.
|
526
|
+
recorder->stats_last_update.objects_skipped++;
|
527
|
+
return ST_CONTINUE;
|
528
|
+
}
|
529
|
+
|
469
530
|
if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) {
|
470
531
|
// Id no longer associated with a valid ref. Need to delete this object record!
|
471
532
|
on_committed_object_record_cleanup(recorder, record);
|
533
|
+
recorder->stats_last_update.objects_dead++;
|
472
534
|
return ST_DELETE;
|
473
535
|
}
|
474
536
|
|
@@ -503,6 +565,7 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
503
565
|
RB_FL_SET(ref, RUBY_FL_SEEN_OBJ_ID);
|
504
566
|
|
505
567
|
on_committed_object_record_cleanup(recorder, record);
|
568
|
+
recorder->stats_last_update.objects_dead++;
|
506
569
|
return ST_DELETE;
|
507
570
|
}
|
508
571
|
|
@@ -516,6 +579,11 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
|
|
516
579
|
record->object_data.is_frozen = RB_OBJ_FROZEN(ref);
|
517
580
|
}
|
518
581
|
|
582
|
+
recorder->stats_last_update.objects_alive++;
|
583
|
+
if (record->object_data.is_frozen) {
|
584
|
+
recorder->stats_last_update.objects_frozen++;
|
585
|
+
}
|
586
|
+
|
519
587
|
return ST_CONTINUE;
|
520
588
|
}
|
521
589
|
|
@@ -525,8 +593,16 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
525
593
|
const heap_stack *stack = record->heap_record->stack;
|
526
594
|
iteration_context *context = (iteration_context*) extra;
|
527
595
|
|
528
|
-
|
596
|
+
const heap_recorder *recorder = context->heap_recorder;
|
597
|
+
|
598
|
+
if (should_exclude_from_iteration(record)) {
|
599
|
+
// Skip objects that should not be included in iteration
|
600
|
+
// NOTE: This matches the short-circuiting condition in st_object_record_update
|
601
|
+
// and prevents iteration over stale objects.
|
602
|
+
return ST_CONTINUE;
|
603
|
+
}
|
529
604
|
|
605
|
+
ddog_prof_Location *locations = recorder->reusable_locations;
|
530
606
|
for (uint16_t i = 0; i < stack->frames_len; i++) {
|
531
607
|
const heap_frame *frame = &stack->frames[i];
|
532
608
|
ddog_prof_Location *location = &locations[i];
|
@@ -725,9 +801,10 @@ void object_record_free(object_record *record) {
|
|
725
801
|
|
726
802
|
VALUE object_record_inspect(object_record *record) {
|
727
803
|
heap_frame top_frame = record->heap_record->stack->frames[0];
|
728
|
-
|
729
|
-
|
730
|
-
|
804
|
+
live_object_data object_data = record->object_data;
|
805
|
+
VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%s:%d alloc_gen=%zu gen_age=%zu frozen=%d ",
|
806
|
+
record->obj_id, object_data.weight, object_data.size, top_frame.filename,
|
807
|
+
(int) top_frame.line, object_data.alloc_gen, object_data.gen_age, object_data.is_frozen);
|
731
808
|
|
732
809
|
const char *class = record->object_data.class;
|
733
810
|
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.
|
@@ -144,6 +150,11 @@ bool heap_recorder_for_each_live_object(
|
|
144
150
|
bool (*for_each_callback)(heap_recorder_iteration_data data, void* extra_arg),
|
145
151
|
void *for_each_callback_extra_arg);
|
146
152
|
|
153
|
+
// Return a Ruby hash containing a snapshot of this recorder's interesting state at calling time.
|
154
|
+
// WARN: This allocates in the Ruby VM and therefore should not be called without the
|
155
|
+
// VM lock or during GC.
|
156
|
+
VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder);
|
157
|
+
|
147
158
|
// v--- TEST-ONLY APIs ---v
|
148
159
|
|
149
160
|
// Assert internal hashing logic is valid for the provided locations and its
|
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
|
+
}
|