datadog 2.8.0 → 2.10.0
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 +62 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +66 -56
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +221 -127
- data/ext/datadog_profiling_native_extension/heap_recorder.c +50 -92
- data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -76
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/lib/datadog/appsec/actions_handler.rb +27 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/component.rb +14 -8
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/context.rb +74 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +12 -8
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +20 -30
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +67 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +7 -7
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -60
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +23 -33
- data/lib/datadog/appsec/contrib/rails/patcher.rb +4 -14
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +7 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +45 -65
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -28
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +6 -6
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +8 -1
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +23 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +6 -6
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec/processor.rb +4 -3
- data/lib/datadog/appsec/response.rb +18 -80
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +88 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec.rb +17 -8
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +4 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +7 -4
- data/lib/datadog/di/component.rb +19 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +39 -18
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe_manager.rb +4 -4
- data/lib/datadog/di/probe_notification_builder.rb +22 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +30 -9
- data/lib/datadog/di/transport.rb +2 -4
- data/lib/datadog/di.rb +5 -108
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +55 -53
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/extensions.rb +15 -3
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +1 -1
- metadata +40 -17
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -1,8 +1,6 @@
|
|
1
1
|
#include "heap_recorder.h"
|
2
|
-
#include <pthread.h>
|
3
2
|
#include "ruby/st.h"
|
4
3
|
#include "ruby_helpers.h"
|
5
|
-
#include <errno.h>
|
6
4
|
#include "collectors_stack.h"
|
7
5
|
#include "libdatadog_helpers.h"
|
8
6
|
#include "time_helpers.h"
|
@@ -30,7 +28,6 @@ typedef struct {
|
|
30
28
|
char *filename;
|
31
29
|
int32_t line;
|
32
30
|
} heap_frame;
|
33
|
-
static st_index_t heap_frame_hash(heap_frame*, st_index_t seed);
|
34
31
|
|
35
32
|
// A compact representation of a stacktrace for a heap allocation.
|
36
33
|
//
|
@@ -113,14 +110,6 @@ static void object_record_free(object_record*);
|
|
113
110
|
static VALUE object_record_inspect(object_record*);
|
114
111
|
static object_record SKIPPED_RECORD = {0};
|
115
112
|
|
116
|
-
// A wrapper around an object record that is in the process of being recorded and was not
|
117
|
-
// yet committed.
|
118
|
-
typedef struct {
|
119
|
-
// Pointer to the (potentially partial) object_record containing metadata about an ongoing recording.
|
120
|
-
// When NULL, this symbolizes an unstarted/invalid recording.
|
121
|
-
object_record *object_record;
|
122
|
-
} recording;
|
123
|
-
|
124
113
|
struct heap_recorder {
|
125
114
|
// Config
|
126
115
|
// Whether the recorder should try to determine approximate sizes for tracked objects.
|
@@ -140,6 +129,9 @@ struct heap_recorder {
|
|
140
129
|
// outside the GVL.
|
141
130
|
// NOTE: This table has ownership of its object_records. The keys are longs and so are
|
142
131
|
// passed as values.
|
132
|
+
//
|
133
|
+
// TODO: @ivoanjo We've evolved to actually never need to look up on object_records (we only insert and iterate),
|
134
|
+
// so right now this seems to be just a really really fancy self-resizing list/set.
|
143
135
|
st_table *object_records;
|
144
136
|
|
145
137
|
// Map[obj_id: long, record: object_record*]
|
@@ -162,7 +154,7 @@ struct heap_recorder {
|
|
162
154
|
long last_update_ns;
|
163
155
|
|
164
156
|
// Data for a heap recording that was started but not yet ended
|
165
|
-
|
157
|
+
object_record *active_recording;
|
166
158
|
|
167
159
|
// Reusable location array, implementing a flyweight pattern for things like iteration.
|
168
160
|
ddog_prof_Location *reusable_locations;
|
@@ -207,7 +199,7 @@ static int st_object_record_update(st_data_t, st_data_t, st_data_t);
|
|
207
199
|
static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
|
208
200
|
static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
|
209
201
|
static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
|
210
|
-
static void commit_recording(heap_recorder*, heap_record*,
|
202
|
+
static void commit_recording(heap_recorder *, heap_record *, object_record *active_recording);
|
211
203
|
static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
|
212
204
|
static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update);
|
213
205
|
static inline double ewma_stat(double previous, double current);
|
@@ -228,7 +220,7 @@ heap_recorder* heap_recorder_new(void) {
|
|
228
220
|
recorder->object_records = st_init_numtable();
|
229
221
|
recorder->object_records_snapshot = NULL;
|
230
222
|
recorder->reusable_locations = ruby_xcalloc(MAX_FRAMES_LIMIT, sizeof(ddog_prof_Location));
|
231
|
-
recorder->active_recording =
|
223
|
+
recorder->active_recording = NULL;
|
232
224
|
recorder->size_enabled = true;
|
233
225
|
recorder->sample_rate = 1; // By default do no sampling on top of what allocation profiling already does
|
234
226
|
|
@@ -254,9 +246,9 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
|
|
254
246
|
st_foreach(heap_recorder->heap_records, st_heap_record_entry_free, 0);
|
255
247
|
st_free_table(heap_recorder->heap_records);
|
256
248
|
|
257
|
-
if (heap_recorder->active_recording
|
249
|
+
if (heap_recorder->active_recording != NULL && heap_recorder->active_recording != &SKIPPED_RECORD) {
|
258
250
|
// If there's a partial object record, clean it up as well
|
259
|
-
object_record_free(heap_recorder->active_recording
|
251
|
+
object_record_free(heap_recorder->active_recording);
|
260
252
|
}
|
261
253
|
|
262
254
|
ruby_xfree(heap_recorder->reusable_locations);
|
@@ -301,7 +293,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
301
293
|
//
|
302
294
|
// There is one small caveat though: fork only preserves one thread and in a Ruby app, that
|
303
295
|
// will be the thread holding on to the GVL. Since we support iteration on the heap recorder
|
304
|
-
// outside of the GVL, any state specific to that interaction may be
|
296
|
+
// outside of the GVL, any state specific to that interaction may be inconsistent after fork
|
305
297
|
// (e.g. an acquired lock for thread safety). Iteration operates on object_records_snapshot
|
306
298
|
// though and that one will be updated on next heap_recorder_prepare_iteration so we really
|
307
299
|
// only need to finish any iteration that might have been left unfinished.
|
@@ -313,18 +305,17 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
|
|
313
305
|
heap_recorder->stats_lifetime = (struct stats_lifetime) {0};
|
314
306
|
}
|
315
307
|
|
316
|
-
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice
|
308
|
+
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class) {
|
317
309
|
if (heap_recorder == NULL) {
|
318
310
|
return;
|
319
311
|
}
|
320
312
|
|
321
|
-
if (heap_recorder->active_recording
|
313
|
+
if (heap_recorder->active_recording != NULL) {
|
322
314
|
rb_raise(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
|
323
315
|
}
|
324
316
|
|
325
|
-
if (heap_recorder->num_recordings_skipped
|
326
|
-
heap_recorder->active_recording
|
327
|
-
heap_recorder->num_recordings_skipped++;
|
317
|
+
if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate) {
|
318
|
+
heap_recorder->active_recording = &SKIPPED_RECORD;
|
328
319
|
return;
|
329
320
|
}
|
330
321
|
|
@@ -335,13 +326,15 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
335
326
|
rb_raise(rb_eRuntimeError, "Detected a bignum object id. These are not supported by heap profiling.");
|
336
327
|
}
|
337
328
|
|
338
|
-
heap_recorder->active_recording = (
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
329
|
+
heap_recorder->active_recording = object_record_new(
|
330
|
+
FIX2LONG(ruby_obj_id),
|
331
|
+
NULL,
|
332
|
+
(live_object_data) {
|
333
|
+
.weight = weight * heap_recorder->sample_rate,
|
334
|
+
.class = string_from_char_slice(alloc_class),
|
335
|
+
.alloc_gen = rb_gc_count(),
|
336
|
+
}
|
337
|
+
);
|
345
338
|
}
|
346
339
|
|
347
340
|
// end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
|
@@ -349,6 +342,10 @@ void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj
|
|
349
342
|
// with an rb_protect.
|
350
343
|
__attribute__((warn_unused_result))
|
351
344
|
int end_heap_allocation_recording_with_rb_protect(struct heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
|
345
|
+
if (heap_recorder == NULL) {
|
346
|
+
return 0;
|
347
|
+
}
|
348
|
+
|
352
349
|
int exception_state;
|
353
350
|
struct end_heap_allocation_args end_heap_allocation_args = {
|
354
351
|
.heap_recorder = heap_recorder,
|
@@ -364,22 +361,18 @@ static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args) {
|
|
364
361
|
struct heap_recorder *heap_recorder = args->heap_recorder;
|
365
362
|
ddog_prof_Slice_Location locations = args->locations;
|
366
363
|
|
367
|
-
|
368
|
-
return Qnil;
|
369
|
-
}
|
364
|
+
object_record *active_recording = heap_recorder->active_recording;
|
370
365
|
|
371
|
-
|
372
|
-
|
373
|
-
if (active_recording.object_record == NULL) {
|
366
|
+
if (active_recording == NULL) {
|
374
367
|
// Recording ended without having been started?
|
375
368
|
rb_raise(rb_eRuntimeError, "Ended a heap recording that was not started");
|
376
369
|
}
|
377
370
|
// From now on, mark the global active recording as invalid so we can short-circuit at any point
|
378
371
|
// and not end up with a still active recording. the local active_recording still holds the
|
379
372
|
// data required for committing though.
|
380
|
-
heap_recorder->active_recording =
|
373
|
+
heap_recorder->active_recording = NULL;
|
381
374
|
|
382
|
-
if (active_recording
|
375
|
+
if (active_recording == &SKIPPED_RECORD) { // special marker when we decided to skip due to sampling
|
383
376
|
return Qnil;
|
384
377
|
}
|
385
378
|
|
@@ -698,6 +691,7 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
|
|
698
691
|
iteration_data.object_data = record->object_data;
|
699
692
|
iteration_data.locations = (ddog_prof_Slice_Location) {.ptr = locations, .len = stack->frames_len};
|
700
693
|
|
694
|
+
// This is expected to be StackRecorder's add_heap_sample_to_active_profile_without_gvl
|
701
695
|
if (!context->for_each_callback(iteration_data, context->for_each_callback_extra_arg)) {
|
702
696
|
return ST_STOP;
|
703
697
|
}
|
@@ -715,49 +709,35 @@ static int st_object_records_debug(DDTRACE_UNUSED st_data_t key, st_data_t value
|
|
715
709
|
return ST_CONTINUE;
|
716
710
|
}
|
717
711
|
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
// [in] The heap recorder where the update is happening.
|
725
|
-
heap_recorder *heap_recorder;
|
726
|
-
} object_record_update_data;
|
727
|
-
|
728
|
-
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t data, int existing) {
|
729
|
-
object_record_update_data *update_data = (object_record_update_data*) data;
|
730
|
-
recording recording = update_data->recording;
|
731
|
-
object_record *new_object_record = recording.object_record;
|
732
|
-
if (existing) {
|
733
|
-
object_record *existing_record = (object_record*) (*value);
|
734
|
-
|
735
|
-
// This is not supposed to happen, raising...
|
736
|
-
VALUE existing_inspect = object_record_inspect(existing_record);
|
737
|
-
VALUE new_inspect = object_record_inspect(new_object_record);
|
738
|
-
rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
739
|
-
"the same id. previous=%"PRIsVALUE" new=%"PRIsVALUE, existing_inspect, new_inspect);
|
712
|
+
static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t new_object_record, int existing) {
|
713
|
+
if (!existing) {
|
714
|
+
(*value) = (st_data_t) new_object_record; // Expected to be a `object_record *`
|
715
|
+
} else {
|
716
|
+
// If key already existed, we don't touch the existing value, so it can be used for diagnostics
|
740
717
|
}
|
741
|
-
// Always carry on with the update, we want the new record to be there at the end
|
742
|
-
(*value) = (st_data_t) new_object_record;
|
743
718
|
return ST_CONTINUE;
|
744
719
|
}
|
745
720
|
|
746
|
-
static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record,
|
721
|
+
static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, object_record *active_recording) {
|
747
722
|
// Link the object record with the corresponding heap record. This was the last remaining thing we
|
748
723
|
// needed to fully build the object_record.
|
749
|
-
|
724
|
+
active_recording->heap_record = heap_record;
|
750
725
|
if (heap_record->num_tracked_objects == UINT32_MAX) {
|
751
726
|
rb_raise(rb_eRuntimeError, "Reached maximum number of tracked objects for heap record");
|
752
727
|
}
|
753
728
|
heap_record->num_tracked_objects++;
|
754
729
|
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
730
|
+
int existing_error = st_update(heap_recorder->object_records, active_recording->obj_id, update_object_record_entry, (st_data_t) active_recording);
|
731
|
+
if (existing_error) {
|
732
|
+
object_record *existing_record = NULL;
|
733
|
+
st_lookup(heap_recorder->object_records, active_recording->obj_id, (st_data_t *) &existing_record);
|
734
|
+
if (existing_record == NULL) rb_raise(rb_eRuntimeError, "Unexpected NULL when reading existing record");
|
735
|
+
|
736
|
+
VALUE existing_inspect = object_record_inspect(existing_record);
|
737
|
+
VALUE new_inspect = object_record_inspect(active_recording);
|
738
|
+
rb_raise(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
|
739
|
+
"the same id. previous={%"PRIsVALUE"} new={%"PRIsVALUE"}", existing_inspect, new_inspect);
|
740
|
+
}
|
761
741
|
}
|
762
742
|
|
763
743
|
// Struct holding data required for an update operation on heap_records
|
@@ -867,7 +847,6 @@ void heap_record_free(heap_record *record) {
|
|
867
847
|
ruby_xfree(record);
|
868
848
|
}
|
869
849
|
|
870
|
-
|
871
850
|
// =================
|
872
851
|
// Object Record API
|
873
852
|
// =================
|
@@ -917,25 +896,6 @@ VALUE object_record_inspect(object_record *record) {
|
|
917
896
|
// ==============
|
918
897
|
// Heap Frame API
|
919
898
|
// ==============
|
920
|
-
int heap_frame_cmp(heap_frame *f1, heap_frame *f2) {
|
921
|
-
int line_diff = (int) (f1->line - f2->line);
|
922
|
-
if (line_diff != 0) {
|
923
|
-
return line_diff;
|
924
|
-
}
|
925
|
-
int cmp = strcmp(f1->name, f2->name);
|
926
|
-
if (cmp != 0) {
|
927
|
-
return cmp;
|
928
|
-
}
|
929
|
-
return strcmp(f1->filename, f2->filename);
|
930
|
-
}
|
931
|
-
|
932
|
-
// TODO: Research potential performance improvements around hashing stuff here
|
933
|
-
// once we have a benchmarking suite.
|
934
|
-
// Example: Each call to st_hash is calling murmur_finish and we may want
|
935
|
-
// to only finish once per structure, not per field?
|
936
|
-
// Example: There may be a more efficient hashing for line that is not the
|
937
|
-
// generic st_hash algorithm?
|
938
|
-
|
939
899
|
// WARN: Must be kept in-sync with ::char_slice_hash
|
940
900
|
st_index_t string_hash(char *str, st_index_t seed) {
|
941
901
|
return st_hash(str, strlen(str), seed);
|
@@ -971,9 +931,7 @@ st_index_t ddog_location_hash(ddog_prof_Location location, st_index_t seed) {
|
|
971
931
|
heap_stack* heap_stack_new(ddog_prof_Slice_Location locations) {
|
972
932
|
uint16_t frames_len = locations.len;
|
973
933
|
if (frames_len > MAX_FRAMES_LIMIT) {
|
974
|
-
// This
|
975
|
-
// the stacktrace construction mechanism. If it happens, lets just raise. This should
|
976
|
-
// be safe since only allocate with the GVL anyway.
|
934
|
+
// This is not expected as MAX_FRAMES_LIMIT is shared with the stacktrace construction mechanism
|
977
935
|
rb_raise(rb_eRuntimeError, "Found stack with more than %d frames (%d)", MAX_FRAMES_LIMIT, frames_len);
|
978
936
|
}
|
979
937
|
heap_stack *stack = ruby_xcalloc(1, sizeof(heap_stack) + frames_len * sizeof(heap_frame));
|
@@ -17,7 +17,7 @@
|
|
17
17
|
typedef struct heap_recorder heap_recorder;
|
18
18
|
|
19
19
|
// Extra data associated with each live object being tracked.
|
20
|
-
typedef struct
|
20
|
+
typedef struct {
|
21
21
|
// The weight of this object from a sampling perspective.
|
22
22
|
//
|
23
23
|
// A notion of weight is preserved for each tracked object to allow for an approximate
|
@@ -105,7 +105,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder);
|
|
105
105
|
// The sampling weight of this object.
|
106
106
|
//
|
107
107
|
// WARN: It needs to be paired with a ::end_heap_allocation_recording call.
|
108
|
-
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice
|
108
|
+
void start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class);
|
109
109
|
|
110
110
|
// End a previously started heap allocation recording on the heap recorder.
|
111
111
|
//
|
@@ -13,13 +13,13 @@ static VALUE error_symbol = Qnil; // :error in Ruby
|
|
13
13
|
|
14
14
|
static VALUE library_version_string = Qnil;
|
15
15
|
|
16
|
-
struct
|
16
|
+
typedef struct {
|
17
17
|
ddog_prof_Exporter *exporter;
|
18
18
|
ddog_prof_Exporter_Request_BuildResult *build_result;
|
19
19
|
ddog_CancellationToken *cancel_token;
|
20
20
|
ddog_prof_Exporter_SendResult result;
|
21
21
|
bool send_ran;
|
22
|
-
};
|
22
|
+
} call_exporter_without_gvl_arguments;
|
23
23
|
|
24
24
|
static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
|
25
25
|
static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
|
@@ -165,7 +165,7 @@ static VALUE perform_export(
|
|
165
165
|
|
166
166
|
// We'll release the Global VM Lock while we're calling send, so that the Ruby VM can continue to work while this
|
167
167
|
// is pending
|
168
|
-
|
168
|
+
call_exporter_without_gvl_arguments args =
|
169
169
|
{.exporter = exporter, .build_result = &build_result, .cancel_token = cancel_token, .send_ran = false};
|
170
170
|
|
171
171
|
// We use rb_thread_call_without_gvl2 instead of rb_thread_call_without_gvl as the gvl2 variant never raises any
|
@@ -300,7 +300,7 @@ static VALUE _native_do_export(
|
|
300
300
|
}
|
301
301
|
|
302
302
|
static void *call_exporter_without_gvl(void *call_args) {
|
303
|
-
|
303
|
+
call_exporter_without_gvl_arguments *args = (call_exporter_without_gvl_arguments*) call_args;
|
304
304
|
|
305
305
|
args->result = ddog_prof_Exporter_send(args->exporter, &args->build_result->ok, args->cancel_token);
|
306
306
|
args->send_ran = true;
|
@@ -800,3 +800,6 @@ static inline int ddtrace_imemo_type(VALUE imemo) {
|
|
800
800
|
return current_thread;
|
801
801
|
}
|
802
802
|
#endif
|
803
|
+
|
804
|
+
// Is the VM smack in the middle of raising an exception?
|
805
|
+
bool is_raised_flag_set(VALUE thread) { return thread_struct_from_object(thread)->ec->raised_flag > 0; }
|
@@ -18,7 +18,7 @@ typedef struct {
|
|
18
18
|
rb_nativethread_id_t owner;
|
19
19
|
} current_gvl_owner;
|
20
20
|
|
21
|
-
typedef struct
|
21
|
+
typedef struct {
|
22
22
|
union {
|
23
23
|
struct {
|
24
24
|
VALUE iseq;
|
@@ -68,3 +68,5 @@ const char *imemo_kind(VALUE imemo);
|
|
68
68
|
|
69
69
|
#define ENFORCE_THREAD(value) \
|
70
70
|
{ if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, RTYPEDDATA_TYPE(rb_thread_current())))) raise_unexpected_type(value, ADD_QUOTES(value), "Thread", __FILE__, __LINE__, __func__); }
|
71
|
+
|
72
|
+
bool is_raised_flag_set(VALUE thread);
|
@@ -11,6 +11,7 @@
|
|
11
11
|
#include "ruby_helpers.h"
|
12
12
|
#include "setup_signal_handler.h"
|
13
13
|
#include "time_helpers.h"
|
14
|
+
#include "unsafe_api_calls_check.h"
|
14
15
|
|
15
16
|
// Each class/module here is implemented in their separate file
|
16
17
|
void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module);
|
@@ -56,6 +57,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
56
57
|
collectors_thread_context_init(profiling_module);
|
57
58
|
http_transport_init(profiling_module);
|
58
59
|
stack_recorder_init(profiling_module);
|
60
|
+
unsafe_api_calls_check_init();
|
59
61
|
|
60
62
|
// Hosts methods used for testing the native code using RSpec
|
61
63
|
VALUE testing_module = rb_define_module_under(native_extension_module, "Testing");
|
@@ -83,16 +85,16 @@ static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
|
|
83
85
|
return Qtrue;
|
84
86
|
}
|
85
87
|
|
86
|
-
struct
|
88
|
+
typedef struct {
|
87
89
|
VALUE exception_class;
|
88
90
|
char *test_message;
|
89
91
|
int test_message_arg;
|
90
|
-
};
|
92
|
+
} trigger_grab_gvl_and_raise_arguments;
|
91
93
|
|
92
94
|
static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE exception_class, VALUE test_message, VALUE test_message_arg, VALUE release_gvl) {
|
93
95
|
ENFORCE_TYPE(test_message, T_STRING);
|
94
96
|
|
95
|
-
|
97
|
+
trigger_grab_gvl_and_raise_arguments args;
|
96
98
|
|
97
99
|
args.exception_class = exception_class;
|
98
100
|
args.test_message = StringValueCStr(test_message);
|
@@ -108,7 +110,7 @@ static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE except
|
|
108
110
|
}
|
109
111
|
|
110
112
|
static void *trigger_grab_gvl_and_raise(void *trigger_args) {
|
111
|
-
|
113
|
+
trigger_grab_gvl_and_raise_arguments *args = (trigger_grab_gvl_and_raise_arguments *) trigger_args;
|
112
114
|
|
113
115
|
if (args->test_message_arg >= 0) {
|
114
116
|
grab_gvl_and_raise(args->exception_class, "%s%d", args->test_message, args->test_message_arg);
|
@@ -119,16 +121,16 @@ static void *trigger_grab_gvl_and_raise(void *trigger_args) {
|
|
119
121
|
return NULL;
|
120
122
|
}
|
121
123
|
|
122
|
-
struct
|
124
|
+
typedef struct {
|
123
125
|
int syserr_errno;
|
124
126
|
char *test_message;
|
125
127
|
int test_message_arg;
|
126
|
-
};
|
128
|
+
} trigger_grab_gvl_and_raise_syserr_arguments;
|
127
129
|
|
128
130
|
static VALUE _native_grab_gvl_and_raise_syserr(DDTRACE_UNUSED VALUE _self, VALUE syserr_errno, VALUE test_message, VALUE test_message_arg, VALUE release_gvl) {
|
129
131
|
ENFORCE_TYPE(test_message, T_STRING);
|
130
132
|
|
131
|
-
|
133
|
+
trigger_grab_gvl_and_raise_syserr_arguments args;
|
132
134
|
|
133
135
|
args.syserr_errno = NUM2INT(syserr_errno);
|
134
136
|
args.test_message = StringValueCStr(test_message);
|
@@ -144,7 +146,7 @@ static VALUE _native_grab_gvl_and_raise_syserr(DDTRACE_UNUSED VALUE _self, VALUE
|
|
144
146
|
}
|
145
147
|
|
146
148
|
static void *trigger_grab_gvl_and_raise_syserr(void *trigger_args) {
|
147
|
-
|
149
|
+
trigger_grab_gvl_and_raise_syserr_arguments *args = (trigger_grab_gvl_and_raise_syserr_arguments *) trigger_args;
|
148
150
|
|
149
151
|
if (args->test_message_arg >= 0) {
|
150
152
|
grab_gvl_and_raise_syserr(args->syserr_errno, "%s%d", args->test_message, args->test_message_arg);
|
@@ -23,18 +23,18 @@ void ruby_helpers_init(void) {
|
|
23
23
|
|
24
24
|
#define MAX_RAISE_MESSAGE_SIZE 256
|
25
25
|
|
26
|
-
struct
|
26
|
+
typedef struct {
|
27
27
|
VALUE exception_class;
|
28
28
|
char exception_message[MAX_RAISE_MESSAGE_SIZE];
|
29
|
-
};
|
29
|
+
} raise_args;
|
30
30
|
|
31
31
|
static void *trigger_raise(void *raise_arguments) {
|
32
|
-
|
32
|
+
raise_args *args = (raise_args *) raise_arguments;
|
33
33
|
rb_raise(args->exception_class, "%s", args->exception_message);
|
34
34
|
}
|
35
35
|
|
36
36
|
void grab_gvl_and_raise(VALUE exception_class, const char *format_string, ...) {
|
37
|
-
|
37
|
+
raise_args args;
|
38
38
|
|
39
39
|
args.exception_class = exception_class;
|
40
40
|
|
@@ -55,18 +55,18 @@ void grab_gvl_and_raise(VALUE exception_class, const char *format_string, ...) {
|
|
55
55
|
rb_bug("[ddtrace] Unexpected: Reached the end of grab_gvl_and_raise while raising '%s'\n", args.exception_message);
|
56
56
|
}
|
57
57
|
|
58
|
-
struct
|
58
|
+
typedef struct {
|
59
59
|
int syserr_errno;
|
60
60
|
char exception_message[MAX_RAISE_MESSAGE_SIZE];
|
61
|
-
};
|
61
|
+
} syserr_raise_args;
|
62
62
|
|
63
63
|
static void *trigger_syserr_raise(void *syserr_raise_arguments) {
|
64
|
-
|
64
|
+
syserr_raise_args *args = (syserr_raise_args *) syserr_raise_arguments;
|
65
65
|
rb_syserr_fail(args->syserr_errno, args->exception_message);
|
66
66
|
}
|
67
67
|
|
68
68
|
void grab_gvl_and_raise_syserr(int syserr_errno, const char *format_string, ...) {
|
69
|
-
|
69
|
+
syserr_raise_args args;
|
70
70
|
|
71
71
|
args.syserr_errno = syserr_errno;
|
72
72
|
|