-
Notifications
You must be signed in to change notification settings - Fork 372
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3824 from DataDog/ivoanjo/prof-10241-libdatadog-c…
…rashtracker-without-profiling-v2 [PROF-10241] Extract libdatadog crashtracker telemetry into separate extension
- Loading branch information
Showing
26 changed files
with
726 additions
and
354 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
ext/datadog_profiling_native_extension/datadog_ruby_common.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#include "datadog_ruby_common.h" | ||
|
||
// IMPORTANT: Currently this file is copy-pasted between extensions. Make sure to update all versions when doing any change! | ||
|
||
void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name) { | ||
rb_exc_raise( | ||
rb_exc_new_str( | ||
rb_eTypeError, | ||
rb_sprintf("wrong argument %"PRIsVALUE" for '%s' (expected a %s) at %s:%d:in `%s'", | ||
rb_inspect(value), | ||
value_name, | ||
type_name, | ||
file, | ||
line, | ||
function_name | ||
) | ||
) | ||
); | ||
} | ||
|
||
VALUE datadog_gem_version(void) { | ||
VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("Datadog")); | ||
ENFORCE_TYPE(ddtrace_module, T_MODULE); | ||
VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION")); | ||
ENFORCE_TYPE(version_module, T_MODULE); | ||
VALUE version_string = rb_const_get(version_module, rb_intern("STRING")); | ||
ENFORCE_TYPE(version_string, T_STRING); | ||
return version_string; | ||
} | ||
|
||
__attribute__((warn_unused_result)) | ||
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) { | ||
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); | ||
|
||
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); | ||
|
||
return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url)); | ||
} | ||
} | ||
|
||
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 convert tag: %"PRIsVALUE, err_details)); | ||
} | ||
|
||
__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; | ||
} |
57 changes: 57 additions & 0 deletions
57
ext/datadog_profiling_native_extension/datadog_ruby_common.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#pragma once | ||
|
||
// IMPORTANT: Currently this file is copy-pasted between extensions. Make sure to update all versions when doing any change! | ||
|
||
#include <ruby.h> | ||
#include <datadog/profiling.h> | ||
|
||
// Used to mark symbols to be exported to the outside of the extension. | ||
// Consider very carefully before tagging a function with this. | ||
#define DDTRACE_EXPORT __attribute__ ((visibility ("default"))) | ||
|
||
// Used to mark function arguments that are deliberately left unused | ||
#ifdef __GNUC__ | ||
#define DDTRACE_UNUSED __attribute__((unused)) | ||
#else | ||
#define DDTRACE_UNUSED | ||
#endif | ||
|
||
#define ADD_QUOTES_HELPER(x) #x | ||
#define ADD_QUOTES(x) ADD_QUOTES_HELPER(x) | ||
|
||
// Ruby has a Check_Type(value, type) that is roughly equivalent to this BUT Ruby's version is rather cryptic when it fails | ||
// e.g. "wrong argument type nil (expected String)". This is a replacement that prints more information to help debugging. | ||
#define ENFORCE_TYPE(value, type) \ | ||
{ if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); } | ||
|
||
#define ENFORCE_BOOLEAN(value) \ | ||
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); } | ||
|
||
// Called by ENFORCE_TYPE; should not be used directly | ||
NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name)); | ||
|
||
// Helper to retrieve Datadog::VERSION::STRING | ||
VALUE datadog_gem_version(void); | ||
|
||
inline static ddog_CharSlice char_slice_from_ruby_string(VALUE string) { | ||
ENFORCE_TYPE(string, T_STRING); | ||
ddog_CharSlice char_slice = {.ptr = StringValuePtr(string), .len = RSTRING_LEN(string)}; | ||
return char_slice; | ||
} | ||
|
||
__attribute__((warn_unused_result)) | ||
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration); | ||
|
||
__attribute__((warn_unused_result)) | ||
ddog_Vec_Tag convert_tags(VALUE tags_as_array); | ||
|
||
inline static VALUE ruby_string_from_error(const ddog_Error *error) { | ||
ddog_CharSlice char_slice = ddog_Error_message(error); | ||
return rb_str_new(char_slice.ptr, char_slice.len); | ||
} | ||
|
||
inline static VALUE get_error_details_and_drop(ddog_Error *error) { | ||
VALUE result = ruby_string_from_error(error); | ||
ddog_Error_drop(error); | ||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.