datadog 2.28.0 → 2.30.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 +87 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +82 -12
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +32 -11
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -24
- data/ext/datadog_profiling_native_extension/heap_recorder.c +186 -55
- data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +51 -64
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
- data/ext/datadog_profiling_native_extension/profiling.c +3 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +24 -8
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -3
- data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -48
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -1
- data/ext/libdatadog_api/crashtracker.c +5 -0
- data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
- data/ext/libdatadog_api/extconf.rb +4 -21
- data/ext/libdatadog_extconf_helpers.rb +49 -11
- data/lib/datadog/ai_guard/configuration/settings.rb +3 -0
- data/lib/datadog/appsec/assets/blocked.html +2 -1
- data/lib/datadog/appsec/configuration/settings.rb +14 -0
- data/lib/datadog/appsec/context.rb +44 -9
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +3 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/patcher.rb +2 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +55 -6
- data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +60 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +11 -6
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -10
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +4 -4
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +26 -5
- data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +2 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +72 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -3
- data/lib/datadog/appsec/counter_sampler.rb +25 -0
- data/lib/datadog/appsec/event.rb +1 -17
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
- data/lib/datadog/appsec/instrumentation/gateway.rb +2 -2
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +18 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/security_engine/engine.rb +23 -2
- data/lib/datadog/appsec/utils/http/body.rb +38 -0
- data/lib/datadog/appsec/utils/http/media_range.rb +2 -1
- data/lib/datadog/appsec/utils/http/media_type.rb +28 -35
- data/lib/datadog/appsec/utils/http/url_encoded.rb +52 -0
- data/lib/datadog/core/configuration/components.rb +29 -4
- data/lib/datadog/core/configuration/option.rb +2 -1
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +27 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +19 -0
- data/lib/datadog/core/configuration.rb +2 -2
- data/lib/datadog/core/crashtracking/component.rb +71 -19
- data/lib/datadog/core/environment/agent_info.rb +65 -1
- data/lib/datadog/core/logger.rb +1 -1
- data/lib/datadog/core/metrics/logging.rb +1 -1
- data/lib/datadog/core/process_discovery.rb +20 -19
- data/lib/datadog/core/rate_limiter.rb +2 -0
- data/lib/datadog/core/remote/component.rb +16 -5
- data/lib/datadog/core/remote/transport/config.rb +5 -11
- data/lib/datadog/core/runtime/metrics.rb +1 -2
- data/lib/datadog/core/telemetry/component.rb +0 -13
- data/lib/datadog/core/telemetry/transport/telemetry.rb +5 -6
- data/lib/datadog/core/transport/ext.rb +1 -0
- data/lib/datadog/core/transport/http/response.rb +4 -0
- data/lib/datadog/core/transport/parcel.rb +61 -9
- data/lib/datadog/core/utils/base64.rb +1 -1
- data/lib/datadog/core/utils/fnv.rb +26 -0
- data/lib/datadog/core/workers/interval_loop.rb +13 -6
- data/lib/datadog/core/workers/queue.rb +0 -4
- data/lib/datadog/core/workers/runtime_metrics.rb +9 -1
- data/lib/datadog/core.rb +6 -1
- data/lib/datadog/data_streams/processor.rb +35 -33
- data/lib/datadog/data_streams/transport/http/stats.rb +6 -0
- data/lib/datadog/data_streams/transport/http.rb +0 -4
- data/lib/datadog/data_streams/transport/stats.rb +5 -12
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/component.rb +17 -5
- data/lib/datadog/di/configuration/settings.rb +9 -0
- data/lib/datadog/di/context.rb +6 -0
- data/lib/datadog/di/instrumenter.rb +183 -134
- data/lib/datadog/di/probe.rb +10 -1
- data/lib/datadog/di/probe_file_loader.rb +2 -2
- data/lib/datadog/di/probe_manager.rb +86 -64
- data/lib/datadog/di/probe_notification_builder.rb +46 -18
- data/lib/datadog/di/probe_notifier_worker.rb +65 -9
- data/lib/datadog/di/probe_repository.rb +198 -0
- data/lib/datadog/di/proc_responder.rb +4 -0
- data/lib/datadog/di/remote.rb +6 -7
- data/lib/datadog/di/serializer.rb +127 -9
- data/lib/datadog/di/transport/diagnostics.rb +5 -7
- data/lib/datadog/di/transport/http/diagnostics.rb +3 -1
- data/lib/datadog/di/transport/http/input.rb +1 -1
- data/lib/datadog/di/transport/http.rb +12 -3
- data/lib/datadog/di/transport/input.rb +51 -14
- data/lib/datadog/kit/tracing/method_tracer.rb +132 -0
- data/lib/datadog/open_feature/configuration.rb +2 -0
- data/lib/datadog/open_feature/transport.rb +8 -11
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +13 -0
- data/lib/datadog/profiling/component.rb +20 -6
- data/lib/datadog/profiling/http_transport.rb +5 -6
- data/lib/datadog/profiling/profiler.rb +15 -8
- data/lib/datadog/tracing/contrib/dalli/integration.rb +4 -1
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/instrumentation.rb +13 -8
- data/lib/datadog/tracing/contrib/grape/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/http/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/karafka/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +10 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +24 -0
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/rack/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +18 -6
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/registerable.rb +11 -0
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sneakers/integration.rb +15 -4
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +1 -0
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/sync_writer.rb +0 -1
- data/lib/datadog/tracing/transport/io/client.rb +5 -8
- data/lib/datadog/tracing/transport/io/traces.rb +28 -34
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +4 -10
- data/lib/datadog/tracing/writer.rb +0 -1
- data/lib/datadog/version.rb +1 -1
- metadata +14 -8
- data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
- data/lib/datadog/tracing/workers/trace_writer.rb +0 -204
|
@@ -9,26 +9,30 @@
|
|
|
9
9
|
|
|
10
10
|
// Used by Collectors::CpuAndWallTimeWorker to setup SIGPROF signal handlers used for cpu/wall-time profiling.
|
|
11
11
|
|
|
12
|
+
static VALUE existing_signal_handler_exception_class = Qnil;
|
|
13
|
+
|
|
12
14
|
static void install_sigprof_signal_handler_internal(
|
|
13
15
|
void (*signal_handler_function)(int, siginfo_t *, void *),
|
|
14
16
|
const char *handler_pretty_name,
|
|
15
|
-
void (*signal_handler_to_replace)(int, siginfo_t *, void *)
|
|
17
|
+
void (*signal_handler_to_replace)(int, siginfo_t *, void *),
|
|
18
|
+
bool should_raise_on_failure
|
|
16
19
|
);
|
|
17
20
|
|
|
18
21
|
void empty_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) { }
|
|
19
22
|
|
|
20
23
|
void install_sigprof_signal_handler(void (*signal_handler_function)(int, siginfo_t *, void *), const char *handler_pretty_name) {
|
|
21
|
-
install_sigprof_signal_handler_internal(signal_handler_function, handler_pretty_name, NULL);
|
|
24
|
+
install_sigprof_signal_handler_internal(signal_handler_function, handler_pretty_name, NULL, true);
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
void replace_sigprof_signal_handler_with_empty_handler(void (*expected_existing_handler)(int, siginfo_t *, void *)) {
|
|
25
|
-
install_sigprof_signal_handler_internal(empty_signal_handler, "empty_signal_handler", expected_existing_handler);
|
|
27
|
+
void replace_sigprof_signal_handler_with_empty_handler(void (*expected_existing_handler)(int, siginfo_t *, void *), bool should_raise_on_failure) {
|
|
28
|
+
install_sigprof_signal_handler_internal(empty_signal_handler, "empty_signal_handler", expected_existing_handler, should_raise_on_failure);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
static void install_sigprof_signal_handler_internal(
|
|
29
32
|
void (*signal_handler_function)(int, siginfo_t *, void *),
|
|
30
33
|
const char *handler_pretty_name,
|
|
31
|
-
void (*signal_handler_to_replace)(int, siginfo_t *, void *)
|
|
34
|
+
void (*signal_handler_to_replace)(int, siginfo_t *, void *),
|
|
35
|
+
bool should_raise_on_failure
|
|
32
36
|
) {
|
|
33
37
|
struct sigaction existing_signal_handler_config = {.sa_sigaction = NULL};
|
|
34
38
|
struct sigaction signal_handler_config = {
|
|
@@ -52,8 +56,7 @@ static void install_sigprof_signal_handler_internal(
|
|
|
52
56
|
) { return; }
|
|
53
57
|
|
|
54
58
|
if (existing_signal_handler_config.sa_handler != NULL || existing_signal_handler_config.sa_sigaction != NULL) {
|
|
55
|
-
// An unexpected/unknown signal handler already existed.
|
|
56
|
-
// of the installation.
|
|
59
|
+
// An unexpected/unknown signal handler already existed.
|
|
57
60
|
|
|
58
61
|
if (sigaction(SIGPROF, &existing_signal_handler_config, NULL) != 0) {
|
|
59
62
|
rb_exc_raise(
|
|
@@ -71,8 +74,12 @@ static void install_sigprof_signal_handler_internal(
|
|
|
71
74
|
);
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
// If should_raise_on_failure is false (e.g., during cleanup), just return silently.
|
|
78
|
+
// This can happen if we failed to install our handler earlier due to a pre-existing handler.
|
|
79
|
+
if (!should_raise_on_failure) return;
|
|
80
|
+
|
|
74
81
|
raise_error(
|
|
75
|
-
|
|
82
|
+
existing_signal_handler_exception_class,
|
|
76
83
|
"Could not install profiling signal handler (%s): There's a pre-existing SIGPROF signal handler",
|
|
77
84
|
handler_pretty_name
|
|
78
85
|
);
|
|
@@ -119,3 +126,12 @@ VALUE is_sigprof_blocked_in_current_thread(void) {
|
|
|
119
126
|
ENFORCE_SUCCESS_GVL(pthread_sigmask(0, NULL, ¤t_signals));
|
|
120
127
|
return sigismember(¤t_signals, SIGPROF) ? Qtrue : Qfalse;
|
|
121
128
|
}
|
|
129
|
+
|
|
130
|
+
void setup_signal_handler_init(VALUE profiling_module) {
|
|
131
|
+
existing_signal_handler_exception_class = rb_define_class_under(
|
|
132
|
+
profiling_module,
|
|
133
|
+
"ExistingSignalHandler",
|
|
134
|
+
rb_eRuntimeError
|
|
135
|
+
);
|
|
136
|
+
rb_gc_register_mark_object(existing_signal_handler_exception_class);
|
|
137
|
+
}
|
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
#include <signal.h>
|
|
4
4
|
#include "datadog_ruby_common.h"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
6
|
void empty_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
|
|
9
7
|
|
|
10
8
|
void install_sigprof_signal_handler(void (*signal_handler_function)(int, siginfo_t *, void *), const char *handler_pretty_name);
|
|
11
|
-
void replace_sigprof_signal_handler_with_empty_handler(void (*expected_existing_handler)(int, siginfo_t *, void *));
|
|
9
|
+
void replace_sigprof_signal_handler_with_empty_handler(void (*expected_existing_handler)(int, siginfo_t *, void *), bool should_raise_on_failure);
|
|
12
10
|
void remove_sigprof_signal_handler(void);
|
|
13
11
|
void block_sigprof_signal_handler_from_running_in_current_thread(void);
|
|
14
12
|
void unblock_sigprof_signal_handler_from_running_in_current_thread(void);
|
|
@@ -131,46 +131,32 @@
|
|
|
131
131
|
static VALUE ok_symbol = Qnil; // :ok in Ruby
|
|
132
132
|
static VALUE error_symbol = Qnil; // :error in Ruby
|
|
133
133
|
|
|
134
|
-
// Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
|
|
135
|
-
// `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
|
|
136
|
-
// tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
|
|
137
|
-
// `DDOG_CHARSLICE_C` with the following error:
|
|
138
|
-
//
|
|
139
|
-
// ```
|
|
140
|
-
// compiling ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c
|
|
141
|
-
// ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c:23:1: error: initializer element is not constant
|
|
142
|
-
// static const ddog_prof_ValueType enabled_value_types[] = {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE};
|
|
143
|
-
// ^
|
|
144
|
-
// ```
|
|
145
|
-
#define VALUE_STRING(string) {.ptr = "" string, .len = sizeof(string) - 1}
|
|
146
|
-
|
|
147
|
-
#define CPU_TIME_VALUE {.type_ = VALUE_STRING("cpu-time"), .unit = VALUE_STRING("nanoseconds")}
|
|
148
134
|
#define CPU_TIME_VALUE_ID 0
|
|
149
|
-
#define CPU_SAMPLES_VALUE {.type_ = VALUE_STRING("cpu-samples"), .unit = VALUE_STRING("count")}
|
|
150
135
|
#define CPU_SAMPLES_VALUE_ID 1
|
|
151
|
-
#define WALL_TIME_VALUE {.type_ = VALUE_STRING("wall-time"), .unit = VALUE_STRING("nanoseconds")}
|
|
152
136
|
#define WALL_TIME_VALUE_ID 2
|
|
153
|
-
#define ALLOC_SAMPLES_VALUE {.type_ = VALUE_STRING("alloc-samples"), .unit = VALUE_STRING("count")}
|
|
154
137
|
#define ALLOC_SAMPLES_VALUE_ID 3
|
|
155
|
-
#define ALLOC_SAMPLES_UNSCALED_VALUE {.type_ = VALUE_STRING("alloc-samples-unscaled"), .unit = VALUE_STRING("count")}
|
|
156
138
|
#define ALLOC_SAMPLES_UNSCALED_VALUE_ID 4
|
|
157
|
-
#define HEAP_SAMPLES_VALUE {.type_ = VALUE_STRING("heap-live-samples"), .unit = VALUE_STRING("count")}
|
|
158
139
|
#define HEAP_SAMPLES_VALUE_ID 5
|
|
159
|
-
#define HEAP_SIZE_VALUE {.type_ = VALUE_STRING("heap-live-size"), .unit = VALUE_STRING("bytes")}
|
|
160
140
|
#define HEAP_SIZE_VALUE_ID 6
|
|
161
|
-
#define TIMELINE_VALUE {.type_ = VALUE_STRING("timeline"), .unit = VALUE_STRING("nanoseconds")}
|
|
162
141
|
#define TIMELINE_VALUE_ID 7
|
|
163
142
|
|
|
164
|
-
static const
|
|
165
|
-
|
|
143
|
+
static const ddog_prof_SampleType all_sample_types[] = {
|
|
144
|
+
DDOG_PROF_SAMPLE_TYPE_CPU_TIME,
|
|
145
|
+
DDOG_PROF_SAMPLE_TYPE_CPU_SAMPLES,
|
|
146
|
+
DDOG_PROF_SAMPLE_TYPE_WALL_TIME,
|
|
147
|
+
DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES,
|
|
148
|
+
DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES_UNSCALED,
|
|
149
|
+
DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SAMPLES,
|
|
150
|
+
DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SIZE,
|
|
151
|
+
DDOG_PROF_SAMPLE_TYPE_TIMELINE,
|
|
152
|
+
};
|
|
166
153
|
|
|
167
|
-
// This array MUST be kept in sync with
|
|
168
|
-
// occupies on the
|
|
169
|
-
// 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.
|
|
154
|
+
// This array MUST be kept in sync with all_sample_types above and is intended to act as a "hashmap" between VALUE_ID and the position it
|
|
155
|
+
// occupies on the all_sample_types array.
|
|
170
156
|
static const uint8_t all_value_types_positions[] =
|
|
171
157
|
{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};
|
|
172
158
|
|
|
173
|
-
#define ALL_VALUE_TYPES_COUNT (sizeof(
|
|
159
|
+
#define ALL_VALUE_TYPES_COUNT (sizeof(all_sample_types) / sizeof(ddog_prof_SampleType))
|
|
174
160
|
|
|
175
161
|
// Struct for storing stats related to a profile in a particular slot.
|
|
176
162
|
// These stats will share the same lifetime as the data in that profile slot.
|
|
@@ -242,7 +228,8 @@ typedef struct {
|
|
|
242
228
|
|
|
243
229
|
static VALUE _native_new(VALUE klass);
|
|
244
230
|
static void initialize_slot_concurrency_control(stack_recorder_state *state);
|
|
245
|
-
static void
|
|
231
|
+
static void stack_recorder_typed_data_mark(void *data);
|
|
232
|
+
static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_SampleType sample_types);
|
|
246
233
|
static void stack_recorder_typed_data_free(void *data);
|
|
247
234
|
static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
|
248
235
|
static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
|
|
@@ -271,6 +258,7 @@ static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self,
|
|
|
271
258
|
static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
|
272
259
|
static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all);
|
|
273
260
|
static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self);
|
|
261
|
+
static VALUE _native_finalize_pending_heap_recordings(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
|
274
262
|
|
|
275
263
|
void stack_recorder_init(VALUE profiling_module) {
|
|
276
264
|
VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
|
@@ -307,6 +295,7 @@ void stack_recorder_init(VALUE profiling_module) {
|
|
|
307
295
|
rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
|
|
308
296
|
rb_define_singleton_method(testing_module, "_native_benchmark_intern", _native_benchmark_intern, 4);
|
|
309
297
|
rb_define_singleton_method(testing_module, "_native_test_managed_string_storage_produces_valid_profiles", _native_test_managed_string_storage_produces_valid_profiles, 0);
|
|
298
|
+
rb_define_singleton_method(testing_module, "_native_finalize_pending_heap_recordings", _native_finalize_pending_heap_recordings, 1);
|
|
310
299
|
|
|
311
300
|
ok_symbol = ID2SYM(rb_intern_const("ok"));
|
|
312
301
|
error_symbol = ID2SYM(rb_intern_const("error"));
|
|
@@ -317,9 +306,9 @@ void stack_recorder_init(VALUE profiling_module) {
|
|
|
317
306
|
static const rb_data_type_t stack_recorder_typed_data = {
|
|
318
307
|
.wrap_struct_name = "Datadog::Profiling::StackRecorder",
|
|
319
308
|
.function = {
|
|
309
|
+
.dmark = stack_recorder_typed_data_mark,
|
|
320
310
|
.dfree = stack_recorder_typed_data_free,
|
|
321
311
|
.dsize = NULL, // We don't track profile memory usage (although it'd be cool if we did!)
|
|
322
|
-
// No need to provide dmark nor dcompact because we don't directly reference Ruby VALUEs from inside this object
|
|
323
312
|
},
|
|
324
313
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
325
314
|
};
|
|
@@ -332,7 +321,7 @@ static VALUE _native_new(VALUE klass) {
|
|
|
332
321
|
|
|
333
322
|
state->heap_clean_after_gc_enabled = false;
|
|
334
323
|
|
|
335
|
-
|
|
324
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
|
|
336
325
|
|
|
337
326
|
initialize_slot_concurrency_control(state);
|
|
338
327
|
for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
|
|
@@ -376,7 +365,7 @@ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
|
|
|
376
365
|
state->active_slot = 1;
|
|
377
366
|
}
|
|
378
367
|
|
|
379
|
-
static void initialize_profiles(stack_recorder_state *state,
|
|
368
|
+
static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_SampleType sample_types) {
|
|
380
369
|
ddog_Timespec start_timestamp = system_epoch_now_timespec();
|
|
381
370
|
|
|
382
371
|
ddog_prof_Profile_NewResult slot_one_profile_result =
|
|
@@ -399,6 +388,12 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
|
|
|
399
388
|
state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
|
|
400
389
|
}
|
|
401
390
|
|
|
391
|
+
static void stack_recorder_typed_data_mark(void *state_ptr) {
|
|
392
|
+
stack_recorder_state *state = (stack_recorder_state *) state_ptr;
|
|
393
|
+
|
|
394
|
+
heap_recorder_mark_pending_recordings(state->heap_recorder);
|
|
395
|
+
}
|
|
396
|
+
|
|
402
397
|
static void stack_recorder_typed_data_free(void *state_ptr) {
|
|
403
398
|
stack_recorder_state *state = (stack_recorder_state *) state_ptr;
|
|
404
399
|
|
|
@@ -459,30 +454,30 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
459
454
|
|
|
460
455
|
state->enabled_values_count = requested_values_count;
|
|
461
456
|
|
|
462
|
-
|
|
457
|
+
ddog_prof_SampleType enabled_sample_types[ALL_VALUE_TYPES_COUNT];
|
|
463
458
|
uint8_t next_enabled_pos = 0;
|
|
464
459
|
uint8_t next_disabled_pos = requested_values_count;
|
|
465
460
|
|
|
466
|
-
//
|
|
467
|
-
|
|
461
|
+
// CPU_SAMPLES is always enabled
|
|
462
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_SAMPLES;
|
|
468
463
|
state->position_for[CPU_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
469
464
|
|
|
470
|
-
//
|
|
471
|
-
|
|
465
|
+
// WALL_TIME is always enabled
|
|
466
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_WALL_TIME;
|
|
472
467
|
state->position_for[WALL_TIME_VALUE_ID] = next_enabled_pos++;
|
|
473
468
|
|
|
474
469
|
if (cpu_time_enabled == Qtrue) {
|
|
475
|
-
|
|
470
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_TIME;
|
|
476
471
|
state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
|
|
477
472
|
} else {
|
|
478
473
|
state->position_for[CPU_TIME_VALUE_ID] = next_disabled_pos++;
|
|
479
474
|
}
|
|
480
475
|
|
|
481
476
|
if (alloc_samples_enabled == Qtrue) {
|
|
482
|
-
|
|
477
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES;
|
|
483
478
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
484
479
|
|
|
485
|
-
|
|
480
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES_UNSCALED;
|
|
486
481
|
state->position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID] = next_enabled_pos++;
|
|
487
482
|
} else {
|
|
488
483
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
|
@@ -490,14 +485,14 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
490
485
|
}
|
|
491
486
|
|
|
492
487
|
if (heap_samples_enabled == Qtrue) {
|
|
493
|
-
|
|
488
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SAMPLES;
|
|
494
489
|
state->position_for[HEAP_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
495
490
|
} else {
|
|
496
491
|
state->position_for[HEAP_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
|
497
492
|
}
|
|
498
493
|
|
|
499
494
|
if (heap_size_enabled == Qtrue) {
|
|
500
|
-
|
|
495
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SIZE;
|
|
501
496
|
state->position_for[HEAP_SIZE_VALUE_ID] = next_enabled_pos++;
|
|
502
497
|
} else {
|
|
503
498
|
state->position_for[HEAP_SIZE_VALUE_ID] = next_disabled_pos++;
|
|
@@ -512,7 +507,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
512
507
|
}
|
|
513
508
|
|
|
514
509
|
if (timeline_enabled == Qtrue) {
|
|
515
|
-
|
|
510
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_TIMELINE;
|
|
516
511
|
state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
|
|
517
512
|
} else {
|
|
518
513
|
state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
|
|
@@ -521,7 +516,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
521
516
|
ddog_prof_Profile_drop(&state->profile_slot_one.profile);
|
|
522
517
|
ddog_prof_Profile_drop(&state->profile_slot_two.profile);
|
|
523
518
|
|
|
524
|
-
|
|
519
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = enabled_sample_types, .len = state->enabled_values_count};
|
|
525
520
|
initialize_profiles(state, sample_types);
|
|
526
521
|
|
|
527
522
|
return Qtrue;
|
|
@@ -662,13 +657,14 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
|
|
|
662
657
|
}
|
|
663
658
|
}
|
|
664
659
|
|
|
665
|
-
|
|
660
|
+
// Returns needs_after_allocation: true whenever an after_sample callback is required
|
|
661
|
+
bool track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class) {
|
|
666
662
|
stack_recorder_state *state;
|
|
667
663
|
TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
|
|
668
664
|
// FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
|
|
669
665
|
// very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
|
|
670
666
|
// be fixed with some refactoring but for now this leads to a less impactful change.
|
|
671
|
-
start_heap_allocation_recording(state->heap_recorder, new_object, sample_weight, alloc_class);
|
|
667
|
+
return start_heap_allocation_recording(state->heap_recorder, new_object, sample_weight, alloc_class);
|
|
672
668
|
}
|
|
673
669
|
|
|
674
670
|
void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) {
|
|
@@ -693,6 +689,13 @@ void recorder_after_gc_step(VALUE recorder_instance) {
|
|
|
693
689
|
if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder);
|
|
694
690
|
}
|
|
695
691
|
|
|
692
|
+
void recorder_after_sample(VALUE recorder_instance) {
|
|
693
|
+
stack_recorder_state *state;
|
|
694
|
+
TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
|
|
695
|
+
|
|
696
|
+
heap_recorder_finalize_pending_recordings(state->heap_recorder);
|
|
697
|
+
}
|
|
698
|
+
|
|
696
699
|
#define MAX_LEN_HEAP_ITERATION_ERROR_MSG 256
|
|
697
700
|
|
|
698
701
|
// Heap recorder iteration context allows us access to stack recorder state and profile being serialized
|
|
@@ -934,8 +937,11 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
|
|
|
934
937
|
|
|
935
938
|
static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class) {
|
|
936
939
|
ENFORCE_TYPE(weight, T_FIXNUM);
|
|
937
|
-
track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
|
|
938
|
-
|
|
940
|
+
bool needs_after_allocation = track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
|
|
941
|
+
|
|
942
|
+
// We could instead choose to automatically trigger the after allocation here; yet, it seems kinda nice to keep it manual for
|
|
943
|
+
// the tests so we can pull on each lever separately and observe "the sausage being made" in steps
|
|
944
|
+
return needs_after_allocation ? Qtrue : Qfalse;
|
|
939
945
|
}
|
|
940
946
|
|
|
941
947
|
static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
|
|
@@ -1059,7 +1065,7 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
|
|
|
1059
1065
|
raise_error(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
|
|
1060
1066
|
}
|
|
1061
1067
|
|
|
1062
|
-
|
|
1068
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
|
|
1063
1069
|
ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
|
|
1064
1070
|
|
|
1065
1071
|
if (profile.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
|
@@ -1143,3 +1149,12 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
|
|
|
1143
1149
|
|
|
1144
1150
|
return rb_ary_new_from_args(2, encoded_pprof_1, encoded_pprof_2);
|
|
1145
1151
|
}
|
|
1152
|
+
|
|
1153
|
+
static VALUE _native_finalize_pending_heap_recordings(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
|
|
1154
|
+
stack_recorder_state *state;
|
|
1155
|
+
TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
|
|
1156
|
+
|
|
1157
|
+
heap_recorder_finalize_pending_recordings(state->heap_recorder);
|
|
1158
|
+
|
|
1159
|
+
return Qtrue;
|
|
1160
|
+
}
|
|
@@ -26,6 +26,7 @@ typedef struct {
|
|
|
26
26
|
|
|
27
27
|
void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels);
|
|
28
28
|
void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint);
|
|
29
|
-
|
|
29
|
+
__attribute__((warn_unused_result)) bool track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class);
|
|
30
|
+
void recorder_after_sample(VALUE recorder_instance);
|
|
30
31
|
void recorder_after_gc_step(VALUE recorder_instance);
|
|
31
32
|
VALUE enforce_recorder_instance(VALUE object);
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
|
8
8
|
static VALUE _native_stop(DDTRACE_UNUSED VALUE _self);
|
|
9
9
|
|
|
10
|
+
void crashtracker_report_exception_init(VALUE crashtracker_class);
|
|
11
|
+
|
|
10
12
|
static bool first_init = true;
|
|
11
13
|
|
|
12
14
|
// Used to report Ruby VM crashes.
|
|
@@ -18,6 +20,9 @@ void crashtracker_init(VALUE core_module) {
|
|
|
18
20
|
|
|
19
21
|
rb_define_singleton_method(crashtracker_class, "_native_start_or_update_on_fork", _native_start_or_update_on_fork, -1);
|
|
20
22
|
rb_define_singleton_method(crashtracker_class, "_native_stop", _native_stop, 0);
|
|
23
|
+
|
|
24
|
+
// Initialize Ruby non-signal-crash reporting
|
|
25
|
+
crashtracker_report_exception_init(crashtracker_class);
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#include <datadog/common.h>
|
|
2
|
+
#include <datadog/crashtracker.h>
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
#include "datadog_ruby_common.h"
|
|
6
|
+
|
|
7
|
+
static VALUE _native_report_ruby_exception(VALUE _self, VALUE exception_type,
|
|
8
|
+
VALUE message, VALUE frames_data);
|
|
9
|
+
|
|
10
|
+
static bool process_crash_frames(VALUE frames_data, ddog_crasht_Handle_StackTrace *stack_trace);
|
|
11
|
+
|
|
12
|
+
void crashtracker_report_exception_init(VALUE crashtracker_class) {
|
|
13
|
+
rb_define_singleton_method(crashtracker_class, "_native_report_ruby_exception",
|
|
14
|
+
_native_report_ruby_exception, 3);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static VALUE _native_report_ruby_exception(DDTRACE_UNUSED VALUE _self, VALUE exception_type,
|
|
18
|
+
VALUE message, VALUE frames_data) {
|
|
19
|
+
ENFORCE_TYPE(exception_type, T_STRING);
|
|
20
|
+
ENFORCE_TYPE(message, T_STRING);
|
|
21
|
+
ENFORCE_TYPE(frames_data, T_ARRAY);
|
|
22
|
+
|
|
23
|
+
// Build stack trace
|
|
24
|
+
ddog_crasht_StackTrace_NewResult stack_result = ddog_crasht_StackTrace_new();
|
|
25
|
+
if (stack_result.tag != DDOG_CRASHT_STACK_TRACE_NEW_RESULT_OK) {
|
|
26
|
+
ddog_Error_drop(&stack_result.err);
|
|
27
|
+
return Qfalse;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ddog_crasht_Handle_StackTrace *stack_trace = &stack_result.ok;
|
|
31
|
+
|
|
32
|
+
bool frames_ok = process_crash_frames(frames_data, stack_trace);
|
|
33
|
+
if (frames_ok) {
|
|
34
|
+
ddog_VoidResult complete_result = ddog_crasht_StackTrace_set_complete(stack_trace);
|
|
35
|
+
if (complete_result.tag != DDOG_VOID_RESULT_OK) {
|
|
36
|
+
ddog_crasht_StackTrace_drop(stack_trace);
|
|
37
|
+
ddog_Error_drop(&complete_result.err);
|
|
38
|
+
return Qfalse;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ddog_crasht_report_unhandled_exception takes ownership of stack_trace
|
|
43
|
+
ddog_VoidResult result = ddog_crasht_report_unhandled_exception(
|
|
44
|
+
char_slice_from_ruby_string(exception_type),
|
|
45
|
+
char_slice_from_ruby_string(message),
|
|
46
|
+
stack_trace
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (result.tag != DDOG_VOID_RESULT_OK) {
|
|
50
|
+
ddog_Error_drop(&result.err);
|
|
51
|
+
return Qfalse;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return Qtrue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static bool process_crash_frames(VALUE frames_data, ddog_crasht_Handle_StackTrace *stack_trace) {
|
|
58
|
+
size_t frame_count = RARRAY_LEN(frames_data);
|
|
59
|
+
|
|
60
|
+
// Return false and early so we can mark the stack as incomplete
|
|
61
|
+
// libdatadog's definition of an incomplete stack is that it has no frames
|
|
62
|
+
// or that report generation died in the middle of unwinding frames
|
|
63
|
+
if (frame_count == 0) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (size_t i = 0; i < frame_count; i++) {
|
|
68
|
+
VALUE frame_array = RARRAY_AREF(frames_data, i);
|
|
69
|
+
|
|
70
|
+
// ruby should guarantee [String, String, Integer]
|
|
71
|
+
if (!RB_TYPE_P(frame_array, T_ARRAY) || RARRAY_LEN(frame_array) != 3) {
|
|
72
|
+
// Malformed data from Ruby; this is a bug, bail out
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
VALUE file_val = RARRAY_AREF(frame_array, 0);
|
|
77
|
+
VALUE func_val = RARRAY_AREF(frame_array, 1);
|
|
78
|
+
VALUE line_val = RARRAY_AREF(frame_array, 2);
|
|
79
|
+
|
|
80
|
+
// validate types; Ruby should guarantee these
|
|
81
|
+
if (!RB_TYPE_P(file_val, T_STRING) || !RB_TYPE_P(func_val, T_STRING) || !RB_TYPE_P(line_val, T_FIXNUM)) {
|
|
82
|
+
// Type mismatch from Ruby; this is a bug, bail out
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
ddog_crasht_StackFrame_NewResult frame_result = ddog_crasht_StackFrame_new();
|
|
87
|
+
if (frame_result.tag != DDOG_CRASHT_STACK_FRAME_NEW_RESULT_OK) {
|
|
88
|
+
ddog_Error_drop(&frame_result.err);
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
ddog_crasht_Handle_StackFrame *frame = &frame_result.ok;
|
|
93
|
+
|
|
94
|
+
ddog_VoidResult file_result = ddog_crasht_StackFrame_with_file(frame, char_slice_from_ruby_string(file_val));
|
|
95
|
+
if (file_result.tag != DDOG_VOID_RESULT_OK) {
|
|
96
|
+
ddog_crasht_StackFrame_drop(frame);
|
|
97
|
+
ddog_Error_drop(&file_result.err);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
ddog_VoidResult func_result = ddog_crasht_StackFrame_with_function(frame, char_slice_from_ruby_string(func_val));
|
|
101
|
+
if (func_result.tag != DDOG_VOID_RESULT_OK) {
|
|
102
|
+
ddog_crasht_StackFrame_drop(frame);
|
|
103
|
+
ddog_Error_drop(&func_result.err);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
uint32_t line = (uint32_t)FIX2INT(line_val);
|
|
108
|
+
if (line > 0) {
|
|
109
|
+
ddog_VoidResult line_result = ddog_crasht_StackFrame_with_line(frame, line);
|
|
110
|
+
if (line_result.tag != DDOG_VOID_RESULT_OK) {
|
|
111
|
+
ddog_crasht_StackFrame_drop(frame);
|
|
112
|
+
ddog_Error_drop(&line_result.err);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
ddog_VoidResult push_result = ddog_crasht_StackTrace_push_frame(stack_trace, frame, true);
|
|
118
|
+
if (push_result.tag != DDOG_VOID_RESULT_OK) {
|
|
119
|
+
ddog_crasht_StackFrame_drop(frame);
|
|
120
|
+
ddog_Error_drop(&push_result.err);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
@@ -40,7 +40,8 @@ append_cflags '-Werror' if ENV['DATADOG_GEM_CI'] == 'true'
|
|
|
40
40
|
# * by upstream Ruby -- search for gnu99 in the codebase
|
|
41
41
|
# * by msgpack, another datadog gem dependency
|
|
42
42
|
# (https://github.com/msgpack/msgpack-ruby/blob/18ce08f6d612fe973843c366ac9a0b74c4e50599/ext/msgpack/extconf.rb#L8)
|
|
43
|
-
|
|
43
|
+
# @ivoanjo: We could probably start using C11/gnu11 for non macOS-too but it's somewhat hard to validate so I chickened out for now
|
|
44
|
+
append_cflags RUBY_PLATFORM.include?('darwin') ? '-std=gnu11' : '-std=gnu99'
|
|
44
45
|
|
|
45
46
|
# Allow defining variables at any point in a function
|
|
46
47
|
append_cflags '-Wno-declaration-after-statement'
|
|
@@ -74,30 +75,12 @@ if ENV['DDTRACE_DEBUG'] == 'true'
|
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
# If we got here, libdatadog is available and loaded
|
|
77
|
-
ENV['PKG_CONFIG_PATH'] = "#{ENV["PKG_CONFIG_PATH"]}:#{Libdatadog.pkgconfig_folder}"
|
|
78
|
-
Logging.message("[datadog] PKG_CONFIG_PATH set to #{ENV["PKG_CONFIG_PATH"].inspect}\n")
|
|
79
78
|
$stderr.puts("Using libdatadog #{Libdatadog::VERSION} from #{Libdatadog.pkgconfig_folder}")
|
|
80
79
|
|
|
81
|
-
unless
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if Datadog::LibdatadogExtconfHelpers.pkg_config_missing?
|
|
85
|
-
skip_building_extension!('the `pkg-config` system tool is missing')
|
|
86
|
-
else
|
|
87
|
-
skip_building_extension!('there was a problem in setting up the `libdatadog` dependency')
|
|
88
|
-
end
|
|
80
|
+
unless Datadog::LibdatadogExtconfHelpers.configure_libdatadog(extconf_folder: __dir__)
|
|
81
|
+
skip_building_extension!('there was a problem in setting up the `libdatadog` dependency')
|
|
89
82
|
end
|
|
90
83
|
|
|
91
|
-
# See comments on the helper methods being used for why we need to additionally set this.
|
|
92
|
-
# The extremely excessive escaping around ORIGIN below seems to be correct and was determined after a lot of
|
|
93
|
-
# experimentation. We need to get these special characters across a lot of tools untouched...
|
|
94
|
-
extra_relative_rpaths = [
|
|
95
|
-
Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_native_lib_folder(current_folder: __dir__),
|
|
96
|
-
*Datadog::LibdatadogExtconfHelpers.libdatadog_folder_relative_to_ruby_extensions_folders,
|
|
97
|
-
]
|
|
98
|
-
extra_relative_rpaths.each { |folder| $LDFLAGS += " -Wl,-rpath,$$$\\\\{ORIGIN\\}/#{folder.to_str}" }
|
|
99
|
-
Logging.message("[datadog] After pkg-config $LDFLAGS were set to: #{$LDFLAGS.inspect}\n")
|
|
100
|
-
|
|
101
84
|
# Tag the native extension library with the Ruby version and Ruby platform.
|
|
102
85
|
# This makes it easier for development (avoids "oops I forgot to rebuild when I switched my Ruby") and ensures that
|
|
103
86
|
# the wrong library is never loaded.
|
|
@@ -10,7 +10,7 @@ module Datadog
|
|
|
10
10
|
module LibdatadogExtconfHelpers
|
|
11
11
|
# Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
|
|
12
12
|
# may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
|
|
13
|
-
LIBDATADOG_VERSION = '~>
|
|
13
|
+
LIBDATADOG_VERSION = '~> 29.0.0.1.0'
|
|
14
14
|
|
|
15
15
|
# Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
|
|
16
16
|
# libdatadog are moved after the extension gets compiled.
|
|
@@ -23,9 +23,9 @@ module Datadog
|
|
|
23
23
|
# Linux: e.g. `readelf -d datadog_profiling_native_extension.2.7.3_x86_64-linux.so`.
|
|
24
24
|
#
|
|
25
25
|
# In older versions of the datadog gem, we only set as runpath an absolute path to libdatadog.
|
|
26
|
-
# (This gets set automatically by the call
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# (This gets set automatically by the call to `configure_libdatadog` in `extconf.rb`).
|
|
27
|
+
# This worked fine as long as libdatadog was **NOT** moved from the folder it was present at
|
|
28
|
+
# datadog gem installation/linking time.
|
|
29
29
|
#
|
|
30
30
|
# Unfortunately, environments such as Heroku and AWS Elastic Beanstalk move gems around in the filesystem after
|
|
31
31
|
# installation. Thus, the profiling native extension could not be loaded in these environments
|
|
@@ -47,12 +47,12 @@ module Datadog
|
|
|
47
47
|
# we could setup when doing a `require`.
|
|
48
48
|
#
|
|
49
49
|
def self.libdatadog_folder_relative_to_native_lib_folder(
|
|
50
|
-
|
|
50
|
+
extconf_folder:,
|
|
51
51
|
libdatadog_pkgconfig_folder: Libdatadog.pkgconfig_folder
|
|
52
52
|
)
|
|
53
53
|
return unless libdatadog_pkgconfig_folder
|
|
54
54
|
|
|
55
|
-
native_lib_folder = "#{
|
|
55
|
+
native_lib_folder = "#{extconf_folder}/../../lib/"
|
|
56
56
|
libdatadog_lib_folder = "#{libdatadog_pkgconfig_folder}/../"
|
|
57
57
|
|
|
58
58
|
Pathname.new(libdatadog_lib_folder).relative_path_from(Pathname.new(native_lib_folder)).to_s
|
|
@@ -104,13 +104,51 @@ module Datadog
|
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
# Directly configures mkmf to link against libdatadog by setting $INCFLAGS, $LDFLAGS, and $libs.
|
|
108
|
+
#
|
|
109
|
+
# This replaces the previous use of mkmf's `pkg_config("datadog_profiling_with_rpath")`, removing the need for
|
|
110
|
+
# the pkg-config system tool to be installed.
|
|
111
|
+
#
|
|
112
|
+
# The extconf_folder argument should be the __dir__ of the calling extconf.rb, used to compute relative rpaths.
|
|
113
|
+
# The logger argument is the mkmf Logging module, dependency-injected to make testing easier.
|
|
114
|
+
# rubocop:disable Style/GlobalVars
|
|
115
|
+
def self.configure_libdatadog(
|
|
116
|
+
extconf_folder:,
|
|
117
|
+
libdatadog_pkgconfig_folder: Libdatadog.pkgconfig_folder,
|
|
118
|
+
gem_dir: Gem.dir,
|
|
119
|
+
logger: Logging
|
|
120
|
+
)
|
|
121
|
+
return unless libdatadog_pkgconfig_folder
|
|
122
|
+
|
|
123
|
+
# The lib and include folders are at a fixed relative path from pkgconfig_folder
|
|
124
|
+
libdir = "#{libdatadog_pkgconfig_folder}/../../lib"
|
|
125
|
+
includedir = "#{libdatadog_pkgconfig_folder}/../../include"
|
|
126
|
+
|
|
127
|
+
# Set mkmf global variables
|
|
128
|
+
$INCFLAGS << " -I#{includedir}"
|
|
129
|
+
$LDFLAGS << " -L#{libdir} -Wl,-rpath,#{libdir}"
|
|
130
|
+
$libs << " -ldatadog_profiling"
|
|
131
|
+
|
|
132
|
+
# Add extra relative rpaths using $ORIGIN to handle environments where gems are moved after installation.
|
|
133
|
+
# The excessive escaping is needed to get these special characters through Make and the shell untouched.
|
|
134
|
+
extra_relative_rpaths = [
|
|
135
|
+
libdatadog_folder_relative_to_native_lib_folder(
|
|
136
|
+
extconf_folder: extconf_folder,
|
|
137
|
+
libdatadog_pkgconfig_folder: libdatadog_pkgconfig_folder,
|
|
138
|
+
),
|
|
139
|
+
*libdatadog_folder_relative_to_ruby_extensions_folders(
|
|
140
|
+
gem_dir: gem_dir,
|
|
141
|
+
libdatadog_pkgconfig_folder: libdatadog_pkgconfig_folder,
|
|
142
|
+
),
|
|
143
|
+
]
|
|
144
|
+
extra_relative_rpaths.each { |folder| $LDFLAGS << " -Wl,-rpath,$$$\\\\{ORIGIN\\}/#{folder}" }
|
|
145
|
+
|
|
146
|
+
logger.message("linking with libdatadog (include=#{includedir}, lib=#{libdir})\n")
|
|
147
|
+
logger.message("[datadog] $LDFLAGS were set to: #{$LDFLAGS.inspect}\n")
|
|
111
148
|
|
|
112
|
-
|
|
149
|
+
true
|
|
113
150
|
end
|
|
151
|
+
# rubocop:enable Style/GlobalVars
|
|
114
152
|
|
|
115
153
|
def self.try_loading_libdatadog
|
|
116
154
|
gem 'libdatadog', LIBDATADOG_VERSION
|
|
@@ -17,6 +17,9 @@ module Datadog
|
|
|
17
17
|
base.class_eval do
|
|
18
18
|
# AI Guard specific configurations.
|
|
19
19
|
# @public_api
|
|
20
|
+
#
|
|
21
|
+
# Steep does not update `self` for this `class_eval` block.
|
|
22
|
+
# @type self: Datadog::Core::Configuration::Base::_DslContext
|
|
20
23
|
settings :ai_guard do
|
|
21
24
|
# Enable AI Guard.
|
|
22
25
|
#
|