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