-
Notifications
You must be signed in to change notification settings - Fork 375
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-10241] Extract libdatadog crashtracker telemetry into separate extension #3824
Changes from all commits
94fc941
bea50c9
ed05c7b
4f8f500
5a8bec6
0bf005d
3342c52
eabcb38
587d535
28ebaa7
85b1d8b
f051a0f
f0a17d2
7037bdb
b7dc64d
7448a21
5f6580d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These things got moved over from other helper files and put together here, they're mostly unchanged. |
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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,17 +2,6 @@ | |
|
||
#include <stdint.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 | ||
|
||
Comment on lines
-5
to
-15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to datadog_ruby_common.h |
||
// @ivoanjo: After trying to read through https://stackoverflow.com/questions/3437404/min-and-max-in-c I decided I | ||
// don't like C and I just implemented this as a function. | ||
inline static uint64_t uint64_max_of(uint64_t a, uint64_t b) { return a > b ? a : b; } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to datadog_ruby_common.c |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to datadog_ruby_common.h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These things got moved over from other helper files and put together here, they're mostly unchanged.