datadog 2.0.0.beta1 → 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +181 -1
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +1 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +40 -32
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +23 -12
- data/ext/datadog_profiling_native_extension/crashtracker.c +108 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -23
- data/ext/datadog_profiling_native_extension/heap_recorder.c +81 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +1 -94
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +86 -0
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +4 -0
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +2 -12
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +25 -86
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +3 -5
- data/ext/datadog_profiling_native_extension/stack_recorder.c +161 -62
- data/lib/datadog/appsec/contrib/devise/tracking.rb +8 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -13
- data/lib/datadog/appsec/event.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +2 -1
- data/lib/datadog/core/configuration/option.rb +7 -5
- data/lib/datadog/core/configuration/settings.rb +34 -79
- data/lib/datadog/core/configuration.rb +20 -4
- data/lib/datadog/core/environment/platform.rb +7 -1
- data/lib/datadog/core/remote/client/capabilities.rb +2 -1
- data/lib/datadog/core/remote/client.rb +1 -5
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/dispatcher.rb +3 -3
- data/lib/datadog/core/remote/transport/http/config.rb +5 -5
- 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/utils/base64.rb +22 -0
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +19 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +3 -17
- data/lib/datadog/profiling/collectors/code_provenance.rb +10 -4
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +25 -0
- data/lib/datadog/profiling/component.rb +49 -17
- data/lib/datadog/profiling/crashtracker.rb +91 -0
- data/lib/datadog/profiling/exporter.rb +6 -3
- data/lib/datadog/profiling/http_transport.rb +7 -11
- data/lib/datadog/profiling/load_native_extension.rb +14 -1
- data/lib/datadog/profiling/profiler.rb +9 -2
- data/lib/datadog/profiling/stack_recorder.rb +6 -2
- data/lib/datadog/profiling.rb +12 -0
- data/lib/datadog/tracing/component.rb +5 -1
- data/lib/datadog/tracing/configuration/dynamic.rb +39 -1
- data/lib/datadog/tracing/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/action_view/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/integration.rb +11 -1
- data/lib/datadog/tracing/contrib/active_support/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +43 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +43 -5
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +1 -1
- data/lib/datadog/tracing/correlation.rb +3 -4
- data/lib/datadog/tracing/remote.rb +5 -1
- data/lib/datadog/tracing/sampling/ext.rb +5 -1
- data/lib/datadog/tracing/sampling/matcher.rb +75 -26
- data/lib/datadog/tracing/sampling/rule.rb +27 -4
- data/lib/datadog/tracing/sampling/rule_sampler.rb +19 -1
- data/lib/datadog/tracing/sampling/span/matcher.rb +13 -41
- data/lib/datadog/tracing/span.rb +7 -2
- data/lib/datadog/tracing/span_link.rb +92 -0
- data/lib/datadog/tracing/span_operation.rb +6 -4
- data/lib/datadog/tracing/trace_operation.rb +12 -0
- data/lib/datadog/tracing/tracer.rb +4 -3
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -1
- data/lib/datadog/tracing/utils.rb +16 -0
- data/lib/datadog/version.rb +1 -1
- metadata +10 -31
- data/lib/datadog/core/telemetry/collector.rb +0 -248
- data/lib/datadog/core/telemetry/v1/app_event.rb +0 -59
- data/lib/datadog/core/telemetry/v1/application.rb +0 -94
- data/lib/datadog/core/telemetry/v1/configuration.rb +0 -27
- data/lib/datadog/core/telemetry/v1/dependency.rb +0 -45
- 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 -66
- data/lib/datadog/core/telemetry/v1/product.rb +0 -36
- data/lib/datadog/core/telemetry/v1/telemetry_request.rb +0 -108
- data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +0 -41
- data/lib/datadog/core/telemetry/v2/request.rb +0 -29
@@ -169,38 +169,62 @@ static const uint8_t all_value_types_positions[] =
|
|
169
169
|
|
170
170
|
#define ALL_VALUE_TYPES_COUNT (sizeof(all_value_types) / sizeof(ddog_prof_ValueType))
|
171
171
|
|
172
|
+
// Struct for storing stats related to a profile in a particular slot.
|
173
|
+
// These stats will share the same lifetime as the data in that profile slot.
|
174
|
+
typedef struct slot_stats {
|
175
|
+
// How many individual samples were recorded into this slot (un-weighted)
|
176
|
+
uint64_t recorded_samples;
|
177
|
+
} stats_slot;
|
178
|
+
|
179
|
+
typedef struct profile_slot {
|
180
|
+
ddog_prof_Profile profile;
|
181
|
+
stats_slot stats;
|
182
|
+
} profile_slot;
|
183
|
+
|
172
184
|
// Contains native state for each instance
|
173
185
|
struct stack_recorder_state {
|
174
186
|
// Heap recorder instance
|
175
187
|
heap_recorder *heap_recorder;
|
176
188
|
|
177
|
-
pthread_mutex_t
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
ddog_prof_Profile slot_two_profile;
|
189
|
+
pthread_mutex_t mutex_slot_one;
|
190
|
+
profile_slot profile_slot_one;
|
191
|
+
pthread_mutex_t mutex_slot_two;
|
192
|
+
profile_slot profile_slot_two;
|
182
193
|
|
183
194
|
short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
|
184
195
|
|
185
196
|
uint8_t position_for[ALL_VALUE_TYPES_COUNT];
|
186
197
|
uint8_t enabled_values_count;
|
198
|
+
|
199
|
+
// Struct for storing stats related to behaviour of a stack recorder instance during its entire lifetime.
|
200
|
+
struct lifetime_stats {
|
201
|
+
// How many profiles have we serialized successfully so far
|
202
|
+
uint64_t serialization_successes;
|
203
|
+
// How many profiles have we serialized unsuccessfully so far
|
204
|
+
uint64_t serialization_failures;
|
205
|
+
// Stats on profile serialization time
|
206
|
+
long serialization_time_ns_min;
|
207
|
+
long serialization_time_ns_max;
|
208
|
+
uint64_t serialization_time_ns_total;
|
209
|
+
} stats_lifetime;
|
187
210
|
};
|
188
211
|
|
189
|
-
// Used to
|
190
|
-
struct
|
212
|
+
// Used to group mutex and the corresponding profile slot for easy unlocking after work is done.
|
213
|
+
typedef struct locked_profile_slot {
|
191
214
|
pthread_mutex_t *mutex;
|
192
|
-
|
193
|
-
};
|
215
|
+
profile_slot *data;
|
216
|
+
} locked_profile_slot;
|
194
217
|
|
195
218
|
struct call_serialize_without_gvl_arguments {
|
196
219
|
// Set by caller
|
197
220
|
struct stack_recorder_state *state;
|
198
221
|
ddog_Timespec finish_timestamp;
|
199
|
-
size_t gc_count_before_serialize;
|
200
222
|
|
201
223
|
// Set by callee
|
202
|
-
|
224
|
+
profile_slot *slot;
|
203
225
|
ddog_prof_Profile_SerializeResult result;
|
226
|
+
long heap_profile_build_time_ns;
|
227
|
+
long serialize_no_gvl_time_ns;
|
204
228
|
|
205
229
|
// Set by both
|
206
230
|
bool serialize_ran;
|
@@ -223,9 +247,9 @@ static VALUE _native_initialize(
|
|
223
247
|
static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
|
224
248
|
static VALUE ruby_time_from(ddog_Timespec ddprof_time);
|
225
249
|
static void *call_serialize_without_gvl(void *call_args);
|
226
|
-
static
|
227
|
-
static void sampler_unlock_active_profile(
|
228
|
-
static
|
250
|
+
static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state);
|
251
|
+
static void sampler_unlock_active_profile(locked_profile_slot active_slot);
|
252
|
+
static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
|
229
253
|
static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
230
254
|
static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
231
255
|
static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
@@ -234,7 +258,7 @@ static ddog_Timespec system_epoch_now_timespec(void);
|
|
234
258
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
|
235
259
|
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time);
|
236
260
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
|
237
|
-
static void
|
261
|
+
static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */);
|
238
262
|
static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
|
239
263
|
static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
|
240
264
|
static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
@@ -242,6 +266,8 @@ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self
|
|
242
266
|
static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
243
267
|
static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj);
|
244
268
|
static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj);
|
269
|
+
static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
|
270
|
+
static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns, long heap_iteration_prep_time_ns, long heap_profile_build_time_ns);
|
245
271
|
|
246
272
|
|
247
273
|
void stack_recorder_init(VALUE profiling_module) {
|
@@ -262,6 +288,7 @@ void stack_recorder_init(VALUE profiling_module) {
|
|
262
288
|
rb_define_singleton_method(stack_recorder_class, "_native_initialize", _native_initialize, 7);
|
263
289
|
rb_define_singleton_method(stack_recorder_class, "_native_serialize", _native_serialize, 1);
|
264
290
|
rb_define_singleton_method(stack_recorder_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
|
291
|
+
rb_define_singleton_method(stack_recorder_class, "_native_stats", _native_stats, 1);
|
265
292
|
rb_define_singleton_method(testing_module, "_native_active_slot", _native_active_slot, 1);
|
266
293
|
rb_define_singleton_method(testing_module, "_native_slot_one_mutex_locked?", _native_is_slot_one_mutex_locked, 1);
|
267
294
|
rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
|
@@ -306,6 +333,9 @@ static VALUE _native_new(VALUE klass) {
|
|
306
333
|
initialize_slot_concurrency_control(state);
|
307
334
|
for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
|
308
335
|
state->enabled_values_count = ALL_VALUE_TYPES_COUNT;
|
336
|
+
state->stats_lifetime = (struct lifetime_stats) {
|
337
|
+
.serialization_time_ns_min = INT64_MAX,
|
338
|
+
};
|
309
339
|
|
310
340
|
// Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
|
311
341
|
// before using them so it's ok for us to go ahead and create the StackRecorder object.
|
@@ -326,11 +356,11 @@ static VALUE _native_new(VALUE klass) {
|
|
326
356
|
}
|
327
357
|
|
328
358
|
static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
|
329
|
-
state->
|
330
|
-
state->
|
359
|
+
state->mutex_slot_one = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
|
360
|
+
state->mutex_slot_two = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
|
331
361
|
|
332
362
|
// A newly-created StackRecorder starts with slot one being active for samples, so let's lock slot two
|
333
|
-
ENFORCE_SUCCESS_GVL(pthread_mutex_lock(&state->
|
363
|
+
ENFORCE_SUCCESS_GVL(pthread_mutex_lock(&state->mutex_slot_two));
|
334
364
|
|
335
365
|
state->active_slot = 1;
|
336
366
|
}
|
@@ -353,18 +383,22 @@ static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Sl
|
|
353
383
|
rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
|
354
384
|
}
|
355
385
|
|
356
|
-
state->
|
357
|
-
|
386
|
+
state->profile_slot_one = (profile_slot) {
|
387
|
+
.profile = slot_one_profile_result.ok,
|
388
|
+
};
|
389
|
+
state->profile_slot_two = (profile_slot) {
|
390
|
+
.profile = slot_two_profile_result.ok,
|
391
|
+
};
|
358
392
|
}
|
359
393
|
|
360
394
|
static void stack_recorder_typed_data_free(void *state_ptr) {
|
361
395
|
struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
|
362
396
|
|
363
|
-
pthread_mutex_destroy(&state->
|
364
|
-
ddog_prof_Profile_drop(&state->
|
397
|
+
pthread_mutex_destroy(&state->mutex_slot_one);
|
398
|
+
ddog_prof_Profile_drop(&state->profile_slot_one.profile);
|
365
399
|
|
366
|
-
pthread_mutex_destroy(&state->
|
367
|
-
ddog_prof_Profile_drop(&state->
|
400
|
+
pthread_mutex_destroy(&state->mutex_slot_two);
|
401
|
+
ddog_prof_Profile_drop(&state->profile_slot_two.profile);
|
368
402
|
|
369
403
|
heap_recorder_free(state->heap_recorder);
|
370
404
|
|
@@ -463,8 +497,8 @@ static VALUE _native_initialize(
|
|
463
497
|
state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
|
464
498
|
}
|
465
499
|
|
466
|
-
ddog_prof_Profile_drop(&state->
|
467
|
-
ddog_prof_Profile_drop(&state->
|
500
|
+
ddog_prof_Profile_drop(&state->profile_slot_one.profile);
|
501
|
+
ddog_prof_Profile_drop(&state->profile_slot_two.profile);
|
468
502
|
|
469
503
|
ddog_prof_Slice_ValueType sample_types = {.ptr = enabled_value_types, .len = state->enabled_values_count};
|
470
504
|
initialize_profiles(state, sample_types);
|
@@ -480,16 +514,17 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
480
514
|
// Need to do this while still holding on to the Global VM Lock; see comments on method for why
|
481
515
|
serializer_set_start_timestamp_for_next_profile(state, finish_timestamp);
|
482
516
|
|
517
|
+
long heap_iteration_prep_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
|
483
518
|
// Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
|
484
519
|
// happen while holding on to the GVL.
|
485
520
|
heap_recorder_prepare_iteration(state->heap_recorder);
|
521
|
+
long heap_iteration_prep_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - heap_iteration_prep_start_time_ns;
|
486
522
|
|
487
523
|
// We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
|
488
524
|
// is pending
|
489
525
|
struct call_serialize_without_gvl_arguments args = {
|
490
526
|
.state = state,
|
491
527
|
.finish_timestamp = finish_timestamp,
|
492
|
-
.gc_count_before_serialize = rb_gc_count(),
|
493
528
|
.serialize_ran = false
|
494
529
|
};
|
495
530
|
|
@@ -510,12 +545,27 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
510
545
|
// Cleanup after heap recorder iteration. This needs to happen while holding on to the GVL.
|
511
546
|
heap_recorder_finish_iteration(state->heap_recorder);
|
512
547
|
|
548
|
+
// NOTE: We are focusing on the serialization time outside of the GVL in this stat here. This doesn't
|
549
|
+
// really cover the full serialization process but it gives a more useful number since it bypasses
|
550
|
+
// the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
|
551
|
+
// conditions and over which we really have no control about.
|
552
|
+
long serialization_time_ns = args.serialize_no_gvl_time_ns;
|
553
|
+
if (serialization_time_ns >= 0) {
|
554
|
+
// Only update stats if our serialization time is valid.
|
555
|
+
state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, serialization_time_ns);
|
556
|
+
state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, serialization_time_ns);
|
557
|
+
state->stats_lifetime.serialization_time_ns_total += serialization_time_ns;
|
558
|
+
}
|
559
|
+
|
513
560
|
ddog_prof_Profile_SerializeResult serialized_profile = args.result;
|
514
561
|
|
515
562
|
if (serialized_profile.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
|
563
|
+
state->stats_lifetime.serialization_failures++;
|
516
564
|
return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
|
517
565
|
}
|
518
566
|
|
567
|
+
state->stats_lifetime.serialization_successes++;
|
568
|
+
|
519
569
|
VALUE encoded_pprof = ruby_string_from_vec_u8(serialized_profile.ok.buffer);
|
520
570
|
|
521
571
|
ddog_Timespec ddprof_start = serialized_profile.ok.start;
|
@@ -525,8 +575,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
525
575
|
|
526
576
|
VALUE start = ruby_time_from(ddprof_start);
|
527
577
|
VALUE finish = ruby_time_from(ddprof_finish);
|
578
|
+
VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
|
528
579
|
|
529
|
-
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(
|
580
|
+
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_pprof, profile_stats));
|
530
581
|
}
|
531
582
|
|
532
583
|
static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
|
@@ -539,7 +590,7 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
539
590
|
struct stack_recorder_state *state;
|
540
591
|
TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
|
541
592
|
|
542
|
-
|
593
|
+
locked_profile_slot active_slot = sampler_lock_active_profile(state);
|
543
594
|
|
544
595
|
// Note: We initialize this array to have ALL_VALUE_TYPES_COUNT but only tell libdatadog to use the first
|
545
596
|
// state->enabled_values_count values. This simplifies handling disabled value types -- we still put them on the
|
@@ -563,7 +614,7 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
563
614
|
}
|
564
615
|
|
565
616
|
ddog_prof_Profile_Result result = ddog_prof_Profile_add(
|
566
|
-
active_slot.profile,
|
617
|
+
&active_slot.data->profile,
|
567
618
|
(ddog_prof_Sample) {
|
568
619
|
.locations = locations,
|
569
620
|
.values = (ddog_Slice_I64) {.ptr = metric_values, .len = state->enabled_values_count},
|
@@ -572,6 +623,8 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
572
623
|
labels.end_timestamp_ns
|
573
624
|
);
|
574
625
|
|
626
|
+
active_slot.data->stats.recorded_samples++;
|
627
|
+
|
575
628
|
sampler_unlock_active_profile(active_slot);
|
576
629
|
|
577
630
|
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
@@ -592,9 +645,9 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
|
|
592
645
|
struct stack_recorder_state *state;
|
593
646
|
TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
|
594
647
|
|
595
|
-
|
648
|
+
locked_profile_slot active_slot = sampler_lock_active_profile(state);
|
596
649
|
|
597
|
-
ddog_prof_Profile_Result result = ddog_prof_Profile_set_endpoint(active_slot.profile, local_root_span_id, endpoint);
|
650
|
+
ddog_prof_Profile_Result result = ddog_prof_Profile_set_endpoint(&active_slot.data->profile, local_root_span_id, endpoint);
|
598
651
|
|
599
652
|
sampler_unlock_active_profile(active_slot);
|
600
653
|
|
@@ -609,12 +662,10 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
|
|
609
662
|
// during iteration of heap recorder live objects.
|
610
663
|
typedef struct heap_recorder_iteration_context {
|
611
664
|
struct stack_recorder_state *state;
|
612
|
-
|
665
|
+
profile_slot *slot;
|
613
666
|
|
614
667
|
bool error;
|
615
668
|
char error_msg[MAX_LEN_HEAP_ITERATION_ERROR_MSG];
|
616
|
-
|
617
|
-
size_t profile_gen;
|
618
669
|
} heap_recorder_iteration_context;
|
619
670
|
|
620
671
|
static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteration_data iteration_data, void *extra_arg) {
|
@@ -643,11 +694,11 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
|
|
643
694
|
}
|
644
695
|
labels[label_offset++] = (ddog_prof_Label) {
|
645
696
|
.key = DDOG_CHARSLICE_C("gc gen age"),
|
646
|
-
.num =
|
697
|
+
.num = object_data->gen_age,
|
647
698
|
};
|
648
699
|
|
649
700
|
ddog_prof_Profile_Result result = ddog_prof_Profile_add(
|
650
|
-
context->profile,
|
701
|
+
&context->slot->profile,
|
651
702
|
(ddog_prof_Sample) {
|
652
703
|
.locations = iteration_data.locations,
|
653
704
|
.values = (ddog_Slice_I64) {.ptr = metric_values, .len = context->state->enabled_values_count},
|
@@ -659,6 +710,8 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
|
|
659
710
|
0
|
660
711
|
);
|
661
712
|
|
713
|
+
context->slot->stats.recorded_samples++;
|
714
|
+
|
662
715
|
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
663
716
|
read_ddogerr_string_and_drop(&result.err, context->error_msg, MAX_LEN_HEAP_ITERATION_ERROR_MSG);
|
664
717
|
context->error = true;
|
@@ -670,13 +723,12 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
|
|
670
723
|
return true;
|
671
724
|
}
|
672
725
|
|
673
|
-
static void build_heap_profile_without_gvl(struct stack_recorder_state *state,
|
726
|
+
static void build_heap_profile_without_gvl(struct stack_recorder_state *state, profile_slot *slot) {
|
674
727
|
heap_recorder_iteration_context iteration_context = {
|
675
728
|
.state = state,
|
676
|
-
.
|
729
|
+
.slot = slot,
|
677
730
|
.error = false,
|
678
731
|
.error_msg = {0},
|
679
|
-
.profile_gen = gc_count_before_serialize,
|
680
732
|
};
|
681
733
|
bool iterated = heap_recorder_for_each_live_object(state->heap_recorder, add_heap_sample_to_active_profile_without_gvl, (void*) &iteration_context);
|
682
734
|
// We wait until we're out of the iteration to grab the gvl and raise. This is important because during
|
@@ -694,15 +746,21 @@ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, d
|
|
694
746
|
static void *call_serialize_without_gvl(void *call_args) {
|
695
747
|
struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
|
696
748
|
|
697
|
-
|
749
|
+
long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
|
750
|
+
|
751
|
+
profile_slot *slot_now_inactive = serializer_flip_active_and_inactive_slots(args->state);
|
752
|
+
|
753
|
+
args->slot = slot_now_inactive;
|
698
754
|
|
699
755
|
// Now that we have the inactive profile with all but heap samples, lets fill it with heap data
|
700
756
|
// without needing to race with the active sampler
|
701
|
-
build_heap_profile_without_gvl(args->state, args->
|
757
|
+
build_heap_profile_without_gvl(args->state, args->slot);
|
758
|
+
args->heap_profile_build_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
|
702
759
|
|
703
760
|
// Note: The profile gets reset by the serialize call
|
704
|
-
args->result = ddog_prof_Profile_serialize(args->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
|
761
|
+
args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
|
705
762
|
args->serialize_ran = true;
|
763
|
+
args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
|
706
764
|
|
707
765
|
return NULL; // Unused
|
708
766
|
}
|
@@ -712,42 +770,42 @@ VALUE enforce_recorder_instance(VALUE object) {
|
|
712
770
|
return object;
|
713
771
|
}
|
714
772
|
|
715
|
-
static
|
773
|
+
static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state) {
|
716
774
|
int error;
|
717
775
|
|
718
776
|
for (int attempts = 0; attempts < 2; attempts++) {
|
719
|
-
error = pthread_mutex_trylock(&state->
|
777
|
+
error = pthread_mutex_trylock(&state->mutex_slot_one);
|
720
778
|
if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
|
721
779
|
|
722
780
|
// Slot one is active
|
723
|
-
if (!error) return (
|
781
|
+
if (!error) return (locked_profile_slot) {.mutex = &state->mutex_slot_one, .data = &state->profile_slot_one};
|
724
782
|
|
725
783
|
// If we got here, slot one was not active, let's try slot two
|
726
784
|
|
727
|
-
error = pthread_mutex_trylock(&state->
|
785
|
+
error = pthread_mutex_trylock(&state->mutex_slot_two);
|
728
786
|
if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
|
729
787
|
|
730
788
|
// Slot two is active
|
731
|
-
if (!error) return (
|
789
|
+
if (!error) return (locked_profile_slot) {.mutex = &state->mutex_slot_two, .data = &state->profile_slot_two};
|
732
790
|
}
|
733
791
|
|
734
792
|
// We already tried both multiple times, and we did not succeed. This is not expected to happen. Let's stop sampling.
|
735
793
|
rb_raise(rb_eRuntimeError, "Failed to grab either mutex in sampler_lock_active_profile");
|
736
794
|
}
|
737
795
|
|
738
|
-
static void sampler_unlock_active_profile(
|
796
|
+
static void sampler_unlock_active_profile(locked_profile_slot active_slot) {
|
739
797
|
ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex));
|
740
798
|
}
|
741
799
|
|
742
|
-
static
|
800
|
+
static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
|
743
801
|
int previously_active_slot = state->active_slot;
|
744
802
|
|
745
803
|
if (previously_active_slot != 1 && previously_active_slot != 2) {
|
746
804
|
grab_gvl_and_raise(rb_eRuntimeError, "Unexpected active_slot state %d in serializer_flip_active_and_inactive_slots", previously_active_slot);
|
747
805
|
}
|
748
806
|
|
749
|
-
pthread_mutex_t *previously_active = (previously_active_slot == 1) ? &state->
|
750
|
-
pthread_mutex_t *previously_inactive = (previously_active_slot == 1) ? &state->
|
807
|
+
pthread_mutex_t *previously_active = (previously_active_slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two;
|
808
|
+
pthread_mutex_t *previously_inactive = (previously_active_slot == 1) ? &state->mutex_slot_two : &state->mutex_slot_one;
|
751
809
|
|
752
810
|
// Release the lock, thus making this slot active
|
753
811
|
ENFORCE_SUCCESS_NO_GVL(pthread_mutex_unlock(previously_inactive));
|
@@ -758,8 +816,8 @@ static ddog_prof_Profile *serializer_flip_active_and_inactive_slots(struct stack
|
|
758
816
|
// Update active_slot
|
759
817
|
state->active_slot = (previously_active_slot == 1) ? 2 : 1;
|
760
818
|
|
761
|
-
// Return
|
762
|
-
return (previously_active_slot == 1) ? &state->
|
819
|
+
// Return pointer to previously active slot (now inactive)
|
820
|
+
return (previously_active_slot == 1) ? &state->profile_slot_one : &state->profile_slot_two;
|
763
821
|
}
|
764
822
|
|
765
823
|
// This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
|
@@ -783,7 +841,7 @@ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
|
|
783
841
|
struct stack_recorder_state *state;
|
784
842
|
TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
|
785
843
|
|
786
|
-
pthread_mutex_t *slot_mutex = (slot == 1) ? &state->
|
844
|
+
pthread_mutex_t *slot_mutex = (slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two;
|
787
845
|
|
788
846
|
// Like Heisenberg's uncertainty principle, we can't observe without affecting...
|
789
847
|
int error = pthread_mutex_trylock(slot_mutex);
|
@@ -818,8 +876,8 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
|
|
818
876
|
// resulting state is inconsistent, we make sure to reset it back to the initial state.
|
819
877
|
initialize_slot_concurrency_control(state);
|
820
878
|
|
821
|
-
|
822
|
-
|
879
|
+
reset_profile_slot(&state->profile_slot_one, /* start_time: */ NULL);
|
880
|
+
reset_profile_slot(&state->profile_slot_two, /* start_time: */ NULL);
|
823
881
|
|
824
882
|
heap_recorder_after_fork(state->heap_recorder);
|
825
883
|
|
@@ -830,8 +888,8 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
|
|
830
888
|
// not be interrupted part-way through by a VM fork.
|
831
889
|
static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) {
|
832
890
|
// Before making this profile active, we reset it so that it uses the correct start_time for its start
|
833
|
-
|
834
|
-
|
891
|
+
profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one;
|
892
|
+
reset_profile_slot(next_profile_slot, &start_time);
|
835
893
|
}
|
836
894
|
|
837
895
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
|
@@ -877,11 +935,12 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
|
|
877
935
|
return Qnil;
|
878
936
|
}
|
879
937
|
|
880
|
-
static void
|
881
|
-
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile, start_time);
|
938
|
+
static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */) {
|
939
|
+
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile, start_time);
|
882
940
|
if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
883
941
|
rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
|
884
942
|
}
|
943
|
+
slot->stats = (stats_slot) {};
|
885
944
|
}
|
886
945
|
|
887
946
|
// This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
|
@@ -918,10 +977,13 @@ static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recor
|
|
918
977
|
#pragma GCC diagnostic push
|
919
978
|
// rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
|
920
979
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
980
|
+
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
921
981
|
// This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
|
922
982
|
// It SHOULD NOT be used for other purposes.
|
923
983
|
static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
|
924
|
-
|
984
|
+
#ifdef HAVE_WORKING_RB_GC_FORCE_RECYCLE
|
985
|
+
rb_gc_force_recycle(obj);
|
986
|
+
#endif
|
925
987
|
return Qnil;
|
926
988
|
}
|
927
989
|
#pragma GCC diagnostic pop
|
@@ -939,3 +1001,40 @@ static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj) {
|
|
939
1001
|
return Qfalse;
|
940
1002
|
#endif
|
941
1003
|
}
|
1004
|
+
|
1005
|
+
static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
|
1006
|
+
struct stack_recorder_state *state;
|
1007
|
+
TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
|
1008
|
+
|
1009
|
+
uint64_t total_serializations = state->stats_lifetime.serialization_successes + state->stats_lifetime.serialization_failures;
|
1010
|
+
|
1011
|
+
VALUE heap_recorder_snapshot = state->heap_recorder ?
|
1012
|
+
heap_recorder_state_snapshot(state->heap_recorder) : Qnil;
|
1013
|
+
|
1014
|
+
VALUE stats_as_hash = rb_hash_new();
|
1015
|
+
VALUE arguments[] = {
|
1016
|
+
ID2SYM(rb_intern("serialization_successes")), /* => */ ULL2NUM(state->stats_lifetime.serialization_successes),
|
1017
|
+
ID2SYM(rb_intern("serialization_failures")), /* => */ ULL2NUM(state->stats_lifetime.serialization_failures),
|
1018
|
+
|
1019
|
+
ID2SYM(rb_intern("serialization_time_ns_min")), /* => */ RUBY_NUM_OR_NIL(state->stats_lifetime.serialization_time_ns_min, != INT64_MAX, LONG2NUM),
|
1020
|
+
ID2SYM(rb_intern("serialization_time_ns_max")), /* => */ RUBY_NUM_OR_NIL(state->stats_lifetime.serialization_time_ns_max, > 0, LONG2NUM),
|
1021
|
+
ID2SYM(rb_intern("serialization_time_ns_total")), /* => */ RUBY_NUM_OR_NIL(state->stats_lifetime.serialization_time_ns_total, > 0, LONG2NUM),
|
1022
|
+
ID2SYM(rb_intern("serialization_time_ns_avg")), /* => */ RUBY_AVG_OR_NIL(state->stats_lifetime.serialization_time_ns_total, total_serializations),
|
1023
|
+
|
1024
|
+
ID2SYM(rb_intern("heap_recorder_snapshot")), /* => */ heap_recorder_snapshot,
|
1025
|
+
};
|
1026
|
+
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
|
1027
|
+
return stats_as_hash;
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns, long heap_iteration_prep_time_ns, long heap_profile_build_time_ns) {
|
1031
|
+
VALUE stats_as_hash = rb_hash_new();
|
1032
|
+
VALUE arguments[] = {
|
1033
|
+
ID2SYM(rb_intern("recorded_samples")), /* => */ ULL2NUM(slot->stats.recorded_samples),
|
1034
|
+
ID2SYM(rb_intern("serialization_time_ns")), /* => */ LONG2NUM(serialization_time_ns),
|
1035
|
+
ID2SYM(rb_intern("heap_iteration_prep_time_ns")), /* => */ LONG2NUM(heap_iteration_prep_time_ns),
|
1036
|
+
ID2SYM(rb_intern("heap_profile_build_time_ns")), /* => */ LONG2NUM(heap_profile_build_time_ns),
|
1037
|
+
};
|
1038
|
+
for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
|
1039
|
+
return stats_as_hash;
|
1040
|
+
}
|
@@ -13,12 +13,16 @@ module Datadog
|
|
13
13
|
SIGNUP_EVENT = 'users.signup'
|
14
14
|
|
15
15
|
def self.track_login_success(trace, span, user_id:, **others)
|
16
|
+
return if trace.nil? || span.nil?
|
17
|
+
|
16
18
|
track(LOGIN_SUCCESS_EVENT, trace, span, **others)
|
17
19
|
|
18
20
|
Kit::Identity.set_user(trace, span, id: user_id.to_s, **others) if user_id
|
19
21
|
end
|
20
22
|
|
21
23
|
def self.track_login_failure(trace, span, user_id:, user_exists:, **others)
|
24
|
+
return if trace.nil? || span.nil?
|
25
|
+
|
22
26
|
track(LOGIN_FAILURE_EVENT, trace, span, **others)
|
23
27
|
|
24
28
|
span.set_tag('appsec.events.users.login.failure.usr.id', user_id) if user_id
|
@@ -26,11 +30,15 @@ module Datadog
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def self.track_signup(trace, span, user_id:, **others)
|
33
|
+
return if trace.nil? || span.nil?
|
34
|
+
|
29
35
|
track(SIGNUP_EVENT, trace, span, **others)
|
30
36
|
Kit::Identity.set_user(trace, id: user_id.to_s, **others) if user_id
|
31
37
|
end
|
32
38
|
|
33
39
|
def self.track(event, trace, span, **others)
|
40
|
+
return if trace.nil? || span.nil?
|
41
|
+
|
34
42
|
span.set_tag("appsec.events.#{event}.track", 'true')
|
35
43
|
span.set_tag("_dd.appsec.events.#{event}.auto.mode", Datadog.configuration.appsec.track_user_events.mode)
|
36
44
|
|
@@ -15,6 +15,18 @@ module Datadog
|
|
15
15
|
module AppSec
|
16
16
|
module Contrib
|
17
17
|
module Rack
|
18
|
+
# Create an array of lowercased headers
|
19
|
+
WAF_VENDOR_HEADERS_TAGS = %w[
|
20
|
+
X-Amzn-Trace-Id
|
21
|
+
Cloudfront-Viewer-Ja3-Fingerprint
|
22
|
+
Cf-Ray
|
23
|
+
X-Cloud-Trace-Context
|
24
|
+
X-Appgw-Trace-id
|
25
|
+
X-SigSci-RequestID
|
26
|
+
X-SigSci-Tags
|
27
|
+
Akamai-User-Risk
|
28
|
+
].map(&:downcase).freeze
|
29
|
+
|
18
30
|
# Topmost Rack middleware for AppSec
|
19
31
|
# This should be inserted just below Datadog::Tracing::Contrib::Rack::TraceMiddleware
|
20
32
|
class RequestMiddleware
|
@@ -22,6 +34,7 @@ module Datadog
|
|
22
34
|
@app = app
|
23
35
|
|
24
36
|
@oneshot_tags_sent = false
|
37
|
+
@rack_headers = {}
|
25
38
|
end
|
26
39
|
|
27
40
|
# rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
@@ -56,7 +69,8 @@ module Datadog
|
|
56
69
|
|
57
70
|
gateway_request = Gateway::Request.new(env)
|
58
71
|
|
59
|
-
add_appsec_tags(processor, scope
|
72
|
+
add_appsec_tags(processor, scope)
|
73
|
+
add_request_tags(scope, env)
|
60
74
|
|
61
75
|
request_return, request_response = catch(::Datadog::AppSec::Ext::INTERRUPT) do
|
62
76
|
Instrumentation.gateway.push('rack.request', gateway_request) do
|
@@ -131,7 +145,7 @@ module Datadog
|
|
131
145
|
Datadog::Tracing.active_span
|
132
146
|
end
|
133
147
|
|
134
|
-
def add_appsec_tags(processor, scope
|
148
|
+
def add_appsec_tags(processor, scope)
|
135
149
|
span = scope.service_entry_span
|
136
150
|
trace = scope.trace
|
137
151
|
|
@@ -141,17 +155,6 @@ module Datadog
|
|
141
155
|
span.set_tag('_dd.runtime_family', 'ruby')
|
142
156
|
span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
143
157
|
|
144
|
-
if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
|
145
|
-
request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
|
146
|
-
|
147
|
-
# always collect client ip, as this is part of AppSec provided functionality
|
148
|
-
Datadog::Tracing::ClientIp.set_client_ip_tag!(
|
149
|
-
span,
|
150
|
-
headers: request_header_collection,
|
151
|
-
remote_ip: env['REMOTE_ADDR']
|
152
|
-
)
|
153
|
-
end
|
154
|
-
|
155
158
|
if processor.diagnostics
|
156
159
|
diagnostics = processor.diagnostics
|
157
160
|
|
@@ -177,6 +180,29 @@ module Datadog
|
|
177
180
|
end
|
178
181
|
end
|
179
182
|
|
183
|
+
def add_request_tags(scope, env)
|
184
|
+
span = scope.service_entry_span
|
185
|
+
|
186
|
+
return unless span
|
187
|
+
|
188
|
+
# Always add WAF vendors headers
|
189
|
+
WAF_VENDOR_HEADERS_TAGS.each do |lowercase_header|
|
190
|
+
rack_header = to_rack_header(lowercase_header)
|
191
|
+
span.set_tag("http.request.headers.#{lowercase_header}", env[rack_header]) if env[rack_header]
|
192
|
+
end
|
193
|
+
|
194
|
+
if span && span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
|
195
|
+
request_header_collection = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
|
196
|
+
|
197
|
+
# always collect client ip, as this is part of AppSec provided functionality
|
198
|
+
Datadog::Tracing::ClientIp.set_client_ip_tag!(
|
199
|
+
span,
|
200
|
+
headers: request_header_collection,
|
201
|
+
remote_ip: env['REMOTE_ADDR']
|
202
|
+
)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
180
206
|
def add_waf_runtime_tags(scope)
|
181
207
|
span = scope.service_entry_span
|
182
208
|
context = scope.processor_context
|
@@ -189,6 +215,10 @@ module Datadog
|
|
189
215
|
span.set_tag('_dd.appsec.waf.duration', context.time_ns / 1000.0)
|
190
216
|
span.set_tag('_dd.appsec.waf.duration_ext', context.time_ext_ns / 1000.0)
|
191
217
|
end
|
218
|
+
|
219
|
+
def to_rack_header(header)
|
220
|
+
@rack_headers[header] ||= Datadog::Tracing::Contrib::Rack::Header.to_rack_header(header)
|
221
|
+
end
|
192
222
|
end
|
193
223
|
end
|
194
224
|
end
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'zlib'
|
5
|
-
require 'base64'
|
6
5
|
|
7
6
|
require_relative 'rate_limiter'
|
7
|
+
require_relative '../core/utils/base64'
|
8
8
|
|
9
9
|
module Datadog
|
10
10
|
module AppSec
|
@@ -140,7 +140,7 @@ module Datadog
|
|
140
140
|
private
|
141
141
|
|
142
142
|
def compressed_and_base64_encoded(value)
|
143
|
-
Base64.
|
143
|
+
Datadog::Core::Utils::Base64.strict_encode64(gzip(value))
|
144
144
|
rescue TypeError => e
|
145
145
|
Datadog.logger.debug do
|
146
146
|
"Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}"
|