datadog 2.1.0 → 2.3.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 +101 -1
- data/ext/datadog_profiling_loader/extconf.rb +15 -15
- data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +132 -44
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
- data/ext/datadog_profiling_native_extension/collectors_stack.c +90 -37
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +69 -62
- data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
- data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
- data/ext/datadog_profiling_native_extension/helpers.h +6 -17
- data/ext/datadog_profiling_native_extension/http_transport.c +3 -3
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -126
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -138
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
- data/ext/datadog_profiling_native_extension/profiling.c +0 -2
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +27 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
- data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
- data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +20 -7
- data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +57 -0
- data/ext/libdatadog_api/extconf.rb +108 -0
- data/ext/libdatadog_api/macos_development.md +26 -0
- data/ext/libdatadog_extconf_helpers.rb +130 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +49 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
- data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
- data/lib/datadog/appsec/extensions.rb +1 -0
- data/lib/datadog/appsec/processor/actions.rb +1 -1
- data/lib/datadog/appsec/response.rb +15 -1
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +17 -12
- data/lib/datadog/core/configuration/settings.rb +93 -7
- data/lib/datadog/core/configuration.rb +3 -17
- data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
- data/lib/datadog/core/crashtracking/component.rb +111 -0
- data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
- data/lib/datadog/core/deprecations.rb +58 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +6 -0
- data/lib/datadog/core/telemetry/component.rb +154 -0
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +132 -26
- data/lib/datadog/core/telemetry/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +11 -13
- data/lib/datadog/core/telemetry/http/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/transport.rb +38 -9
- data/lib/datadog/core/telemetry/logging.rb +35 -0
- data/lib/datadog/core/telemetry/metric.rb +167 -0
- data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
- data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/core/telemetry/worker.rb +173 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/core/utils/only_once_successful.rb +76 -0
- data/lib/datadog/core.rb +2 -19
- data/lib/datadog/kit/appsec/events.rb +2 -4
- data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +15 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +24 -11
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +17 -17
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
- data/lib/datadog/profiling/collectors/info.rb +3 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
- data/lib/datadog/profiling/component.rb +85 -90
- data/lib/datadog/profiling/exporter.rb +3 -3
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
- data/lib/datadog/profiling/ext.rb +21 -21
- data/lib/datadog/profiling/flush.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +8 -6
- data/lib/datadog/profiling/load_native_extension.rb +5 -5
- data/lib/datadog/profiling/preload.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +5 -8
- data/lib/datadog/profiling/scheduler.rb +31 -25
- data/lib/datadog/profiling/tag_builder.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +5 -5
- data/lib/datadog/profiling/tasks/setup.rb +16 -35
- data/lib/datadog/profiling.rb +5 -5
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +2 -1
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
- data/lib/datadog/tracing/contrib/analytics.rb +5 -0
- data/lib/datadog/tracing/contrib/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +28 -0
- data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
- data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/distributed/propagation.rb +9 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +3 -2
- data/lib/datadog/tracing/metadata/errors.rb +9 -1
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/span.rb +9 -2
- data/lib/datadog/tracing/span_event.rb +41 -0
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +7 -3
- data/lib/datadog/tracing/trace_segment.rb +4 -1
- data/lib/datadog/tracing/tracer.rb +9 -2
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
- data/lib/datadog/tracing.rb +5 -1
- data/lib/datadog/version.rb +2 -2
- metadata +43 -12
- data/lib/datadog/core/telemetry/client.rb +0 -95
- data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -19,7 +19,6 @@ void collectors_dynamic_sampling_rate_init(VALUE profiling_module);
|
|
19
19
|
void collectors_idle_sampling_helper_init(VALUE profiling_module);
|
20
20
|
void collectors_stack_init(VALUE profiling_module);
|
21
21
|
void collectors_thread_context_init(VALUE profiling_module);
|
22
|
-
void crashtracker_init(VALUE profiling_module);
|
23
22
|
void http_transport_init(VALUE profiling_module);
|
24
23
|
void stack_recorder_init(VALUE profiling_module);
|
25
24
|
|
@@ -54,7 +53,6 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
54
53
|
collectors_idle_sampling_helper_init(profiling_module);
|
55
54
|
collectors_stack_init(profiling_module);
|
56
55
|
collectors_thread_context_init(profiling_module);
|
57
|
-
crashtracker_init(profiling_module);
|
58
56
|
http_transport_init(profiling_module);
|
59
57
|
stack_recorder_init(profiling_module);
|
60
58
|
|
@@ -20,29 +20,6 @@ void ruby_helpers_init(void) {
|
|
20
20
|
to_s_id = rb_intern("to_s");
|
21
21
|
}
|
22
22
|
|
23
|
-
void raise_unexpected_type(
|
24
|
-
VALUE value,
|
25
|
-
const char *value_name,
|
26
|
-
const char *type_name,
|
27
|
-
const char *file,
|
28
|
-
int line,
|
29
|
-
const char* function_name
|
30
|
-
) {
|
31
|
-
rb_exc_raise(
|
32
|
-
rb_exc_new_str(
|
33
|
-
rb_eTypeError,
|
34
|
-
rb_sprintf("wrong argument %"PRIsVALUE" for '%s' (expected a %s) at %s:%d:in `%s'",
|
35
|
-
rb_inspect(value),
|
36
|
-
value_name,
|
37
|
-
type_name,
|
38
|
-
file,
|
39
|
-
line,
|
40
|
-
function_name
|
41
|
-
)
|
42
|
-
)
|
43
|
-
);
|
44
|
-
}
|
45
|
-
|
46
23
|
#define MAX_RAISE_MESSAGE_SIZE 256
|
47
24
|
|
48
25
|
struct raise_arguments {
|
@@ -255,13 +232,3 @@ VALUE ruby_safe_inspect(VALUE obj) {
|
|
255
232
|
return rb_str_new_cstr("(Not inspectable)");
|
256
233
|
}
|
257
234
|
}
|
258
|
-
|
259
|
-
VALUE ddtrace_version(void) {
|
260
|
-
VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
261
|
-
ENFORCE_TYPE(ddtrace_module, T_MODULE);
|
262
|
-
VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION"));
|
263
|
-
ENFORCE_TYPE(version_module, T_MODULE);
|
264
|
-
VALUE version_string = rb_const_get(version_module, rb_intern("STRING"));
|
265
|
-
ENFORCE_TYPE(version_string, T_STRING);
|
266
|
-
return version_string;
|
267
|
-
}
|
@@ -1,9 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
-
#include <ruby.h>
|
4
3
|
#include <stdbool.h>
|
5
|
-
|
6
|
-
#include "helpers.h"
|
4
|
+
#include "datadog_ruby_common.h"
|
7
5
|
|
8
6
|
// Initialize internal data needed by some ruby helpers. Should be called during start, before any actual
|
9
7
|
// usage of ruby helpers.
|
@@ -39,27 +37,6 @@ static inline int check_if_pending_exception(void) {
|
|
39
37
|
return pending_exception;
|
40
38
|
}
|
41
39
|
|
42
|
-
#define ADD_QUOTES_HELPER(x) #x
|
43
|
-
#define ADD_QUOTES(x) ADD_QUOTES_HELPER(x)
|
44
|
-
|
45
|
-
// Ruby has a Check_Type(value, type) that is roughly equivalent to this BUT Ruby's version is rather cryptic when it fails
|
46
|
-
// e.g. "wrong argument type nil (expected String)". This is a replacement that prints more information to help debugging.
|
47
|
-
#define ENFORCE_TYPE(value, type) \
|
48
|
-
{ if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
|
49
|
-
|
50
|
-
#define ENFORCE_BOOLEAN(value) \
|
51
|
-
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
|
52
|
-
|
53
|
-
// Called by ENFORCE_TYPE; should not be used directly
|
54
|
-
NORETURN(void raise_unexpected_type(
|
55
|
-
VALUE value,
|
56
|
-
const char *value_name,
|
57
|
-
const char *type_name,
|
58
|
-
const char *file,
|
59
|
-
int line,
|
60
|
-
const char *function_name
|
61
|
-
));
|
62
|
-
|
63
40
|
#define VALUE_COUNT(array) (sizeof(array) / sizeof(VALUE))
|
64
41
|
|
65
42
|
NORETURN(
|
@@ -113,5 +90,3 @@ size_t ruby_obj_memsize_of(VALUE obj);
|
|
113
90
|
// return a string with the result of that call. Elsif the object responds to
|
114
91
|
// 'to_s', return a string with the result of that call. Otherwise, return Qnil.
|
115
92
|
VALUE ruby_safe_inspect(VALUE obj);
|
116
|
-
|
117
|
-
VALUE ddtrace_version(void);
|
@@ -91,7 +91,7 @@ void remove_sigprof_signal_handler(void) {
|
|
91
91
|
if (sigaction(SIGPROF, &signal_handler_config, NULL) != 0) rb_sys_fail("Failure while removing the signal handler");
|
92
92
|
}
|
93
93
|
|
94
|
-
static void toggle_sigprof_signal_handler_for_current_thread(int action) {
|
94
|
+
static inline void toggle_sigprof_signal_handler_for_current_thread(int action) {
|
95
95
|
sigset_t signals_to_toggle;
|
96
96
|
sigemptyset(&signals_to_toggle);
|
97
97
|
sigaddset(&signals_to_toggle, SIGPROF);
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
3
|
#include <signal.h>
|
4
|
+
#include "datadog_ruby_common.h"
|
4
5
|
|
5
6
|
void empty_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
|
6
7
|
void install_sigprof_signal_handler(void (*signal_handler_function)(int, siginfo_t *, void *), const char *handler_pretty_name);
|
@@ -151,21 +151,23 @@ static VALUE error_symbol = Qnil; // :error in Ruby
|
|
151
151
|
#define WALL_TIME_VALUE_ID 2
|
152
152
|
#define ALLOC_SAMPLES_VALUE {.type_ = VALUE_STRING("alloc-samples"), .unit = VALUE_STRING("count")}
|
153
153
|
#define ALLOC_SAMPLES_VALUE_ID 3
|
154
|
+
#define ALLOC_SAMPLES_UNSCALED_VALUE {.type_ = VALUE_STRING("alloc-samples-unscaled"), .unit = VALUE_STRING("count")}
|
155
|
+
#define ALLOC_SAMPLES_UNSCALED_VALUE_ID 4
|
154
156
|
#define HEAP_SAMPLES_VALUE {.type_ = VALUE_STRING("heap-live-samples"), .unit = VALUE_STRING("count")}
|
155
|
-
#define HEAP_SAMPLES_VALUE_ID
|
157
|
+
#define HEAP_SAMPLES_VALUE_ID 5
|
156
158
|
#define HEAP_SIZE_VALUE {.type_ = VALUE_STRING("heap-live-size"), .unit = VALUE_STRING("bytes")}
|
157
|
-
#define HEAP_SIZE_VALUE_ID
|
159
|
+
#define HEAP_SIZE_VALUE_ID 6
|
158
160
|
#define TIMELINE_VALUE {.type_ = VALUE_STRING("timeline"), .unit = VALUE_STRING("nanoseconds")}
|
159
|
-
#define TIMELINE_VALUE_ID
|
161
|
+
#define TIMELINE_VALUE_ID 7
|
160
162
|
|
161
163
|
static const ddog_prof_ValueType all_value_types[] =
|
162
|
-
{CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE, ALLOC_SAMPLES_VALUE, HEAP_SAMPLES_VALUE, HEAP_SIZE_VALUE, TIMELINE_VALUE};
|
164
|
+
{CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE, ALLOC_SAMPLES_VALUE, ALLOC_SAMPLES_UNSCALED_VALUE, HEAP_SAMPLES_VALUE, HEAP_SIZE_VALUE, TIMELINE_VALUE};
|
163
165
|
|
164
166
|
// This array MUST be kept in sync with all_value_types above and is intended to act as a "hashmap" between VALUE_ID and the position it
|
165
167
|
// occupies on the all_value_types array.
|
166
168
|
// E.g. all_value_types_positions[CPU_TIME_VALUE_ID] => 0, means that CPU_TIME_VALUE was declared at position 0 of all_value_types.
|
167
169
|
static const uint8_t all_value_types_positions[] =
|
168
|
-
{CPU_TIME_VALUE_ID, CPU_SAMPLES_VALUE_ID, WALL_TIME_VALUE_ID, ALLOC_SAMPLES_VALUE_ID, HEAP_SAMPLES_VALUE_ID, HEAP_SIZE_VALUE_ID, TIMELINE_VALUE_ID};
|
170
|
+
{CPU_TIME_VALUE_ID, CPU_SAMPLES_VALUE_ID, WALL_TIME_VALUE_ID, ALLOC_SAMPLES_VALUE_ID, ALLOC_SAMPLES_UNSCALED_VALUE_ID, HEAP_SAMPLES_VALUE_ID, HEAP_SIZE_VALUE_ID, TIMELINE_VALUE_ID};
|
169
171
|
|
170
172
|
#define ALL_VALUE_TYPES_COUNT (sizeof(all_value_types) / sizeof(ddog_prof_ValueType))
|
171
173
|
|
@@ -340,6 +342,10 @@ static VALUE _native_new(VALUE klass) {
|
|
340
342
|
// Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
|
341
343
|
// before using them so it's ok for us to go ahead and create the StackRecorder object.
|
342
344
|
|
345
|
+
// Note: As of this writing, no new Ruby objects get created and stored in the state. If that ever changes, remember
|
346
|
+
// to keep them on the stack and mark them with RB_GC_GUARD -- otherwise it's possible for a GC to run and
|
347
|
+
// since the instance representing the state does not yet exist, such objects will not get marked.
|
348
|
+
|
343
349
|
VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
|
344
350
|
|
345
351
|
// NOTE: We initialize this because we want a new recorder to be operational even without initialization and our
|
@@ -429,7 +435,7 @@ static VALUE _native_initialize(
|
|
429
435
|
|
430
436
|
uint8_t requested_values_count = ALL_VALUE_TYPES_COUNT -
|
431
437
|
(cpu_time_enabled == Qtrue ? 0 : 1) -
|
432
|
-
(alloc_samples_enabled == Qtrue? 0 :
|
438
|
+
(alloc_samples_enabled == Qtrue? 0 : 2) -
|
433
439
|
(heap_samples_enabled == Qtrue ? 0 : 1) -
|
434
440
|
(heap_size_enabled == Qtrue ? 0 : 1) -
|
435
441
|
(timeline_enabled == Qtrue ? 0 : 1);
|
@@ -464,8 +470,12 @@ static VALUE _native_initialize(
|
|
464
470
|
if (alloc_samples_enabled == Qtrue) {
|
465
471
|
enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) ALLOC_SAMPLES_VALUE;
|
466
472
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
473
|
+
|
474
|
+
enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) ALLOC_SAMPLES_UNSCALED_VALUE;
|
475
|
+
state->position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID] = next_enabled_pos++;
|
467
476
|
} else {
|
468
477
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
478
|
+
state->position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID] = next_disabled_pos++;
|
469
479
|
}
|
470
480
|
|
471
481
|
if (heap_samples_enabled == Qtrue) {
|
@@ -603,14 +613,23 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
603
613
|
metric_values[position_for[CPU_SAMPLES_VALUE_ID]] = values.cpu_or_wall_samples;
|
604
614
|
metric_values[position_for[WALL_TIME_VALUE_ID]] = values.wall_time_ns;
|
605
615
|
metric_values[position_for[ALLOC_SAMPLES_VALUE_ID]] = values.alloc_samples;
|
616
|
+
metric_values[position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID]] = values.alloc_samples_unscaled;
|
606
617
|
metric_values[position_for[TIMELINE_VALUE_ID]] = values.timeline_wall_time_ns;
|
607
618
|
|
608
|
-
if (values.
|
619
|
+
if (values.heap_sample) {
|
609
620
|
// If we got an allocation sample end the heap allocation recording to commit the heap sample.
|
610
621
|
// FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
|
611
622
|
// very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
|
612
623
|
// be fixed with some refactoring but for now this leads to a less impactful change.
|
613
|
-
|
624
|
+
//
|
625
|
+
// NOTE: The heap recorder is allowed to raise exceptions if something's wrong. But we also need to handle it
|
626
|
+
// on this side to make sure we properly unlock the active slot mutex on our way out. Otherwise, this would
|
627
|
+
// later lead to deadlocks (since the active slot mutex is not expected to be locked forever).
|
628
|
+
int exception_state = end_heap_allocation_recording_with_rb_protect(state->heap_recorder, locations);
|
629
|
+
if (exception_state) {
|
630
|
+
sampler_unlock_active_profile(active_slot);
|
631
|
+
rb_jump_tag(exception_state);
|
632
|
+
}
|
614
633
|
}
|
615
634
|
|
616
635
|
ddog_prof_Profile_Result result = ddog_prof_Profile_add(
|
@@ -4,21 +4,6 @@
|
|
4
4
|
#include "ruby_helpers.h"
|
5
5
|
#include "time_helpers.h"
|
6
6
|
|
7
|
-
// Safety: This function is assumed never to raise exceptions by callers when raise_on_failure == false
|
8
|
-
long retrieve_clock_as_ns(clockid_t clock_id, bool raise_on_failure) {
|
9
|
-
struct timespec clock_value;
|
10
|
-
|
11
|
-
if (clock_gettime(clock_id, &clock_value) != 0) {
|
12
|
-
if (raise_on_failure) ENFORCE_SUCCESS_GVL(errno);
|
13
|
-
return 0;
|
14
|
-
}
|
15
|
-
|
16
|
-
return clock_value.tv_nsec + SECONDS_AS_NS(clock_value.tv_sec);
|
17
|
-
}
|
18
|
-
|
19
|
-
long monotonic_wall_time_now_ns(bool raise_on_failure) { return retrieve_clock_as_ns(CLOCK_MONOTONIC, raise_on_failure); }
|
20
|
-
long system_epoch_time_now_ns(bool raise_on_failure) { return retrieve_clock_as_ns(CLOCK_REALTIME, raise_on_failure); }
|
21
|
-
|
22
7
|
// Design: The monotonic_to_system_epoch_state struct is kept somewhere by the caller, and MUST be initialized to
|
23
8
|
// MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER.
|
24
9
|
//
|
@@ -1,12 +1,16 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
3
|
#include <stdbool.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#include <time.h>
|
6
|
+
|
7
|
+
#include "extconf.h" // Needed for HAVE_CLOCK_MONOTONIC_COARSE
|
8
|
+
#include "ruby_helpers.h"
|
4
9
|
|
5
10
|
#define SECONDS_AS_NS(value) (value * 1000 * 1000 * 1000L)
|
6
11
|
#define MILLIS_AS_NS(value) (value * 1000 * 1000L)
|
7
12
|
|
8
|
-
|
9
|
-
#define DO_NOT_RAISE_ON_FAILURE false
|
13
|
+
typedef enum { RAISE_ON_FAILURE, DO_NOT_RAISE_ON_FAILURE } raise_on_failure_setting;
|
10
14
|
|
11
15
|
#define INVALID_TIME -1
|
12
16
|
|
@@ -17,10 +21,36 @@ typedef struct {
|
|
17
21
|
|
18
22
|
#define MONOTONIC_TO_SYSTEM_EPOCH_INITIALIZER {.system_epoch_ns_reference = INVALID_TIME, .delta_to_epoch_ns = INVALID_TIME}
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
static inline long retrieve_clock_as_ns(clockid_t clock_id, raise_on_failure_setting raise_on_failure) {
|
25
|
+
struct timespec clock_value;
|
26
|
+
|
27
|
+
if (clock_gettime(clock_id, &clock_value) != 0) {
|
28
|
+
if (raise_on_failure == RAISE_ON_FAILURE) ENFORCE_SUCCESS_GVL(errno);
|
29
|
+
return 0;
|
30
|
+
}
|
31
|
+
|
32
|
+
return clock_value.tv_nsec + SECONDS_AS_NS(clock_value.tv_sec);
|
33
|
+
}
|
34
|
+
|
35
|
+
static inline long monotonic_wall_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_MONOTONIC, raise_on_failure); }
|
36
|
+
static inline long system_epoch_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_REALTIME, raise_on_failure); }
|
37
|
+
|
38
|
+
// Coarse instants use CLOCK_MONOTONIC_COARSE on Linux which is expected to provide resolution in the millisecond range:
|
39
|
+
// https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/sect-posix_clocks#Using_clock_getres_to_compare_clock_resolution
|
40
|
+
// We introduce here a separate type for it, so as to make it harder to misuse/more explicit when these timestamps are used
|
41
|
+
|
42
|
+
typedef struct coarse_instant {
|
43
|
+
long timestamp_ns;
|
44
|
+
} coarse_instant;
|
45
|
+
|
46
|
+
static inline coarse_instant to_coarse_instant(long timestamp_ns) { return (coarse_instant) {.timestamp_ns = timestamp_ns}; }
|
22
47
|
|
23
|
-
|
24
|
-
|
48
|
+
static inline coarse_instant monotonic_coarse_wall_time_now_ns(void) {
|
49
|
+
#ifdef HAVE_CLOCK_MONOTONIC_COARSE // Linux
|
50
|
+
return to_coarse_instant(retrieve_clock_as_ns(CLOCK_MONOTONIC_COARSE, DO_NOT_RAISE_ON_FAILURE));
|
51
|
+
#else // macOS
|
52
|
+
return to_coarse_instant(retrieve_clock_as_ns(CLOCK_MONOTONIC, DO_NOT_RAISE_ON_FAILURE));
|
53
|
+
#endif
|
54
|
+
}
|
25
55
|
|
26
56
|
long monotonic_to_system_epoch_ns(monotonic_to_system_epoch_state *state, long monotonic_wall_time_ns);
|
@@ -1,15 +1,25 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#include <datadog/
|
3
|
-
|
2
|
+
#include <datadog/profiling.h>
|
3
|
+
|
4
|
+
#include "datadog_ruby_common.h"
|
4
5
|
|
5
6
|
static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
6
7
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self);
|
8
|
+
static void crashtracker_init(VALUE crashtracking_module);
|
7
9
|
|
8
10
|
// Used to report Ruby VM crashes.
|
9
11
|
// Once initialized, segfaults will be reported automatically using libdatadog.
|
10
12
|
|
11
|
-
void
|
12
|
-
VALUE
|
13
|
+
void DDTRACE_EXPORT Init_libdatadog_api(void) {
|
14
|
+
VALUE datadog_module = rb_define_module("Datadog");
|
15
|
+
VALUE core_module = rb_define_module_under(datadog_module, "Core");
|
16
|
+
VALUE crashtracking_module = rb_define_module_under(core_module, "Crashtracking");
|
17
|
+
|
18
|
+
crashtracker_init(crashtracking_module);
|
19
|
+
}
|
20
|
+
|
21
|
+
void crashtracker_init(VALUE crashtracking_module) {
|
22
|
+
VALUE crashtracker_class = rb_define_class_under(crashtracking_module, "Component", rb_cObject);
|
13
23
|
|
14
24
|
rb_define_singleton_method(crashtracker_class, "_native_start_or_update_on_fork", _native_start_or_update_on_fork, -1);
|
15
25
|
rb_define_singleton_method(crashtracker_class, "_native_stop", _native_stop, 0);
|
@@ -38,7 +48,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
38
48
|
|
39
49
|
if (action != start_action && action != update_on_fork_action) rb_raise(rb_eArgError, "Unexpected action: %+"PRIsVALUE, action);
|
40
50
|
|
41
|
-
VALUE version =
|
51
|
+
VALUE version = datadog_gem_version();
|
42
52
|
ddog_prof_Endpoint endpoint = endpoint_from(exporter_configuration);
|
43
53
|
|
44
54
|
// Tags are heap-allocated, so after here we can't raise exceptions otherwise we'll leak this memory
|
@@ -57,8 +67,11 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
57
67
|
// "Process.kill('SEGV', Process.pid)" gets run.
|
58
68
|
.create_alt_stack = false,
|
59
69
|
.endpoint = endpoint,
|
60
|
-
.resolve_frames =
|
70
|
+
.resolve_frames = DDOG_PROF_STACKTRACE_COLLECTION_ENABLED_WITH_SYMBOLS_IN_RECEIVER,
|
61
71
|
.timeout_secs = FIX2INT(upload_timeout_seconds),
|
72
|
+
// Waits for crash tracker to finish reporting the issue before letting the Ruby process die; see
|
73
|
+
// https://github.com/DataDog/libdatadog/pull/477 for details
|
74
|
+
.wait_for_receiver = true,
|
62
75
|
};
|
63
76
|
|
64
77
|
ddog_prof_CrashtrackerMetadata metadata = {
|
@@ -83,7 +96,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
83
96
|
|
84
97
|
ddog_prof_CrashtrackerResult result =
|
85
98
|
action == start_action ?
|
86
|
-
|
99
|
+
ddog_prof_Crashtracker_init_with_receiver(config, receiver_config, metadata) :
|
87
100
|
ddog_prof_Crashtracker_update_on_fork(config, receiver_config, metadata);
|
88
101
|
|
89
102
|
// Clean up before potentially raising any exceptions
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#include "datadog_ruby_common.h"
|
2
|
+
|
3
|
+
// IMPORTANT: Currently this file is copy-pasted between extensions. Make sure to update all versions when doing any change!
|
4
|
+
|
5
|
+
void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name) {
|
6
|
+
rb_exc_raise(
|
7
|
+
rb_exc_new_str(
|
8
|
+
rb_eTypeError,
|
9
|
+
rb_sprintf("wrong argument %"PRIsVALUE" for '%s' (expected a %s) at %s:%d:in `%s'",
|
10
|
+
rb_inspect(value),
|
11
|
+
value_name,
|
12
|
+
type_name,
|
13
|
+
file,
|
14
|
+
line,
|
15
|
+
function_name
|
16
|
+
)
|
17
|
+
)
|
18
|
+
);
|
19
|
+
}
|
20
|
+
|
21
|
+
VALUE datadog_gem_version(void) {
|
22
|
+
VALUE ddtrace_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
23
|
+
ENFORCE_TYPE(ddtrace_module, T_MODULE);
|
24
|
+
VALUE version_module = rb_const_get(ddtrace_module, rb_intern("VERSION"));
|
25
|
+
ENFORCE_TYPE(version_module, T_MODULE);
|
26
|
+
VALUE version_string = rb_const_get(version_module, rb_intern("STRING"));
|
27
|
+
ENFORCE_TYPE(version_string, T_STRING);
|
28
|
+
return version_string;
|
29
|
+
}
|
30
|
+
|
31
|
+
__attribute__((warn_unused_result))
|
32
|
+
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
|
33
|
+
ENFORCE_TYPE(exporter_configuration, T_ARRAY);
|
34
|
+
|
35
|
+
VALUE exporter_working_mode = rb_ary_entry(exporter_configuration, 0);
|
36
|
+
ENFORCE_TYPE(exporter_working_mode, T_SYMBOL);
|
37
|
+
ID working_mode = SYM2ID(exporter_working_mode);
|
38
|
+
|
39
|
+
ID agentless_id = rb_intern("agentless");
|
40
|
+
ID agent_id = rb_intern("agent");
|
41
|
+
|
42
|
+
if (working_mode != agentless_id && working_mode != agent_id) {
|
43
|
+
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
|
44
|
+
}
|
45
|
+
|
46
|
+
if (working_mode == agentless_id) {
|
47
|
+
VALUE site = rb_ary_entry(exporter_configuration, 1);
|
48
|
+
VALUE api_key = rb_ary_entry(exporter_configuration, 2);
|
49
|
+
|
50
|
+
return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
|
51
|
+
} else { // agent_id
|
52
|
+
VALUE base_url = rb_ary_entry(exporter_configuration, 1);
|
53
|
+
|
54
|
+
return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
static VALUE log_failure_to_process_tag(VALUE err_details) {
|
59
|
+
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
60
|
+
VALUE logger = rb_funcall(datadog_module, rb_intern("logger"), 0);
|
61
|
+
|
62
|
+
return rb_funcall(logger, rb_intern("warn"), 1, rb_sprintf("Failed to convert tag: %"PRIsVALUE, err_details));
|
63
|
+
}
|
64
|
+
|
65
|
+
__attribute__((warn_unused_result))
|
66
|
+
ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
|
67
|
+
ENFORCE_TYPE(tags_as_array, T_ARRAY);
|
68
|
+
|
69
|
+
long tags_count = RARRAY_LEN(tags_as_array);
|
70
|
+
ddog_Vec_Tag tags = ddog_Vec_Tag_new();
|
71
|
+
|
72
|
+
for (long i = 0; i < tags_count; i++) {
|
73
|
+
VALUE name_value_pair = rb_ary_entry(tags_as_array, i);
|
74
|
+
|
75
|
+
if (!RB_TYPE_P(name_value_pair, T_ARRAY)) {
|
76
|
+
ddog_Vec_Tag_drop(tags);
|
77
|
+
ENFORCE_TYPE(name_value_pair, T_ARRAY);
|
78
|
+
}
|
79
|
+
|
80
|
+
// Note: We can index the array without checking its size first because rb_ary_entry returns Qnil if out of bounds
|
81
|
+
VALUE tag_name = rb_ary_entry(name_value_pair, 0);
|
82
|
+
VALUE tag_value = rb_ary_entry(name_value_pair, 1);
|
83
|
+
|
84
|
+
if (!(RB_TYPE_P(tag_name, T_STRING) && RB_TYPE_P(tag_value, T_STRING))) {
|
85
|
+
ddog_Vec_Tag_drop(tags);
|
86
|
+
ENFORCE_TYPE(tag_name, T_STRING);
|
87
|
+
ENFORCE_TYPE(tag_value, T_STRING);
|
88
|
+
}
|
89
|
+
|
90
|
+
ddog_Vec_Tag_PushResult push_result =
|
91
|
+
ddog_Vec_Tag_push(&tags, char_slice_from_ruby_string(tag_name), char_slice_from_ruby_string(tag_value));
|
92
|
+
|
93
|
+
if (push_result.tag == DDOG_VEC_TAG_PUSH_RESULT_ERR) {
|
94
|
+
// libdatadog validates tags and may catch invalid tags that ddtrace didn't actually catch.
|
95
|
+
// We warn users about such tags, and then just ignore them.
|
96
|
+
|
97
|
+
int exception_state;
|
98
|
+
rb_protect(log_failure_to_process_tag, get_error_details_and_drop(&push_result.err), &exception_state);
|
99
|
+
|
100
|
+
// Since we are calling into Ruby code, it may raise an exception. Ensure that dynamically-allocated tags
|
101
|
+
// get cleaned before propagating the exception.
|
102
|
+
if (exception_state) {
|
103
|
+
ddog_Vec_Tag_drop(tags);
|
104
|
+
rb_jump_tag(exception_state); // "Re-raise" exception
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
return tags;
|
110
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
// IMPORTANT: Currently this file is copy-pasted between extensions. Make sure to update all versions when doing any change!
|
4
|
+
|
5
|
+
#include <ruby.h>
|
6
|
+
#include <datadog/profiling.h>
|
7
|
+
|
8
|
+
// Used to mark symbols to be exported to the outside of the extension.
|
9
|
+
// Consider very carefully before tagging a function with this.
|
10
|
+
#define DDTRACE_EXPORT __attribute__ ((visibility ("default")))
|
11
|
+
|
12
|
+
// Used to mark function arguments that are deliberately left unused
|
13
|
+
#ifdef __GNUC__
|
14
|
+
#define DDTRACE_UNUSED __attribute__((unused))
|
15
|
+
#else
|
16
|
+
#define DDTRACE_UNUSED
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#define ADD_QUOTES_HELPER(x) #x
|
20
|
+
#define ADD_QUOTES(x) ADD_QUOTES_HELPER(x)
|
21
|
+
|
22
|
+
// Ruby has a Check_Type(value, type) that is roughly equivalent to this BUT Ruby's version is rather cryptic when it fails
|
23
|
+
// e.g. "wrong argument type nil (expected String)". This is a replacement that prints more information to help debugging.
|
24
|
+
#define ENFORCE_TYPE(value, type) \
|
25
|
+
{ if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
|
26
|
+
|
27
|
+
#define ENFORCE_BOOLEAN(value) \
|
28
|
+
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
|
29
|
+
|
30
|
+
// Called by ENFORCE_TYPE; should not be used directly
|
31
|
+
NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
|
32
|
+
|
33
|
+
// Helper to retrieve Datadog::VERSION::STRING
|
34
|
+
VALUE datadog_gem_version(void);
|
35
|
+
|
36
|
+
static inline ddog_CharSlice char_slice_from_ruby_string(VALUE string) {
|
37
|
+
ENFORCE_TYPE(string, T_STRING);
|
38
|
+
ddog_CharSlice char_slice = {.ptr = RSTRING_PTR(string), .len = RSTRING_LEN(string)};
|
39
|
+
return char_slice;
|
40
|
+
}
|
41
|
+
|
42
|
+
__attribute__((warn_unused_result))
|
43
|
+
ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);
|
44
|
+
|
45
|
+
__attribute__((warn_unused_result))
|
46
|
+
ddog_Vec_Tag convert_tags(VALUE tags_as_array);
|
47
|
+
|
48
|
+
static inline VALUE ruby_string_from_error(const ddog_Error *error) {
|
49
|
+
ddog_CharSlice char_slice = ddog_Error_message(error);
|
50
|
+
return rb_str_new(char_slice.ptr, char_slice.len);
|
51
|
+
}
|
52
|
+
|
53
|
+
static inline VALUE get_error_details_and_drop(ddog_Error *error) {
|
54
|
+
VALUE result = ruby_string_from_error(error);
|
55
|
+
ddog_Error_drop(error);
|
56
|
+
return result;
|
57
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# rubocop:disable Style/StderrPuts
|
2
|
+
# rubocop:disable Style/GlobalVars
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require_relative '../libdatadog_extconf_helpers'
|
6
|
+
|
7
|
+
def skip_building_extension!(reason)
|
8
|
+
$stderr.puts(
|
9
|
+
"WARN: Skipping build of libdatadog_api (#{reason}). Some functionality will not be available."
|
10
|
+
)
|
11
|
+
|
12
|
+
fail_install_if_missing_extension = ENV['DD_FAIL_INSTALL_IF_MISSING_EXTENSION'].to_s.strip.downcase == 'true'
|
13
|
+
|
14
|
+
if fail_install_if_missing_extension
|
15
|
+
require 'mkmf'
|
16
|
+
Logging.message("[datadog] Failure cause: #{reason}")
|
17
|
+
else
|
18
|
+
File.write('Makefile', 'all install clean: # dummy makefile that does nothing')
|
19
|
+
end
|
20
|
+
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
if ENV['DD_NO_EXTENSION'].to_s.strip.downcase == 'true'
|
25
|
+
skip_building_extension!('the `DD_NO_EXTENSION` environment variable is/was set to `true` during installation')
|
26
|
+
end
|
27
|
+
skip_building_extension!('current Ruby VM is not supported') if RUBY_ENGINE != 'ruby'
|
28
|
+
skip_building_extension!('Microsoft Windows is not supported') if Gem.win_platform?
|
29
|
+
skip_building_extension!('issue setting up `libdatadog` gem') if Datadog::LibdatadogExtconfHelpers.libdatadog_issue?
|
30
|
+
|
31
|
+
require 'mkmf'
|
32
|
+
|
33
|
+
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
|
34
|
+
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
|
35
|
+
append_cflags '-Werror' if ENV['DATADOG_GEM_CI'] == 'true'
|
36
|
+
|
37
|
+
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
|
38
|
+
# * by upstream Ruby -- search for gnu99 in the codebase
|
39
|
+
# * by msgpack, another datadog gem dependency
|
40
|
+
# (https://github.com/msgpack/msgpack-ruby/blob/18ce08f6d612fe973843c366ac9a0b74c4e50599/ext/msgpack/extconf.rb#L8)
|
41
|
+
append_cflags '-std=gnu99'
|
42
|
+
|
43
|
+
# Allow defining variables at any point in a function
|
44
|
+
append_cflags '-Wno-declaration-after-statement'
|
45
|
+
|
46
|
+
# If we forget to include a Ruby header, the function call may still appear to work, but then
|
47
|
+
# cause a segfault later. Let's ensure that never happens.
|
48
|
+
append_cflags '-Werror-implicit-function-declaration'
|
49
|
+
|
50
|
+
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
51
|
+
append_cflags '-Wunused-parameter'
|
52
|
+
|
53
|
+
# The native extension is not intended to expose any symbols/functions for other native libraries to use;
|
54
|
+
# the sole exception being `Init_libdatadog_api` which needs to be visible for Ruby to call it when
|
55
|
+
# it `dlopen`s the library.
|
56
|
+
#
|
57
|
+
# By setting this compiler flag, we tell it to assume that everything is private unless explicitly stated.
|
58
|
+
# For more details see https://gcc.gnu.org/wiki/Visibility
|
59
|
+
append_cflags '-fvisibility=hidden'
|
60
|
+
|
61
|
+
# Avoid legacy C definitions
|
62
|
+
append_cflags '-Wold-style-definition'
|
63
|
+
|
64
|
+
# Enable all other compiler warnings
|
65
|
+
append_cflags '-Wall'
|
66
|
+
append_cflags '-Wextra'
|
67
|
+
|
68
|
+
if ENV['DDTRACE_DEBUG'] == 'true'
|
69
|
+
$defs << '-DDD_DEBUG'
|
70
|
+
CONFIG['optflags'] = '-O0'
|
71
|
+
CONFIG['debugflags'] = '-ggdb3'
|
72
|
+
end
|
73
|
+
|
74
|
+
# If we got here, libdatadog is available and loaded
|
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
|
+
$stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
|
78
|
+
|
79
|
+
unless pkg_config('datadog_profiling_with_rpath')
|
80
|
+
Logging.message("[datadog] Ruby detected the pkg-config command is #{$PKGCONFIG.inspect}\n")
|
81
|
+
|
82
|
+
if Datadog::LibdatadogExtconfHelpers.pkg_config_missing?
|
83
|
+
skip_building_extension!('the `pkg-config` system tool is missing')
|
84
|
+
else
|
85
|
+
skip_building_extension!('there was a problem in setting up the `libdatadog` dependency')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# See comments on the helper methods being used for why we need to additionally set this.
|
90
|
+
# The extremely excessive escaping around ORIGIN below seems to be correct and was determined after a lot of
|
91
|
+
# experimentation. We need to get these special characters across a lot of tools untouched...
|
92
|
+
extra_relative_rpaths = [
|
93
|
+
Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_native_lib_folder(current_folder: __dir__),
|
94
|
+
*Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_ruby_extensions_folders,
|
95
|
+
]
|
96
|
+
extra_relative_rpaths.each { |folder| $LDFLAGS += " -Wl,-rpath,$$$\\\\{ORIGIN\\}/#{folder.to_str}" }
|
97
|
+
Logging.message("[datadog] After pkg-config $LDFLAGS were set to: #{$LDFLAGS.inspect}\n")
|
98
|
+
|
99
|
+
# Tag the native extension library with the Ruby version and Ruby platform.
|
100
|
+
# This makes it easier for development (avoids "oops I forgot to rebuild when I switched my Ruby") and ensures that
|
101
|
+
# the wrong library is never loaded.
|
102
|
+
# When requiring, we need to use the exact same string, including the version and the platform.
|
103
|
+
EXTENSION_NAME = "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}".freeze
|
104
|
+
|
105
|
+
create_makefile(EXTENSION_NAME)
|
106
|
+
|
107
|
+
# rubocop:enable Style/GlobalVars
|
108
|
+
# rubocop:enable Style/StderrPuts
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Developing on macOS
|
2
|
+
|
3
|
+
As of this writing (August 2024), the libdatadog builds on rubygems.org only support Linux.
|
4
|
+
|
5
|
+
We don't officially support using libdatadog for Ruby on other platforms yet, but it is possible to use it for local development on macOS.
|
6
|
+
(**Note that you don't need these instructions if you develop inside docker.**)
|
7
|
+
|
8
|
+
Here's how you can do so:
|
9
|
+
|
10
|
+
1. [Install rust](https://www.rust-lang.org/tools/install)
|
11
|
+
2. Install `cbindgen`: `cargo install cbindgen`
|
12
|
+
3. Clone [libdatadog](https://github.com/datadog/libdatadog)
|
13
|
+
4. Create a folder for building into based on your ruby platform:
|
14
|
+
|
15
|
+
```
|
16
|
+
export DD_RUBY_PLATFORM=`ruby -e 'puts Gem::Platform.local.to_s'`
|
17
|
+
mkdir -p my-libdatadog-build/$DD_RUBY_PLATFORM
|
18
|
+
```
|
19
|
+
|
20
|
+
5. Build libdatadog into this folder: `./build-profiling-ffi.sh my-libdatadog-build/$DD_RUBY_PLATFORM`
|
21
|
+
6. Tell the Ruby where to find libdatadog: `export LIBDATADOG_VENDOR_OVERRIDE=/full/path/to/my-libdatadog-build/` (Notice no platform here)
|
22
|
+
7. Run `bundle exec rake clean compile`
|
23
|
+
|
24
|
+
If you additionally want to run the profiler test suite, also remember to `export DD_PROFILING_MACOS_TESTING=true` and re-run `rake clean compile`.
|
25
|
+
|
26
|
+
These instructions can quickly get outdated, so feel free to open an issue if they're not working (and/or ping @ivoanjo).
|