datadog 2.17.0 → 2.18.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 +44 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +12 -46
- data/ext/datadog_profiling_native_extension/collectors_stack.c +227 -49
- data/ext/datadog_profiling_native_extension/collectors_stack.h +19 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +63 -12
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +7 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +239 -363
- data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -6
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -3
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -13
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
- data/ext/datadog_profiling_native_extension/stack_recorder.c +154 -57
- data/ext/libdatadog_api/extconf.rb +2 -2
- data/ext/libdatadog_api/library_config.c +54 -12
- data/ext/libdatadog_api/library_config.h +6 -0
- data/ext/libdatadog_api/process_discovery.c +2 -7
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/lru_cache.rb +9 -2
- data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
- data/lib/datadog/appsec/api_security/sampler.rb +59 -0
- data/lib/datadog/appsec/api_security.rb +14 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +257 -85
- data/lib/datadog/appsec/assets/waf_rules/strict.json +10 -78
- data/lib/datadog/appsec/component.rb +30 -54
- data/lib/datadog/appsec/configuration/settings.rb +60 -2
- data/lib/datadog/appsec/context.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +27 -16
- data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
- data/lib/datadog/appsec/remote.rb +15 -55
- data/lib/datadog/appsec/security_engine/engine.rb +194 -0
- data/lib/datadog/appsec/security_engine/runner.rb +10 -11
- data/lib/datadog/appsec.rb +4 -7
- data/lib/datadog/core/configuration/agent_settings.rb +52 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +1 -43
- data/lib/datadog/core/configuration/components.rb +2 -4
- data/lib/datadog/core/configuration/option.rb +9 -9
- data/lib/datadog/core/configuration/settings.rb +22 -10
- data/lib/datadog/core/configuration/stable_config.rb +1 -2
- data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
- data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
- data/lib/datadog/core/process_discovery.rb +5 -1
- data/lib/datadog/core/remote/configuration/repository.rb +12 -0
- data/lib/datadog/core/tag_builder.rb +56 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +1 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +129 -39
- data/lib/datadog/core/telemetry/logger.rb +5 -4
- data/lib/datadog/core/telemetry/logging.rb +11 -5
- data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
- data/lib/datadog/core/transport/http/builder.rb +2 -2
- data/lib/datadog/core/transport/http/env.rb +8 -0
- data/lib/datadog/core/utils.rb +7 -0
- data/lib/datadog/di/instrumenter.rb +52 -2
- data/lib/datadog/di/probe_notification_builder.rb +31 -41
- data/lib/datadog/di/probe_notifier_worker.rb +9 -1
- data/lib/datadog/di/serializer.rb +6 -2
- data/lib/datadog/di/transport/http/input.rb +10 -0
- data/lib/datadog/di/transport/input.rb +10 -2
- data/lib/datadog/profiling/collectors/code_provenance.rb +17 -8
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +16 -1
- data/lib/datadog/profiling/component.rb +7 -9
- data/lib/datadog/profiling/ext.rb +0 -12
- data/lib/datadog/profiling/http_transport.rb +2 -2
- data/lib/datadog/profiling/profiler.rb +2 -0
- data/lib/datadog/profiling/scheduler.rb +2 -1
- data/lib/datadog/profiling/stack_recorder.rb +5 -5
- data/lib/datadog/profiling/tag_builder.rb +5 -37
- data/lib/datadog/profiling/tasks/setup.rb +2 -0
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
- data/lib/datadog/tracing/sync_writer.rb +1 -1
- data/lib/datadog/tracing/trace_operation.rb +12 -4
- data/lib/datadog/tracing/tracer.rb +6 -2
- data/lib/datadog/version.rb +1 -1
- metadata +12 -10
- data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
- data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
- data/lib/datadog/appsec/processor.rb +0 -107
@@ -34,7 +34,7 @@ typedef struct {
|
|
34
34
|
|
35
35
|
// The class of the object that we're tracking.
|
36
36
|
// NOTE: This is optional and will be set to NULL if not set.
|
37
|
-
|
37
|
+
ddog_prof_ManagedStringId class;
|
38
38
|
|
39
39
|
// The GC allocation gen in which we saw this object being allocated.
|
40
40
|
//
|
@@ -59,7 +59,7 @@ typedef struct {
|
|
59
59
|
} heap_recorder_iteration_data;
|
60
60
|
|
61
61
|
// Initialize a new heap recorder.
|
62
|
-
heap_recorder* heap_recorder_new(
|
62
|
+
heap_recorder* heap_recorder_new(ddog_prof_ManagedStringStorage string_storage);
|
63
63
|
|
64
64
|
// Free a previously initialized heap recorder.
|
65
65
|
void heap_recorder_free(heap_recorder *heap_recorder);
|
@@ -164,10 +164,6 @@ VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder);
|
|
164
164
|
|
165
165
|
// v--- TEST-ONLY APIs ---v
|
166
166
|
|
167
|
-
// Assert internal hashing logic is valid for the provided locations and its
|
168
|
-
// corresponding internal representations in heap recorder.
|
169
|
-
void heap_recorder_testonly_assert_hash_matches(ddog_prof_Slice_Location locations);
|
170
|
-
|
171
167
|
// Returns a Ruby string with a representation of internal data helpful to
|
172
168
|
// troubleshoot issues such as unexpected test failures.
|
173
169
|
VALUE heap_recorder_testonly_debug(heap_recorder *heap_recorder);
|
@@ -177,3 +173,5 @@ VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VA
|
|
177
173
|
|
178
174
|
// Used to ensure that a GC actually triggers an update of the objects
|
179
175
|
void heap_recorder_testonly_reset_last_update(heap_recorder *heap_recorder);
|
176
|
+
|
177
|
+
void heap_recorder_testonly_benchmark_intern(heap_recorder *heap_recorder, ddog_CharSlice string, int times, bool use_all);
|
@@ -60,3 +60,25 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
|
|
60
60
|
ddog_Error_drop(error);
|
61
61
|
return error_msg_size;
|
62
62
|
}
|
63
|
+
|
64
|
+
ddog_prof_ManagedStringId intern_or_raise(ddog_prof_ManagedStringStorage string_storage, ddog_CharSlice string) {
|
65
|
+
if (string.len == 0) return (ddog_prof_ManagedStringId) { 0 }; // Id 0 is always an empty string, no need to ask
|
66
|
+
|
67
|
+
ddog_prof_ManagedStringStorageInternResult intern_result = ddog_prof_ManagedStringStorage_intern(string_storage, string);
|
68
|
+
if (intern_result.tag == DDOG_PROF_MANAGED_STRING_STORAGE_INTERN_RESULT_ERR) {
|
69
|
+
rb_raise(rb_eRuntimeError, "Failed to intern string: %"PRIsVALUE, get_error_details_and_drop(&intern_result.err));
|
70
|
+
}
|
71
|
+
return intern_result.ok;
|
72
|
+
}
|
73
|
+
|
74
|
+
void intern_all_or_raise(
|
75
|
+
ddog_prof_ManagedStringStorage string_storage,
|
76
|
+
ddog_prof_Slice_CharSlice strings,
|
77
|
+
ddog_prof_ManagedStringId *output_ids,
|
78
|
+
uintptr_t output_ids_size
|
79
|
+
) {
|
80
|
+
ddog_prof_MaybeError result = ddog_prof_ManagedStringStorage_intern_all(string_storage, strings, output_ids, output_ids_size);
|
81
|
+
if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
|
82
|
+
rb_raise(rb_eRuntimeError, "Failed to intern_all: %"PRIsVALUE, get_error_details_and_drop(&result.some));
|
83
|
+
}
|
84
|
+
}
|
@@ -18,8 +18,11 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
|
|
18
18
|
const char *ruby_value_type_to_string(enum ruby_value_type type);
|
19
19
|
ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
ddog_prof_ManagedStringId intern_or_raise(ddog_prof_ManagedStringStorage string_storage, ddog_CharSlice string);
|
22
|
+
|
23
|
+
void intern_all_or_raise(
|
24
|
+
ddog_prof_ManagedStringStorage string_storage,
|
25
|
+
ddog_prof_Slice_CharSlice strings,
|
26
|
+
ddog_prof_ManagedStringId *output_ids,
|
27
|
+
uintptr_t output_ids_size
|
28
|
+
);
|
@@ -569,6 +569,7 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *st
|
|
569
569
|
|
570
570
|
stack_buffer[i].as.native_frame.caching_cme = (VALUE)cme;
|
571
571
|
stack_buffer[i].as.native_frame.method_id = cme->def->original_id;
|
572
|
+
stack_buffer[i].as.native_frame.function = cme->def->body.cfunc.func;
|
572
573
|
stack_buffer[i].is_ruby_frame = false;
|
573
574
|
i++;
|
574
575
|
}
|
@@ -18,16 +18,19 @@ typedef struct {
|
|
18
18
|
rb_nativethread_id_t owner;
|
19
19
|
} current_gvl_owner;
|
20
20
|
|
21
|
+
// If a sample is kept around for later use, some of its fields need marking. Remember to
|
22
|
+
// update the marking code in `sampling_buffer_mark` if new fields are added.
|
21
23
|
typedef struct {
|
22
24
|
union {
|
23
25
|
struct {
|
24
|
-
VALUE iseq;
|
25
|
-
void *caching_pc; // For caching only
|
26
|
+
VALUE iseq; // Needs marking if kept around
|
27
|
+
void *caching_pc; // For caching validation/invalidation only (does not need marking)
|
26
28
|
int line;
|
27
29
|
} ruby_frame;
|
28
30
|
struct {
|
29
|
-
VALUE caching_cme; // For caching only
|
31
|
+
VALUE caching_cme; // For caching validation/invalidation only (does not need marking)
|
30
32
|
ID method_id;
|
33
|
+
void *function;
|
31
34
|
} native_frame;
|
32
35
|
} as;
|
33
36
|
bool is_ruby_frame : 1;
|
@@ -103,16 +103,6 @@ void raise_syserr(
|
|
103
103
|
}
|
104
104
|
}
|
105
105
|
|
106
|
-
char* ruby_strndup(const char *str, size_t size) {
|
107
|
-
char *dup;
|
108
|
-
|
109
|
-
dup = xmalloc(size + 1);
|
110
|
-
memcpy(dup, str, size);
|
111
|
-
dup[size] = '\0';
|
112
|
-
|
113
|
-
return dup;
|
114
|
-
}
|
115
|
-
|
116
106
|
static VALUE _id2ref(VALUE obj_id) {
|
117
107
|
// Call ::ObjectSpace._id2ref natively. It will raise if the id is no longer valid
|
118
108
|
return rb_funcall(module_object_space, _id2ref_id, 1, obj_id);
|
@@ -122,9 +112,7 @@ static VALUE _id2ref_failure(DDTRACE_UNUSED VALUE _unused1, DDTRACE_UNUSED VALUE
|
|
122
112
|
return Qfalse;
|
123
113
|
}
|
124
114
|
|
125
|
-
//
|
126
|
-
// writes the ref to the value pointer parameter if !NULL. False if id doesn't
|
127
|
-
// reference a valid object (in which case value is not changed).
|
115
|
+
// See notes on header for important details
|
128
116
|
bool ruby_ref_from_id(VALUE obj_id, VALUE *value) {
|
129
117
|
// Call ::ObjectSpace._id2ref natively. It will raise if the id is no longer valid
|
130
118
|
// so we need to call it via rb_rescue2
|
@@ -67,19 +67,11 @@ NORETURN(void raise_syserr(
|
|
67
67
|
const char *function_name
|
68
68
|
));
|
69
69
|
|
70
|
-
// Alternative to ruby_strdup that takes a size argument.
|
71
|
-
// Similar to C's strndup but slightly less smart as size is expected to
|
72
|
-
// be smaller or equal to the real size of str (minus null termination if it
|
73
|
-
// exists).
|
74
|
-
// A new string will be returned with size+1 bytes and last byte set to '\0'.
|
75
|
-
// The returned string must be freed explicitly.
|
76
|
-
//
|
77
|
-
// WARN: Cannot be used during GC or outside the GVL.
|
78
|
-
char* ruby_strndup(const char *str, size_t size);
|
79
|
-
|
80
70
|
// Native wrapper to get an object ref from an id. Returns true on success and
|
81
71
|
// writes the ref to the value pointer parameter if !NULL. False if id doesn't
|
82
72
|
// reference a valid object (in which case value is not changed).
|
73
|
+
//
|
74
|
+
// Note: GVL can be released and other threads may get to run before this method returns
|
83
75
|
bool ruby_ref_from_id(size_t id, VALUE *value);
|
84
76
|
|
85
77
|
// Native wrapper to get the approximate/estimated current size of the passed
|
@@ -196,6 +196,10 @@ typedef struct {
|
|
196
196
|
pthread_mutex_t mutex_slot_two;
|
197
197
|
profile_slot profile_slot_two;
|
198
198
|
|
199
|
+
ddog_prof_ManagedStringStorage string_storage;
|
200
|
+
ddog_prof_ManagedStringId label_key_allocation_class;
|
201
|
+
ddog_prof_ManagedStringId label_key_gc_gen_age;
|
202
|
+
|
199
203
|
short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
|
200
204
|
|
201
205
|
uint8_t position_for[ALL_VALUE_TYPES_COUNT];
|
@@ -230,6 +234,7 @@ typedef struct {
|
|
230
234
|
ddog_prof_Profile_SerializeResult result;
|
231
235
|
long heap_profile_build_time_ns;
|
232
236
|
long serialize_no_gvl_time_ns;
|
237
|
+
ddog_prof_MaybeError advance_gen_result;
|
233
238
|
|
234
239
|
// Set by both
|
235
240
|
bool serialize_ran;
|
@@ -256,7 +261,6 @@ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state
|
|
256
261
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
|
257
262
|
static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
|
258
263
|
static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
|
259
|
-
static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
|
260
264
|
static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
261
265
|
static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
262
266
|
static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
@@ -265,6 +269,8 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns,
|
|
265
269
|
static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE object_id);
|
266
270
|
static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
267
271
|
static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
272
|
+
static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all);
|
273
|
+
static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self);
|
268
274
|
|
269
275
|
void stack_recorder_init(VALUE profiling_module) {
|
270
276
|
VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
@@ -290,7 +296,6 @@ void stack_recorder_init(VALUE profiling_module) {
|
|
290
296
|
rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
|
291
297
|
rb_define_singleton_method(testing_module, "_native_record_endpoint", _native_record_endpoint, 3);
|
292
298
|
rb_define_singleton_method(testing_module, "_native_track_object", _native_track_object, 4);
|
293
|
-
rb_define_singleton_method(testing_module, "_native_check_heap_hashes", _native_check_heap_hashes, 1);
|
294
299
|
rb_define_singleton_method(testing_module, "_native_start_fake_slow_heap_serialization",
|
295
300
|
_native_start_fake_slow_heap_serialization, 1);
|
296
301
|
rb_define_singleton_method(testing_module, "_native_end_fake_slow_heap_serialization",
|
@@ -300,6 +305,8 @@ void stack_recorder_init(VALUE profiling_module) {
|
|
300
305
|
rb_define_singleton_method(testing_module, "_native_is_object_recorded?", _native_is_object_recorded, 2);
|
301
306
|
rb_define_singleton_method(testing_module, "_native_heap_recorder_reset_last_update", _native_heap_recorder_reset_last_update, 1);
|
302
307
|
rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
|
308
|
+
rb_define_singleton_method(testing_module, "_native_benchmark_intern", _native_benchmark_intern, 4);
|
309
|
+
rb_define_singleton_method(testing_module, "_native_test_managed_string_storage_produces_valid_profiles", _native_test_managed_string_storage_produces_valid_profiles, 0);
|
303
310
|
|
304
311
|
ok_symbol = ID2SYM(rb_intern_const("ok"));
|
305
312
|
error_symbol = ID2SYM(rb_intern_const("error"));
|
@@ -334,17 +341,27 @@ static VALUE _native_new(VALUE klass) {
|
|
334
341
|
.serialization_time_ns_min = INT64_MAX,
|
335
342
|
};
|
336
343
|
|
337
|
-
// Note: At this point, slot_one_profile/slot_two_profile contain null pointers. Libdatadog validates pointers
|
344
|
+
// Note: At this point, slot_one_profile/slot_two_profile/string_storage contain null pointers. Libdatadog validates pointers
|
338
345
|
// before using them so it's ok for us to go ahead and create the StackRecorder object.
|
339
346
|
|
340
347
|
VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
|
341
348
|
|
349
|
+
ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
|
350
|
+
|
351
|
+
if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
|
352
|
+
rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
|
353
|
+
}
|
354
|
+
|
355
|
+
state->string_storage = string_storage.ok;
|
356
|
+
state->label_key_allocation_class = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("allocation class"));
|
357
|
+
state->label_key_gc_gen_age = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("gc gen age"));
|
358
|
+
|
359
|
+
initialize_profiles(state, sample_types);
|
360
|
+
|
342
361
|
// NOTE: We initialize this because we want a new recorder to be operational even before #initialize runs and our
|
343
362
|
// default is everything enabled. However, if during recording initialization it turns out we don't want
|
344
363
|
// heap samples, we will free and reset heap_recorder back to NULL.
|
345
|
-
state->heap_recorder = heap_recorder_new();
|
346
|
-
|
347
|
-
initialize_profiles(state, sample_types);
|
364
|
+
state->heap_recorder = heap_recorder_new(state->string_storage);
|
348
365
|
|
349
366
|
return stack_recorder;
|
350
367
|
}
|
@@ -363,7 +380,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
|
|
363
380
|
ddog_Timespec start_timestamp = system_epoch_now_timespec();
|
364
381
|
|
365
382
|
ddog_prof_Profile_NewResult slot_one_profile_result =
|
366
|
-
|
383
|
+
ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
|
367
384
|
|
368
385
|
if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
369
386
|
rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
|
@@ -372,7 +389,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
|
|
372
389
|
state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
|
373
390
|
|
374
391
|
ddog_prof_Profile_NewResult slot_two_profile_result =
|
375
|
-
|
392
|
+
ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
|
376
393
|
|
377
394
|
if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
378
395
|
// Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
|
@@ -393,6 +410,8 @@ static void stack_recorder_typed_data_free(void *state_ptr) {
|
|
393
410
|
|
394
411
|
heap_recorder_free(state->heap_recorder);
|
395
412
|
|
413
|
+
ddog_prof_ManagedStringStorage_drop(state->string_storage);
|
414
|
+
|
396
415
|
ruby_xfree(state);
|
397
416
|
}
|
398
417
|
|
@@ -519,6 +538,8 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
519
538
|
long heap_iteration_prep_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
|
520
539
|
// Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
|
521
540
|
// happen while holding on to the GVL.
|
541
|
+
// NOTE: While rare, it's possible for the GVL to be released inside this function (see comments on `heap_recorder_update`)
|
542
|
+
// and thus don't assume this is an "atomic" step -- other threads may get some running time in the meanwhile.
|
522
543
|
heap_recorder_prepare_iteration(state->heap_recorder);
|
523
544
|
long heap_iteration_prep_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - heap_iteration_prep_start_time_ns;
|
524
545
|
|
@@ -527,7 +548,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
527
548
|
call_serialize_without_gvl_arguments args = {
|
528
549
|
.state = state,
|
529
550
|
.finish_timestamp = finish_timestamp,
|
530
|
-
.serialize_ran = false
|
551
|
+
.serialize_ran = false,
|
531
552
|
};
|
532
553
|
|
533
554
|
while (!args.serialize_ran) {
|
@@ -551,13 +572,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
551
572
|
// really cover the full serialization process but it gives a more useful number since it bypasses
|
552
573
|
// the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
|
553
574
|
// conditions and over which we really have no control about.
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, serialization_time_ns);
|
558
|
-
state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, serialization_time_ns);
|
559
|
-
state->stats_lifetime.serialization_time_ns_total += serialization_time_ns;
|
560
|
-
}
|
575
|
+
state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, args.serialize_no_gvl_time_ns);
|
576
|
+
state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, args.serialize_no_gvl_time_ns);
|
577
|
+
state->stats_lifetime.serialization_time_ns_total += args.serialize_no_gvl_time_ns;
|
561
578
|
|
562
579
|
ddog_prof_Profile_SerializeResult serialized_profile = args.result;
|
563
580
|
|
@@ -566,14 +583,20 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
566
583
|
return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
|
567
584
|
}
|
568
585
|
|
586
|
+
// Note: If we got here, the profile serialized correctly.
|
587
|
+
// Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it and we
|
588
|
+
// can raise exceptions without worrying about leaking the profile.
|
569
589
|
state->stats_lifetime.serialization_successes++;
|
570
|
-
|
571
|
-
// Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it
|
572
590
|
VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
|
573
591
|
|
592
|
+
ddog_prof_MaybeError result = args.advance_gen_result;
|
593
|
+
if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
|
594
|
+
rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&result.some));
|
595
|
+
}
|
596
|
+
|
574
597
|
VALUE start = ruby_time_from(args.slot->start_timestamp);
|
575
598
|
VALUE finish = ruby_time_from(finish_timestamp);
|
576
|
-
VALUE profile_stats = build_profile_stats(args.slot,
|
599
|
+
VALUE profile_stats = build_profile_stats(args.slot, args.serialize_no_gvl_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
|
577
600
|
|
578
601
|
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
|
579
602
|
}
|
@@ -696,18 +719,15 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
|
|
696
719
|
ddog_prof_Label labels[2];
|
697
720
|
size_t label_offset = 0;
|
698
721
|
|
699
|
-
if (object_data->class
|
722
|
+
if (object_data->class.value > 0) {
|
700
723
|
labels[label_offset++] = (ddog_prof_Label) {
|
701
|
-
.
|
702
|
-
.
|
703
|
-
.ptr = object_data->class,
|
704
|
-
.len = strlen(object_data->class),
|
705
|
-
},
|
724
|
+
.key_id = context->state->label_key_allocation_class,
|
725
|
+
.str_id = object_data->class,
|
706
726
|
.num = 0, // This shouldn't be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this
|
707
727
|
};
|
708
728
|
}
|
709
729
|
labels[label_offset++] = (ddog_prof_Label) {
|
710
|
-
.
|
730
|
+
.key_id = context->state->label_key_gc_gen_age,
|
711
731
|
.num = object_data->gen_age,
|
712
732
|
};
|
713
733
|
|
@@ -772,8 +792,9 @@ static void *call_serialize_without_gvl(void *call_args) {
|
|
772
792
|
|
773
793
|
// Note: The profile gets reset by the serialize call
|
774
794
|
args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->slot->start_timestamp, &args->finish_timestamp);
|
795
|
+
args->advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(args->state->string_storage);
|
775
796
|
args->serialize_ran = true;
|
776
|
-
args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
|
797
|
+
args->serialize_no_gvl_time_ns = long_max_of(0, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns);
|
777
798
|
|
778
799
|
return NULL; // Unused
|
779
800
|
}
|
@@ -917,36 +938,6 @@ static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_ins
|
|
917
938
|
return Qtrue;
|
918
939
|
}
|
919
940
|
|
920
|
-
static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations) {
|
921
|
-
ENFORCE_TYPE(locations, T_ARRAY);
|
922
|
-
size_t locations_len = rb_array_len(locations);
|
923
|
-
ddog_prof_Location locations_arr[locations_len];
|
924
|
-
for (size_t i = 0; i < locations_len; i++) {
|
925
|
-
VALUE location = rb_ary_entry(locations, i);
|
926
|
-
ENFORCE_TYPE(location, T_ARRAY);
|
927
|
-
VALUE name = rb_ary_entry(location, 0);
|
928
|
-
VALUE filename = rb_ary_entry(location, 1);
|
929
|
-
VALUE line = rb_ary_entry(location, 2);
|
930
|
-
ENFORCE_TYPE(name, T_STRING);
|
931
|
-
ENFORCE_TYPE(filename, T_STRING);
|
932
|
-
ENFORCE_TYPE(line, T_FIXNUM);
|
933
|
-
locations_arr[i] = (ddog_prof_Location) {
|
934
|
-
.line = line,
|
935
|
-
.function = (ddog_prof_Function) {
|
936
|
-
.name = char_slice_from_ruby_string(name),
|
937
|
-
.filename = char_slice_from_ruby_string(filename),
|
938
|
-
}
|
939
|
-
};
|
940
|
-
}
|
941
|
-
ddog_prof_Slice_Location ddog_locations = {
|
942
|
-
.len = locations_len,
|
943
|
-
.ptr = locations_arr,
|
944
|
-
};
|
945
|
-
heap_recorder_testonly_assert_hash_matches(ddog_locations);
|
946
|
-
|
947
|
-
return Qnil;
|
948
|
-
}
|
949
|
-
|
950
941
|
static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
|
951
942
|
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
|
952
943
|
if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
@@ -1046,3 +1037,109 @@ static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE re
|
|
1046
1037
|
recorder_after_gc_step(recorder_instance);
|
1047
1038
|
return Qtrue;
|
1048
1039
|
}
|
1040
|
+
|
1041
|
+
static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all) {
|
1042
|
+
ENFORCE_TYPE(string, T_STRING);
|
1043
|
+
ENFORCE_TYPE(times, T_FIXNUM);
|
1044
|
+
ENFORCE_BOOLEAN(use_all);
|
1045
|
+
|
1046
|
+
stack_recorder_state *state;
|
1047
|
+
TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
|
1048
|
+
|
1049
|
+
heap_recorder_testonly_benchmark_intern(state->heap_recorder, char_slice_from_ruby_string(string), FIX2INT(times), use_all == Qtrue);
|
1050
|
+
|
1051
|
+
return Qtrue;
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
// See comments in rspec test for details on what we're testing here.
|
1055
|
+
static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self) {
|
1056
|
+
ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
|
1057
|
+
|
1058
|
+
if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
|
1059
|
+
rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
|
1063
|
+
ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
|
1064
|
+
|
1065
|
+
if (profile.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
1066
|
+
rb_raise(rb_eRuntimeError, "Failed to initialize profile: %"PRIsVALUE, get_error_details_and_drop(&profile.err));
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
ddog_prof_ManagedStringId hello = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("hello"));
|
1070
|
+
ddog_prof_ManagedStringId world = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("world"));
|
1071
|
+
ddog_prof_ManagedStringId key = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("key"));
|
1072
|
+
|
1073
|
+
int64_t metric_values[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
1074
|
+
ddog_prof_Label labels[] = {{.key_id = key, .str_id = key}};
|
1075
|
+
|
1076
|
+
ddog_prof_Location locations[] = {
|
1077
|
+
(ddog_prof_Location) {
|
1078
|
+
.mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
|
1079
|
+
.function = {
|
1080
|
+
.name = DDOG_CHARSLICE_C(""),
|
1081
|
+
.name_id = hello,
|
1082
|
+
.filename = DDOG_CHARSLICE_C(""),
|
1083
|
+
.filename_id = world,
|
1084
|
+
},
|
1085
|
+
.line = 1,
|
1086
|
+
}
|
1087
|
+
};
|
1088
|
+
|
1089
|
+
ddog_prof_Profile_Result result = ddog_prof_Profile_add(
|
1090
|
+
&profile.ok,
|
1091
|
+
(ddog_prof_Sample) {
|
1092
|
+
.locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
|
1093
|
+
.values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
|
1094
|
+
.labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
|
1095
|
+
},
|
1096
|
+
0
|
1097
|
+
);
|
1098
|
+
|
1099
|
+
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
1100
|
+
rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
ddog_Timespec finish_timestamp = system_epoch_now_timespec();
|
1104
|
+
ddog_Timespec start_timestamp = {.seconds = finish_timestamp.seconds - 60};
|
1105
|
+
ddog_prof_Profile_SerializeResult serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
|
1106
|
+
|
1107
|
+
if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
|
1108
|
+
rb_raise(rb_eRuntimeError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
ddog_prof_MaybeError advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(string_storage.ok);
|
1112
|
+
|
1113
|
+
if (advance_gen_result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
|
1114
|
+
rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&advance_gen_result.some));
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
VALUE encoded_pprof_1 = from_ddog_prof_EncodedProfile(serialize_result.ok);
|
1118
|
+
|
1119
|
+
result = ddog_prof_Profile_add(
|
1120
|
+
&profile.ok,
|
1121
|
+
(ddog_prof_Sample) {
|
1122
|
+
.locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
|
1123
|
+
.values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
|
1124
|
+
.labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
|
1125
|
+
},
|
1126
|
+
0
|
1127
|
+
);
|
1128
|
+
|
1129
|
+
if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
1130
|
+
rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
|
1134
|
+
|
1135
|
+
if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
|
1136
|
+
rb_raise(rb_eArgError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
VALUE encoded_pprof_2 = from_ddog_prof_EncodedProfile(serialize_result.ok);
|
1140
|
+
|
1141
|
+
ddog_prof_Profile_drop(&profile.ok);
|
1142
|
+
ddog_prof_ManagedStringStorage_drop(string_storage.ok);
|
1143
|
+
|
1144
|
+
return rb_ary_new_from_args(2, encoded_pprof_1, encoded_pprof_2);
|
1145
|
+
}
|
@@ -72,8 +72,8 @@ if ENV['DDTRACE_DEBUG'] == 'true'
|
|
72
72
|
end
|
73
73
|
|
74
74
|
# If we got here, libdatadog is available and loaded
|
75
|
-
ENV['PKG_CONFIG_PATH'] = "#{ENV[
|
76
|
-
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV[
|
75
|
+
ENV['PKG_CONFIG_PATH'] = "#{ENV["PKG_CONFIG_PATH"]}:#{Libdatadog.pkgconfig_folder}"
|
76
|
+
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV["PKG_CONFIG_PATH"].inspect}\n")
|
77
77
|
$stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
|
78
78
|
|
79
79
|
unless pkg_config('datadog_profiling_with_rpath')
|
@@ -7,6 +7,10 @@
|
|
7
7
|
static VALUE _native_configurator_new(VALUE klass);
|
8
8
|
static VALUE _native_configurator_get(VALUE self);
|
9
9
|
|
10
|
+
// Used for testing in RSpec
|
11
|
+
static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
12
|
+
static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path);
|
13
|
+
|
10
14
|
static VALUE config_vec_class = Qnil;
|
11
15
|
|
12
16
|
// ddog_Configurator memory management
|
@@ -52,20 +56,42 @@ void library_config_init(VALUE core_module) {
|
|
52
56
|
rb_define_alloc_func(configurator_class, _native_configurator_new);
|
53
57
|
rb_define_method(configurator_class, "get", _native_configurator_get, 0);
|
54
58
|
|
59
|
+
// Used for testing in RSpec
|
60
|
+
VALUE testing_module = rb_define_module_under(stable_config_module, "Testing");
|
61
|
+
rb_define_singleton_method(testing_module, "with_local_path", _native_configurator_with_local_path, 2);
|
62
|
+
rb_define_singleton_method(testing_module, "with_fleet_path", _native_configurator_with_fleet_path, 2);
|
63
|
+
|
55
64
|
rb_undef_alloc_func(config_vec_class); // It cannot be created from Ruby code and only serves as an intermediate object for the Ruby GC
|
56
65
|
}
|
57
66
|
|
58
|
-
|
59
|
-
static VALUE _native_configurator_new(DDTRACE_UNUSED VALUE _klass) {
|
60
|
-
/*
|
67
|
+
static VALUE _native_configurator_new(VALUE klass) {
|
61
68
|
ddog_Configurator *configurator = ddog_library_configurator_new(false, DDOG_CHARSLICE_C("ruby"));
|
62
69
|
|
63
70
|
ddog_library_configurator_with_detect_process_info(configurator);
|
64
71
|
|
65
72
|
return TypedData_Wrap_Struct(klass, &configurator_typed_data, configurator);
|
66
|
-
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE _native_configurator_with_local_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
|
76
|
+
ddog_Configurator *configurator;
|
77
|
+
TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
|
78
|
+
|
79
|
+
ENFORCE_TYPE(path, T_STRING);
|
67
80
|
|
68
|
-
|
81
|
+
ddog_library_configurator_with_local_path(configurator, cstr_from_ruby_string(path));
|
82
|
+
|
83
|
+
return Qnil;
|
84
|
+
}
|
85
|
+
|
86
|
+
static VALUE _native_configurator_with_fleet_path(DDTRACE_UNUSED VALUE _self, VALUE rb_configurator, VALUE path) {
|
87
|
+
ddog_Configurator *configurator;
|
88
|
+
TypedData_Get_Struct(rb_configurator, ddog_Configurator, &configurator_typed_data, configurator);
|
89
|
+
|
90
|
+
ENFORCE_TYPE(path, T_STRING);
|
91
|
+
|
92
|
+
ddog_library_configurator_with_fleet_path(configurator, cstr_from_ruby_string(path));
|
93
|
+
|
94
|
+
return Qnil;
|
69
95
|
}
|
70
96
|
|
71
97
|
static VALUE _native_configurator_get(VALUE self) {
|
@@ -96,26 +122,42 @@ static VALUE _native_configurator_get(VALUE self) {
|
|
96
122
|
|
97
123
|
VALUE local_config_hash = rb_hash_new();
|
98
124
|
VALUE fleet_config_hash = rb_hash_new();
|
99
|
-
|
100
|
-
|
125
|
+
|
126
|
+
bool local_config_id_set = false;
|
127
|
+
bool fleet_config_id_set = false;
|
128
|
+
VALUE local_hash = rb_hash_new();
|
129
|
+
VALUE fleet_hash = rb_hash_new();
|
101
130
|
for (uintptr_t i = 0; i < config_vec->len; i++) {
|
102
131
|
ddog_LibraryConfig config = config_vec->ptr[i];
|
103
132
|
VALUE selected_hash;
|
104
133
|
if (config.source == DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG) {
|
105
134
|
selected_hash = local_config_hash;
|
135
|
+
if (!local_config_id_set) {
|
136
|
+
local_config_id_set = true;
|
137
|
+
if (config.config_id.length > 0) {
|
138
|
+
rb_hash_aset(local_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
|
139
|
+
}
|
140
|
+
}
|
106
141
|
}
|
107
142
|
else {
|
108
143
|
selected_hash = fleet_config_hash;
|
144
|
+
if (!fleet_config_id_set) {
|
145
|
+
fleet_config_id_set = true;
|
146
|
+
if (config.config_id.length > 0) {
|
147
|
+
rb_hash_aset(fleet_hash, ID2SYM(rb_intern("id")), rb_utf8_str_new_cstr(config.config_id.ptr));
|
148
|
+
}
|
149
|
+
}
|
109
150
|
}
|
110
151
|
|
111
|
-
|
112
|
-
rb_hash_aset(selected_hash, rb_str_new(name.ptr, name.length), rb_str_new(config.value.ptr, config.value.length));
|
152
|
+
rb_hash_aset(selected_hash, rb_utf8_str_new_cstr(config.name.ptr), rb_utf8_str_new_cstr(config.value.ptr));
|
113
153
|
}
|
114
|
-
|
154
|
+
|
155
|
+
rb_hash_aset(local_hash, ID2SYM(rb_intern("config")), local_config_hash);
|
156
|
+
rb_hash_aset(fleet_hash, ID2SYM(rb_intern("config")), fleet_config_hash);
|
115
157
|
|
116
158
|
VALUE result = rb_hash_new();
|
117
|
-
rb_hash_aset(result, ID2SYM(rb_intern("local")),
|
118
|
-
rb_hash_aset(result, ID2SYM(rb_intern("fleet")),
|
159
|
+
rb_hash_aset(result, ID2SYM(rb_intern("local")), local_hash);
|
160
|
+
rb_hash_aset(result, ID2SYM(rb_intern("fleet")), fleet_hash);
|
119
161
|
|
120
162
|
RB_GC_GUARD(config_vec_rb);
|
121
163
|
return result;
|
@@ -17,3 +17,9 @@ static inline VALUE log_warning_without_config(VALUE warning) {
|
|
17
17
|
|
18
18
|
return rb_funcall(logger, rb_intern("warn"), 1, warning);
|
19
19
|
}
|
20
|
+
|
21
|
+
static inline ddog_CStr cstr_from_ruby_string(VALUE string) {
|
22
|
+
ENFORCE_TYPE(string, T_STRING);
|
23
|
+
ddog_CStr cstr = {.ptr = RSTRING_PTR(string), .length = RSTRING_LEN(string)};
|
24
|
+
return cstr;
|
25
|
+
}
|