Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PROF-8917] Add support for the libdatadog crash tracker #3384

Merged
merged 48 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e1340de
Introduce setting to control crash tracker option
ivoanjo Jan 16, 2024
789db6b
Extract `convert_tags` and `endpoint_from` from `HttpTransport` to li…
ivoanjo Jan 16, 2024
8afc9f2
Extract `ddtrace_version` from `HttpTransport` to `ruby_helpers.h`
ivoanjo Jan 16, 2024
a9c51b0
[PROF-8917] Add support for the libdatadog crash tracker
ivoanjo Jan 16, 2024
d89e876
Add TODO about integration spec
ivoanjo Jan 16, 2024
d3bc290
Update `crash_tracker.c` with latest libdatadog API
ivoanjo Mar 11, 2024
4889d05
Add experimental spec
ivoanjo Mar 11, 2024
37f8082
Minor: Remove unused/outdated type declaration
ivoanjo Mar 11, 2024
18758de
Redesign crash tracker to behave as regular object
ivoanjo Mar 11, 2024
02d8691
Merge branch 'master' into ivoanjo/prof-8917-crash-tracker-ruby
ivoanjo Mar 12, 2024
bc7d72c
Wire new crash tracker design into profiler
ivoanjo Mar 12, 2024
5312591
Minor: Remove redundant log message
ivoanjo Mar 12, 2024
45f5daa
Avoid leaking threads and outputting errors during spec
ivoanjo Mar 12, 2024
a5c0ba2
Rename CrashTracker to Crashtracker to match libdatadog naming
ivoanjo Mar 12, 2024
fb45524
Match fixed case for crashtracker APIs
ivoanjo Mar 12, 2024
6f83a4a
Merge branch 'master' into ivoanjo/prof-8917-crash-tracker-ruby
ivoanjo Mar 12, 2024
6af57da
Update to libdatadog 7 APIs
ivoanjo Mar 22, 2024
d19ecde
Merge branch 'master' into ivoanjo/prof-8917-crash-tracker-ruby
ivoanjo Mar 22, 2024
e670699
Enable frame resolution
ivoanjo Mar 22, 2024
d37cbb8
Use in-receiver resolve frames
ivoanjo Mar 28, 2024
d8b4122
Merge branch 'master' into ivoanjo/prof-8917-crash-tracker-ruby
ivoanjo Apr 3, 2024
6f3f8be
Adjust to latest libdatadog crash tracker changes
ivoanjo Apr 3, 2024
66e8d95
Remove TODO, it's fixed now
ivoanjo Apr 3, 2024
ce15ade
Add detail to explaining why alt stack can't be used
ivoanjo Apr 4, 2024
1b501cc
Clarify section of method where exceptions mustn't be raised
ivoanjo Apr 4, 2024
bd0537e
Document that crashtracker state is a singleton
ivoanjo Apr 4, 2024
0b40fbf
Avoid hardcoding ports when testing with built-in webrick
ivoanjo Apr 4, 2024
a3081b4
Add test coverage for crashtracker surviving in `#component_failed`
ivoanjo Apr 4, 2024
680c4a3
[NO-TICKET] Upgrade to libdatadog 8
ivoanjo Apr 9, 2024
32f02b4
Update gemfiles with libdatadog 7 -> 8 upgrade
ivoanjo Apr 9, 2024
356002e
Merge branch 'ivoanjo/libdatadog8-upgrade' into ivoanjo/prof-8917-cra…
ivoanjo Apr 9, 2024
7776107
[NO-TICKET] Upgrade to libdatadog 9
AlexJF May 6, 2024
520c8ab
Restore `required_ruby_version` to be in single line, but make Ruboco…
ivoanjo May 9, 2024
a6ddf72
Minor cleanups to comments
ivoanjo May 9, 2024
3c27b38
Minor: Fix length of guide comment for breaking lines in message
ivoanjo May 9, 2024
ed971a5
Revert "[NO-TICKET] Upgrade to libdatadog 8"
ivoanjo May 9, 2024
f029683
Revert "Update gemfiles with libdatadog 7 -> 8 upgrade"
ivoanjo May 9, 2024
7083455
Merge branch 'alexjf/libdatadog9' into ivoanjo/prof-8917-crash-tracke…
ivoanjo May 9, 2024
49e9f31
Update Ruby crashtracker to libdatadog v9 API
ivoanjo May 9, 2024
5197792
Setup `ld_library_path` argument for crashtracker
ivoanjo May 9, 2024
7cda332
Use `profiling.upload.timeout_seconds` for crashtracker timeout
ivoanjo May 9, 2024
b87f171
Remove temporary libdatadog monkey patch
ivoanjo May 9, 2024
3acf413
Fix `upload_timeout_seconds` being a float by default
ivoanjo May 9, 2024
bd7de08
Make rubocop happy
ivoanjo May 9, 2024
09976cc
Minor: Add explanation for why we're skipping crash tracker with cust…
ivoanjo May 10, 2024
5431d2b
Assert that no crashtracker is running before each test
ivoanjo May 10, 2024
a2ae730
Assert that correct signal name is reported
ivoanjo May 10, 2024
42f6ca5
Minor: Empty commit to re-trigger CI
ivoanjo May 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 5 additions & 4 deletions datadog.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
# DEV: Loading gem files here is undesirable because it pollutes the application namesspace.
# DEV: Loading gem files here is undesirable because it pollutes the application namespace.
# DEV: In this case, `bundle exec ruby -e 'puts defined?(Datadog)'` will return `constant`
# DEV: even though `require 'datadog'` wasn't executed. But only the version file was loaded.
# DEV: We should avoid loading gem files to fetch the version here.
Expand All @@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
spec.name = 'datadog'
spec.version = Datadog::VERSION::STRING
# required_ruby_version should be in a single line due to test-head workflow `sed` to unlock the version
spec.required_ruby_version = [">= #{Datadog::VERSION::MINIMUM_RUBY_VERSION}", "< #{Datadog::VERSION::MAXIMUM_RUBY_VERSION}"]
spec.required_ruby_version = [">= #{Datadog::VERSION::MINIMUM_RUBY_VERSION}", "< #{Datadog::VERSION::MAXIMUM_RUBY_VERSION}"] # rubocop:disable Layout/LineLength
spec.required_rubygems_version = '>= 2.0.0'
spec.authors = ['Datadog, Inc.']
spec.email = ['dev@datadoghq.com']
Expand Down Expand Up @@ -69,8 +69,9 @@ Gem::Specification.new do |spec|
spec.add_dependency 'libddwaf', '~> 1.14.0.0.0'

# Used by profiling (and possibly others in the future)
# When updating the version here, please also update the version in `native_extension_helpers.rb` (and yes we have a test for it)
spec.add_dependency 'libdatadog', '~> 7.0.0.1.0'
# When updating the version here, please also update the version in `native_extension_helpers.rb`
# (and yes we have a test for it)
spec.add_dependency 'libdatadog', '~> 9.0.0.1.0'

spec.extensions = ['ext/datadog_profiling_native_extension/extconf.rb', 'ext/datadog_profiling_loader/extconf.rb']
end
108 changes: 108 additions & 0 deletions ext/datadog_profiling_native_extension/crashtracker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include <ruby.h>
#include <datadog/common.h>
#include <libdatadog_helpers.h>

static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self);

// Used to report Ruby VM crashes.
// Once initialized, segfaults will be reported automatically using libdatadog.

void crashtracker_init(VALUE profiling_module) {
VALUE crashtracker_class = rb_define_class_under(profiling_module, "Crashtracker", rb_cObject);

rb_define_singleton_method(crashtracker_class, "_native_start_or_update_on_fork", _native_start_or_update_on_fork, -1);
rb_define_singleton_method(crashtracker_class, "_native_stop", _native_stop, 0);
}

static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
VALUE options;
rb_scan_args(argc, argv, "0:", &options);

VALUE exporter_configuration = rb_hash_fetch(options, ID2SYM(rb_intern("exporter_configuration")));
VALUE path_to_crashtracking_receiver_binary = rb_hash_fetch(options, ID2SYM(rb_intern("path_to_crashtracking_receiver_binary")));
VALUE ld_library_path = rb_hash_fetch(options, ID2SYM(rb_intern("ld_library_path")));
VALUE tags_as_array = rb_hash_fetch(options, ID2SYM(rb_intern("tags_as_array")));
VALUE action = rb_hash_fetch(options, ID2SYM(rb_intern("action")));
VALUE upload_timeout_seconds = rb_hash_fetch(options, ID2SYM(rb_intern("upload_timeout_seconds")));

VALUE start_action = ID2SYM(rb_intern("start"));
VALUE update_on_fork_action = ID2SYM(rb_intern("update_on_fork"));

ENFORCE_TYPE(exporter_configuration, T_ARRAY);
ENFORCE_TYPE(tags_as_array, T_ARRAY);
ENFORCE_TYPE(path_to_crashtracking_receiver_binary, T_STRING);
ENFORCE_TYPE(ld_library_path, T_STRING);
ENFORCE_TYPE(action, T_SYMBOL);
ENFORCE_TYPE(upload_timeout_seconds, T_FIXNUM);

if (action != start_action && action != update_on_fork_action) rb_raise(rb_eArgError, "Unexpected action: %+"PRIsVALUE, action);

VALUE version = ddtrace_version();
ddog_prof_Endpoint endpoint = endpoint_from(exporter_configuration);

// Tags are heap-allocated, so after here we can't raise exceptions otherwise we'll leak this memory
// Start of exception-free zone to prevent leaks {{
ddog_Vec_Tag tags = convert_tags(tags_as_array);

ddog_prof_CrashtrackerConfiguration config = {
.additional_files = {},
// The Ruby VM already uses an alt stack to detect stack overflows so the crash handler must not overwrite it.
//
// @ivoanjo: Specifically, with `create_alt_stack = true` I saw a segfault, such as Ruby 2.6's bug with
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, this is why this is an option here :)

// "Process.detach(fork { exit! }).instance_variable_get(:@foo)" being turned into a
// "-e:1:in `instance_variable_get': stack level too deep (SystemStackError)" by Ruby.
//
// The Ruby crash handler also seems to get confused when this option is enabled and
// "Process.kill('SEGV', Process.pid)" gets run.
.create_alt_stack = false,
.endpoint = endpoint,
.resolve_frames = DDOG_PROF_STACKTRACE_COLLECTION_ENABLED,
.timeout_secs = FIX2INT(upload_timeout_seconds),
};

ddog_prof_CrashtrackerMetadata metadata = {
.profiling_library_name = DDOG_CHARSLICE_C("dd-trace-rb"),
.profiling_library_version = char_slice_from_ruby_string(version),
.family = DDOG_CHARSLICE_C("ruby"),
.tags = &tags,
};

ddog_prof_EnvVar ld_library_path_env = {
.key = DDOG_CHARSLICE_C("LD_LIBRARY_PATH"),
.val = char_slice_from_ruby_string(ld_library_path),
};

ddog_prof_CrashtrackerReceiverConfig receiver_config = {
.args = {},
.env = {.ptr = &ld_library_path_env, .len = 1},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might override the env rather than appending. Which would you expect to happen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question -- I don't particularly have a preference.

On one side, inheriting the full env would be useful if the crash tracker wanted to log some extra info from there. On the other hand, we can always add anything else we want extra later.

Dealer's choice? Do you think it'd be useful for me to pass along the env that Ruby has + with the addition of the ld_library_path?

.path_to_receiver_binary = char_slice_from_ruby_string(path_to_crashtracking_receiver_binary),
.optional_stderr_filename = {},
.optional_stdout_filename = {},
};

ddog_prof_CrashtrackerResult result =
action == start_action ?
ddog_prof_Crashtracker_init(config, receiver_config, metadata) :
ddog_prof_Crashtracker_update_on_fork(config, receiver_config, metadata);

// Clean up before potentially raising any exceptions
ddog_Vec_Tag_drop(tags);
ivoanjo marked this conversation as resolved.
Show resolved Hide resolved
// }} End of exception-free zone to prevent leaks

if (result.tag == DDOG_PROF_CRASHTRACKER_RESULT_ERR) {
rb_raise(rb_eRuntimeError, "Failed to start/update the crash tracker: %"PRIsVALUE, get_error_details_and_drop(&result.err));
}

return Qtrue;
}

static VALUE _native_stop(DDTRACE_UNUSED VALUE _self) {
ddog_prof_CrashtrackerResult result = ddog_prof_Crashtracker_shutdown();

if (result.tag == DDOG_PROF_CRASHTRACKER_RESULT_ERR) {
rb_raise(rb_eRuntimeError, "Failed to stop the crash tracker: %"PRIsVALUE, get_error_details_and_drop(&result.err));
}

return Qtrue;
}
93 changes: 0 additions & 93 deletions ext/datadog_profiling_native_extension/http_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
static VALUE ok_symbol = Qnil; // :ok in Ruby
static VALUE error_symbol = Qnil; // :error in Ruby

static ID agentless_id; // id of :agentless in Ruby
static ID agent_id; // id of :agent in Ruby

static ID log_failure_to_process_tag_id; // id of :log_failure_to_process_tag in Ruby

static VALUE library_version_string = Qnil;

struct call_exporter_without_gvl_arguments {
Expand All @@ -30,9 +25,6 @@ inline static ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);
static ddog_Vec_Tag convert_tags(VALUE tags_as_array);
static void safely_log_failure_to_process_tag(ddog_Vec_Tag tags, VALUE err_details);
static VALUE _native_do_export(
VALUE self,
VALUE exporter_configuration,
Expand Down Expand Up @@ -60,9 +52,6 @@ void http_transport_init(VALUE profiling_module) {

ok_symbol = ID2SYM(rb_intern_const("ok"));
error_symbol = ID2SYM(rb_intern_const("error"));
agentless_id = rb_intern_const("agentless");
agent_id = rb_intern_const("agent");
log_failure_to_process_tag_id = rb_intern_const("log_failure_to_process_tag");

library_version_string = ddtrace_version();
rb_global_variable(&library_version_string);
Expand Down Expand Up @@ -116,88 +105,6 @@ static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_resul
rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&exporter_result.err));
}

static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
ENFORCE_TYPE(exporter_configuration, T_ARRAY);

ID working_mode = SYM2ID(rb_ary_entry(exporter_configuration, 0)); // SYM2ID verifies its input so we can do this safely

if (working_mode != agentless_id && working_mode != agent_id) {
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
}

if (working_mode == agentless_id) {
VALUE site = rb_ary_entry(exporter_configuration, 1);
VALUE api_key = rb_ary_entry(exporter_configuration, 2);
ENFORCE_TYPE(site, T_STRING);
ENFORCE_TYPE(api_key, T_STRING);

return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
} else { // agent_id
VALUE base_url = rb_ary_entry(exporter_configuration, 1);
ENFORCE_TYPE(base_url, T_STRING);

return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
}
}

__attribute__((warn_unused_result))
static ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
ENFORCE_TYPE(tags_as_array, T_ARRAY);

long tags_count = RARRAY_LEN(tags_as_array);
ddog_Vec_Tag tags = ddog_Vec_Tag_new();

for (long i = 0; i < tags_count; i++) {
VALUE name_value_pair = rb_ary_entry(tags_as_array, i);

if (!RB_TYPE_P(name_value_pair, T_ARRAY)) {
ddog_Vec_Tag_drop(tags);
ENFORCE_TYPE(name_value_pair, T_ARRAY);
}

// Note: We can index the array without checking its size first because rb_ary_entry returns Qnil if out of bounds
VALUE tag_name = rb_ary_entry(name_value_pair, 0);
VALUE tag_value = rb_ary_entry(name_value_pair, 1);

if (!(RB_TYPE_P(tag_name, T_STRING) && RB_TYPE_P(tag_value, T_STRING))) {
ddog_Vec_Tag_drop(tags);
ENFORCE_TYPE(tag_name, T_STRING);
ENFORCE_TYPE(tag_value, T_STRING);
}

ddog_Vec_Tag_PushResult push_result =
ddog_Vec_Tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));

if (push_result.tag == DDOG_VEC_TAG_PUSH_RESULT_ERR) {
// libdatadog validates tags and may catch invalid tags that ddtrace didn't actually catch.
// We warn users about such tags, and then just ignore them.
safely_log_failure_to_process_tag(tags, get_error_details_and_drop(&push_result.err));
}
}

return tags;
}

static VALUE log_failure_to_process_tag(VALUE err_details) {
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
VALUE profiling_module = rb_const_get(datadog_module, rb_intern("Profiling"));
VALUE http_transport_class = rb_const_get(profiling_module, rb_intern("HttpTransport"));

return rb_funcall(http_transport_class, log_failure_to_process_tag_id, 1, err_details);
}

// Since we are calling into Ruby code, it may raise an exception. This method ensure that dynamically-allocated tags
// get cleaned before propagating the exception.
static void safely_log_failure_to_process_tag(ddog_Vec_Tag tags, VALUE err_details) {
int exception_state;
rb_protect(log_failure_to_process_tag, err_details, &exception_state);

if (exception_state) { // An exception was raised
ddog_Vec_Tag_drop(tags); // clean up
rb_jump_tag(exception_state); // "Re-raise" exception
}
}

// Note: This function handles a bunch of libdatadog dynamically-allocated objects, so it MUST not use any Ruby APIs
// which can raise exceptions, otherwise the objects will be leaked.
static VALUE perform_export(
Expand Down
86 changes: 86 additions & 0 deletions ext/datadog_profiling_native_extension/libdatadog_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <ruby.h>

static VALUE log_failure_to_process_tag(VALUE err_details);

const char *ruby_value_type_to_string(enum ruby_value_type type) {
return ruby_value_type_to_char_slice(type).ptr;
}
Expand Down Expand Up @@ -60,3 +62,87 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
ddog_Error_drop(error);
return error_msg_size;
}

__attribute__((warn_unused_result))
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you want a way to send to file endpoints?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can imagine some uses for it in some weird debugging cases... 🤔

From my side, I'm fine with not having that ability, so I don't particularly think it's worth the effort.

ENFORCE_TYPE(exporter_configuration, T_ARRAY);

VALUE exporter_working_mode = rb_ary_entry(exporter_configuration, 0);
ENFORCE_TYPE(exporter_working_mode, T_SYMBOL);
ID working_mode = SYM2ID(exporter_working_mode);

ID agentless_id = rb_intern("agentless");
ID agent_id = rb_intern("agent");

if (working_mode != agentless_id && working_mode != agent_id) {
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
}

if (working_mode == agentless_id) {
VALUE site = rb_ary_entry(exporter_configuration, 1);
VALUE api_key = rb_ary_entry(exporter_configuration, 2);
ENFORCE_TYPE(site, T_STRING);
ENFORCE_TYPE(api_key, T_STRING);

return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
} else { // agent_id
VALUE base_url = rb_ary_entry(exporter_configuration, 1);
ENFORCE_TYPE(base_url, T_STRING);

return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
}
}

__attribute__((warn_unused_result))
ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
ENFORCE_TYPE(tags_as_array, T_ARRAY);

long tags_count = RARRAY_LEN(tags_as_array);
ddog_Vec_Tag tags = ddog_Vec_Tag_new();

for (long i = 0; i < tags_count; i++) {
VALUE name_value_pair = rb_ary_entry(tags_as_array, i);

if (!RB_TYPE_P(name_value_pair, T_ARRAY)) {
ddog_Vec_Tag_drop(tags);
ENFORCE_TYPE(name_value_pair, T_ARRAY);
}

// Note: We can index the array without checking its size first because rb_ary_entry returns Qnil if out of bounds
VALUE tag_name = rb_ary_entry(name_value_pair, 0);
VALUE tag_value = rb_ary_entry(name_value_pair, 1);

if (!(RB_TYPE_P(tag_name, T_STRING) && RB_TYPE_P(tag_value, T_STRING))) {
ddog_Vec_Tag_drop(tags);
ENFORCE_TYPE(tag_name, T_STRING);
ENFORCE_TYPE(tag_value, T_STRING);
}

ddog_Vec_Tag_PushResult push_result =
ddog_Vec_Tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));

if (push_result.tag == DDOG_VEC_TAG_PUSH_RESULT_ERR) {
// libdatadog validates tags and may catch invalid tags that ddtrace didn't actually catch.
// We warn users about such tags, and then just ignore them.

int exception_state;
rb_protect(log_failure_to_process_tag, get_error_details_and_drop(&push_result.err), &exception_state);

// Since we are calling into Ruby code, it may raise an exception. Ensure that dynamically-allocated tags
// get cleaned before propagating the exception.
if (exception_state) {
ddog_Vec_Tag_drop(tags);
rb_jump_tag(exception_state); // "Re-raise" exception
}
}
}

return tags;
}

static VALUE log_failure_to_process_tag(VALUE err_details) {
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);

return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to add tag to profiling request: %"PRIsVALUE, err_details));
}
4 changes: 4 additions & 0 deletions ext/datadog_profiling_native_extension/libdatadog_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ ddog_CharSlice ruby_value_type_to_char_slice(enum ruby_value_type type);
inline static char* string_from_char_slice(ddog_CharSlice slice) {
return ruby_strndup(slice.ptr, slice.len);
}

ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);

ddog_Vec_Tag convert_tags(VALUE tags_as_array);
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module NativeExtensionHelpers
# The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on debase-ruby_core_source
CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?('2.6', '2.7', '3.0.', '3.1.', '3.2.')

LIBDATADOG_VERSION = '~> 7.0.0.1.0'
LIBDATADOG_VERSION = '~> 9.0.0.1.0'

def self.fail_install_if_missing_extension?
ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == 'true'
Expand Down Expand Up @@ -165,7 +165,7 @@ def self.pkg_config_missing?(command: $PKGCONFIG) # rubocop:disable Style/Global

# Validation for this check is done in extconf.rb because it relies on mkmf
PKG_CONFIG_IS_MISSING = explain_issue(
#+-----------------------------------------------------------------------------+
# ----------------------------------------------------------------------------+
'the `pkg-config` system tool is missing.',
'This issue can usually be fixed by installing one of the following:',
'the `pkg-config` package on Homebrew and Debian/Ubuntu-based Linux;',
Expand Down
2 changes: 2 additions & 0 deletions ext/datadog_profiling_native_extension/profiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void collectors_dynamic_sampling_rate_init(VALUE profiling_module);
void collectors_idle_sampling_helper_init(VALUE profiling_module);
void collectors_stack_init(VALUE profiling_module);
void collectors_thread_context_init(VALUE profiling_module);
void crashtracker_init(VALUE profiling_module);
void http_transport_init(VALUE profiling_module);
void stack_recorder_init(VALUE profiling_module);

Expand Down Expand Up @@ -53,6 +54,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
collectors_idle_sampling_helper_init(profiling_module);
collectors_stack_init(profiling_module);
collectors_thread_context_init(profiling_module);
crashtracker_init(profiling_module);
http_transport_init(profiling_module);
stack_recorder_init(profiling_module);

Expand Down
Loading
Loading