datadog 2.29.0 → 2.31.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 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +21 -12
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +9 -7
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -24
- data/ext/datadog_profiling_native_extension/heap_recorder.c +5 -6
- 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 +29 -43
- data/ext/libdatadog_api/crashtracker.c +5 -8
- data/ext/libdatadog_api/crashtracker_report_exception.c +34 -144
- data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
- data/ext/libdatadog_api/di.c +79 -0
- data/ext/libdatadog_api/extconf.rb +5 -20
- data/ext/libdatadog_api/init.c +5 -2
- data/ext/libdatadog_extconf_helpers.rb +57 -11
- data/lib/datadog/ai_guard/component.rb +2 -0
- data/lib/datadog/ai_guard/configuration/settings.rb +3 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
- data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation.rb +36 -7
- data/lib/datadog/ai_guard.rb +26 -8
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -7
- 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 +1 -1
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +25 -2
- 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/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +2 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +3 -3
- 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 -15
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -2
- data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
- data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
- data/lib/datadog/appsec.rb +5 -9
- data/lib/datadog/core/configuration/base.rb +17 -5
- data/lib/datadog/core/configuration/components.rb +21 -8
- data/lib/datadog/core/configuration/config_helper.rb +9 -0
- data/lib/datadog/core/configuration/option.rb +32 -6
- data/lib/datadog/core/configuration/option_definition.rb +38 -12
- data/lib/datadog/core/configuration/options.rb +41 -7
- data/lib/datadog/core/configuration/settings.rb +42 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +17 -0
- data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
- data/lib/datadog/core/contrib/rails/utils.rb +7 -3
- data/lib/datadog/core/crashtracking/component.rb +7 -15
- data/lib/datadog/core/environment/container.rb +2 -2
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +25 -3
- data/lib/datadog/core/environment/process.rb +12 -0
- data/lib/datadog/core/metrics/client.rb +5 -5
- data/lib/datadog/core/process_discovery.rb +5 -0
- data/lib/datadog/core/remote/component.rb +38 -21
- data/lib/datadog/core/runtime/metrics.rb +2 -3
- data/lib/datadog/core/telemetry/component.rb +3 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
- data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
- data/lib/datadog/core/telemetry/event.rb +1 -7
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
- data/lib/datadog/core/telemetry/worker.rb +20 -0
- data/lib/datadog/core/utils/base64.rb +1 -1
- data/lib/datadog/core/utils/only_once.rb +1 -1
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- 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 +0 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/data_streams/processor.rb +1 -0
- data/lib/datadog/di/boot.rb +3 -4
- data/lib/datadog/di/component.rb +20 -4
- data/lib/datadog/di/instrumenter.rb +20 -10
- data/lib/datadog/di/probe_manager.rb +79 -62
- data/lib/datadog/di/probe_notification_builder.rb +148 -33
- data/lib/datadog/di/probe_notifier_worker.rb +52 -6
- data/lib/datadog/di/probe_repository.rb +198 -0
- data/lib/datadog/di/remote.rb +5 -6
- data/lib/datadog/di/serializer.rb +127 -9
- data/lib/datadog/di/transport/http.rb +12 -3
- data/lib/datadog/di/transport/input.rb +46 -8
- data/lib/datadog/di.rb +81 -0
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/open_feature/configuration.rb +2 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +1 -1
- data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
- data/lib/datadog/open_feature/exposures/worker.rb +1 -1
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/open_feature/transport.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +2 -3
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +14 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/component.rb +31 -1
- data/lib/datadog/profiling/http_transport.rb +5 -6
- data/lib/datadog/profiling/load_native_extension.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +15 -12
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +2 -2
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/component.rb +11 -0
- data/lib/datadog/tracing/configuration/settings.rb +2 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
- 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 +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/configurable.rb +18 -3
- data/lib/datadog/tracing/contrib/dalli/integration.rb +4 -1
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -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/excon/middleware.rb +2 -2
- 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/faraday/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +7 -7
- 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/instrumentation.rb +1 -1
- 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/httprb/instrumentation.rb +1 -1
- 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/opensearch/patcher.rb +1 -1
- 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/rails/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- 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/status_range_matcher.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -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/distributed/datadog.rb +4 -2
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/remote.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +2 -0
- data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/sync_writer.rb +0 -1
- data/lib/datadog/tracing/trace_operation.rb +50 -6
- data/lib/datadog/tracing/tracer.rb +25 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/writer.rb +0 -1
- data/lib/datadog/version.rb +1 -1
- metadata +15 -8
- data/lib/datadog/tracing/workers/trace_writer.rb +0 -204
|
@@ -104,19 +104,6 @@ module Datadog
|
|
|
104
104
|
suggested: CONTACT_SUPPORT,
|
|
105
105
|
)
|
|
106
106
|
|
|
107
|
-
# Validation for this check is done in extconf.rb because it relies on mkmf
|
|
108
|
-
PKG_CONFIG_IS_MISSING = explain_issue(
|
|
109
|
-
# ----------------------------------------------------------------------------+
|
|
110
|
-
"the `pkg-config` system tool is missing.",
|
|
111
|
-
"This issue can usually be fixed by installing one of the following:",
|
|
112
|
-
"the `pkg-config` package on Homebrew and Debian/Ubuntu-based Linux;",
|
|
113
|
-
"the `pkgconf` package on Arch and Alpine-based Linux;",
|
|
114
|
-
"the `pkgconf-pkg-config` package on Fedora/Red Hat-based Linux.",
|
|
115
|
-
"(Tip: When fixing this, ensure `pkg-config` is installed **before**",
|
|
116
|
-
"running `bundle install`, and remember to clear any installed gems cache).",
|
|
117
|
-
suggested: CONTACT_SUPPORT,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
107
|
# Validation for this check is done in extconf.rb because it relies on mkmf
|
|
121
108
|
COMPILER_ATOMIC_MISSING = explain_issue(
|
|
122
109
|
"your C compiler is missing support for the <stdatomic.h> header.",
|
|
@@ -25,6 +25,7 @@ void encoded_profile_init(VALUE profiling_module);
|
|
|
25
25
|
void http_transport_init(VALUE profiling_module);
|
|
26
26
|
void stack_recorder_init(VALUE profiling_module);
|
|
27
27
|
void crashtracking_runtime_stacks_init(void);
|
|
28
|
+
void setup_signal_handler_init(VALUE profiling_module);
|
|
28
29
|
|
|
29
30
|
static VALUE native_working_p(VALUE self);
|
|
30
31
|
static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE exception_class, VALUE test_message, VALUE test_message_arg, VALUE release_gvl);
|
|
@@ -62,6 +63,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
|
62
63
|
rb_funcall(native_extension_module, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("native_working?")));
|
|
63
64
|
|
|
64
65
|
ruby_helpers_init();
|
|
66
|
+
setup_signal_handler_init(profiling_module);
|
|
65
67
|
collectors_cpu_and_wall_time_worker_init(profiling_module);
|
|
66
68
|
collectors_discrete_dynamic_sampler_init(profiling_module);
|
|
67
69
|
collectors_dynamic_sampling_rate_init(profiling_module);
|
|
@@ -251,7 +253,7 @@ static VALUE _native_trigger_holding_the_gvl_signal_handler_on(DDTRACE_UNUSED VA
|
|
|
251
253
|
|
|
252
254
|
ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(&holding_the_gvl_signal_handler_mutex));
|
|
253
255
|
|
|
254
|
-
replace_sigprof_signal_handler_with_empty_handler(holding_the_gvl_signal_handler);
|
|
256
|
+
replace_sigprof_signal_handler_with_empty_handler(holding_the_gvl_signal_handler, true);
|
|
255
257
|
|
|
256
258
|
if (holding_the_gvl_signal_handler_result[0] == Qfalse) raise_error(rb_eRuntimeError, "Could not signal background_thread");
|
|
257
259
|
|
|
@@ -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,8 +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 initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
|
|
246
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);
|
|
247
233
|
static void stack_recorder_typed_data_free(void *data);
|
|
248
234
|
static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
|
249
235
|
static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
|
|
@@ -335,7 +321,7 @@ static VALUE _native_new(VALUE klass) {
|
|
|
335
321
|
|
|
336
322
|
state->heap_clean_after_gc_enabled = false;
|
|
337
323
|
|
|
338
|
-
|
|
324
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
|
|
339
325
|
|
|
340
326
|
initialize_slot_concurrency_control(state);
|
|
341
327
|
for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
|
|
@@ -379,7 +365,7 @@ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
|
|
|
379
365
|
state->active_slot = 1;
|
|
380
366
|
}
|
|
381
367
|
|
|
382
|
-
static void initialize_profiles(stack_recorder_state *state,
|
|
368
|
+
static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_SampleType sample_types) {
|
|
383
369
|
ddog_Timespec start_timestamp = system_epoch_now_timespec();
|
|
384
370
|
|
|
385
371
|
ddog_prof_Profile_NewResult slot_one_profile_result =
|
|
@@ -468,30 +454,30 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
468
454
|
|
|
469
455
|
state->enabled_values_count = requested_values_count;
|
|
470
456
|
|
|
471
|
-
|
|
457
|
+
ddog_prof_SampleType enabled_sample_types[ALL_VALUE_TYPES_COUNT];
|
|
472
458
|
uint8_t next_enabled_pos = 0;
|
|
473
459
|
uint8_t next_disabled_pos = requested_values_count;
|
|
474
460
|
|
|
475
|
-
//
|
|
476
|
-
|
|
461
|
+
// CPU_SAMPLES is always enabled
|
|
462
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_SAMPLES;
|
|
477
463
|
state->position_for[CPU_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
478
464
|
|
|
479
|
-
//
|
|
480
|
-
|
|
465
|
+
// WALL_TIME is always enabled
|
|
466
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_WALL_TIME;
|
|
481
467
|
state->position_for[WALL_TIME_VALUE_ID] = next_enabled_pos++;
|
|
482
468
|
|
|
483
469
|
if (cpu_time_enabled == Qtrue) {
|
|
484
|
-
|
|
470
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_TIME;
|
|
485
471
|
state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
|
|
486
472
|
} else {
|
|
487
473
|
state->position_for[CPU_TIME_VALUE_ID] = next_disabled_pos++;
|
|
488
474
|
}
|
|
489
475
|
|
|
490
476
|
if (alloc_samples_enabled == Qtrue) {
|
|
491
|
-
|
|
477
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES;
|
|
492
478
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
493
479
|
|
|
494
|
-
|
|
480
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES_UNSCALED;
|
|
495
481
|
state->position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID] = next_enabled_pos++;
|
|
496
482
|
} else {
|
|
497
483
|
state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
|
@@ -499,14 +485,14 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
499
485
|
}
|
|
500
486
|
|
|
501
487
|
if (heap_samples_enabled == Qtrue) {
|
|
502
|
-
|
|
488
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SAMPLES;
|
|
503
489
|
state->position_for[HEAP_SAMPLES_VALUE_ID] = next_enabled_pos++;
|
|
504
490
|
} else {
|
|
505
491
|
state->position_for[HEAP_SAMPLES_VALUE_ID] = next_disabled_pos++;
|
|
506
492
|
}
|
|
507
493
|
|
|
508
494
|
if (heap_size_enabled == Qtrue) {
|
|
509
|
-
|
|
495
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SIZE;
|
|
510
496
|
state->position_for[HEAP_SIZE_VALUE_ID] = next_enabled_pos++;
|
|
511
497
|
} else {
|
|
512
498
|
state->position_for[HEAP_SIZE_VALUE_ID] = next_disabled_pos++;
|
|
@@ -521,7 +507,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
521
507
|
}
|
|
522
508
|
|
|
523
509
|
if (timeline_enabled == Qtrue) {
|
|
524
|
-
|
|
510
|
+
enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_TIMELINE;
|
|
525
511
|
state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
|
|
526
512
|
} else {
|
|
527
513
|
state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
|
|
@@ -530,7 +516,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
|
|
|
530
516
|
ddog_prof_Profile_drop(&state->profile_slot_one.profile);
|
|
531
517
|
ddog_prof_Profile_drop(&state->profile_slot_two.profile);
|
|
532
518
|
|
|
533
|
-
|
|
519
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = enabled_sample_types, .len = state->enabled_values_count};
|
|
534
520
|
initialize_profiles(state, sample_types);
|
|
535
521
|
|
|
536
522
|
return Qtrue;
|
|
@@ -1079,7 +1065,7 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
|
|
|
1079
1065
|
raise_error(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
|
|
1080
1066
|
}
|
|
1081
1067
|
|
|
1082
|
-
|
|
1068
|
+
ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
|
|
1083
1069
|
ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
|
|
1084
1070
|
|
|
1085
1071
|
if (profile.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
|
@@ -51,12 +51,8 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
|
51
51
|
|
|
52
52
|
VALUE version = datadog_gem_version();
|
|
53
53
|
|
|
54
|
-
// Tags
|
|
54
|
+
// Tags are heap-allocated, so after here we can't raise exceptions otherwise we'll leak this memory
|
|
55
55
|
// Start of exception-free zone to prevent leaks {{
|
|
56
|
-
ddog_Endpoint *endpoint = ddog_endpoint_from_url(char_slice_from_ruby_string(agent_base_url));
|
|
57
|
-
if (endpoint == NULL) {
|
|
58
|
-
raise_error(rb_eRuntimeError, "Failed to create endpoint from agent_base_url: %"PRIsVALUE, agent_base_url);
|
|
59
|
-
}
|
|
60
56
|
ddog_Vec_Tag tags = convert_tags(tags_as_array);
|
|
61
57
|
|
|
62
58
|
ddog_crasht_Config config = {
|
|
@@ -73,7 +69,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
|
73
69
|
// overriding what Ruby set up seems a saner default to keep anyway.
|
|
74
70
|
.create_alt_stack = false,
|
|
75
71
|
.use_alt_stack = true,
|
|
76
|
-
.endpoint =
|
|
72
|
+
.endpoint = {.url = char_slice_from_ruby_string(agent_base_url)},
|
|
77
73
|
.resolve_frames = DDOG_CRASHT_STACKTRACE_COLLECTION_ENABLED_WITH_SYMBOLS_IN_RECEIVER,
|
|
78
74
|
.timeout_ms = FIX2INT(upload_timeout_seconds) * 1000,
|
|
79
75
|
};
|
|
@@ -106,11 +102,12 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
|
|
|
106
102
|
) :
|
|
107
103
|
ddog_crasht_update_on_fork(config, receiver_config, metadata);
|
|
108
104
|
|
|
109
|
-
first_init
|
|
105
|
+
// We use first_init to know which of [init, reconfigure] needs to be called. BUT if init failed we actually need
|
|
106
|
+
// to call init next time again, not reconfigure.
|
|
107
|
+
if (result.tag == DDOG_VOID_RESULT_OK) first_init = false;
|
|
110
108
|
|
|
111
109
|
// Clean up before potentially raising any exceptions
|
|
112
110
|
ddog_Vec_Tag_drop(tags);
|
|
113
|
-
ddog_endpoint_drop(endpoint);
|
|
114
111
|
// }} End of exception-free zone to prevent leaks
|
|
115
112
|
|
|
116
113
|
CHECK_VOID_RESULT("Failed to start/update the crash tracker", result);
|
|
@@ -1,53 +1,57 @@
|
|
|
1
1
|
#include <datadog/common.h>
|
|
2
2
|
#include <datadog/crashtracker.h>
|
|
3
3
|
#include <ruby.h>
|
|
4
|
-
#include <sys/types.h>
|
|
5
|
-
#include <unistd.h>
|
|
6
|
-
#include <string.h>
|
|
7
4
|
|
|
8
5
|
#include "datadog_ruby_common.h"
|
|
9
6
|
|
|
10
|
-
static VALUE _native_report_ruby_exception(VALUE _self, VALUE
|
|
11
|
-
VALUE message, VALUE frames_data
|
|
12
|
-
VALUE tags_as_array, VALUE library_version);
|
|
7
|
+
static VALUE _native_report_ruby_exception(VALUE _self, VALUE exception_type,
|
|
8
|
+
VALUE message, VALUE frames_data);
|
|
13
9
|
|
|
14
10
|
static bool process_crash_frames(VALUE frames_data, ddog_crasht_Handle_StackTrace *stack_trace);
|
|
15
|
-
static bool build_and_send_crash_report(ddog_crasht_Metadata metadata,
|
|
16
|
-
ddog_Endpoint *endpoint,
|
|
17
|
-
VALUE message,
|
|
18
|
-
VALUE frames_data);
|
|
19
11
|
|
|
20
12
|
void crashtracker_report_exception_init(VALUE crashtracker_class) {
|
|
21
13
|
rb_define_singleton_method(crashtracker_class, "_native_report_ruby_exception",
|
|
22
|
-
_native_report_ruby_exception,
|
|
14
|
+
_native_report_ruby_exception, 3);
|
|
23
15
|
}
|
|
24
16
|
|
|
25
|
-
static VALUE _native_report_ruby_exception(DDTRACE_UNUSED VALUE _self, VALUE
|
|
26
|
-
VALUE message, VALUE frames_data
|
|
27
|
-
|
|
28
|
-
ENFORCE_TYPE(agent_base_url, T_STRING);
|
|
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);
|
|
29
20
|
ENFORCE_TYPE(message, T_STRING);
|
|
30
21
|
ENFORCE_TYPE(frames_data, T_ARRAY);
|
|
31
|
-
ENFORCE_TYPE(tags_as_array, T_ARRAY);
|
|
32
|
-
ENFORCE_TYPE(library_version, T_STRING);
|
|
33
22
|
|
|
34
|
-
|
|
35
|
-
|
|
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
|
+
}
|
|
36
29
|
|
|
37
|
-
|
|
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
|
+
}
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
+
);
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if (result.tag != DDOG_VOID_RESULT_OK) {
|
|
50
|
+
ddog_Error_drop(&result.err);
|
|
51
|
+
return Qfalse;
|
|
52
|
+
}
|
|
49
53
|
|
|
50
|
-
return
|
|
54
|
+
return Qtrue;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
static bool process_crash_frames(VALUE frames_data, ddog_crasht_Handle_StackTrace *stack_trace) {
|
|
@@ -120,117 +124,3 @@ static bool process_crash_frames(VALUE frames_data, ddog_crasht_Handle_StackTrac
|
|
|
120
124
|
|
|
121
125
|
return true;
|
|
122
126
|
}
|
|
123
|
-
|
|
124
|
-
static bool build_and_send_crash_report(ddog_crasht_Metadata metadata,
|
|
125
|
-
ddog_Endpoint *endpoint,
|
|
126
|
-
VALUE message,
|
|
127
|
-
VALUE frames_data) {
|
|
128
|
-
ddog_crasht_Handle_StackTrace *stack_trace = NULL;
|
|
129
|
-
|
|
130
|
-
ddog_crasht_CrashInfoBuilder_NewResult builder_result = ddog_crasht_CrashInfoBuilder_new();
|
|
131
|
-
if (builder_result.tag != DDOG_CRASHT_CRASH_INFO_BUILDER_NEW_RESULT_OK) {
|
|
132
|
-
ddog_Error_drop(&builder_result.err);
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
ddog_crasht_Handle_CrashInfoBuilder *builder = &builder_result.ok;
|
|
137
|
-
|
|
138
|
-
// Setup builder metadata and configuration
|
|
139
|
-
ddog_VoidResult metadata_result = ddog_crasht_CrashInfoBuilder_with_metadata(builder, metadata);
|
|
140
|
-
if (metadata_result.tag != DDOG_VOID_RESULT_OK) {
|
|
141
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
142
|
-
ddog_Error_drop(&metadata_result.err);
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
ddog_VoidResult kind_result = ddog_crasht_CrashInfoBuilder_with_kind(builder, DDOG_CRASHT_ERROR_KIND_UNHANDLED_EXCEPTION);
|
|
147
|
-
if (kind_result.tag != DDOG_VOID_RESULT_OK) {
|
|
148
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
149
|
-
ddog_Error_drop(&kind_result.err);
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Send ping first
|
|
154
|
-
ddog_VoidResult ping_result = ddog_crasht_CrashInfoBuilder_upload_ping_to_endpoint(builder, endpoint);
|
|
155
|
-
if (ping_result.tag != DDOG_VOID_RESULT_OK) {
|
|
156
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
157
|
-
ddog_Error_drop(&ping_result.err);
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
ddog_crasht_ProcInfo proc_info = { .pid = (uint32_t)getpid() };
|
|
162
|
-
ddog_VoidResult proc_info_result = ddog_crasht_CrashInfoBuilder_with_proc_info(builder, proc_info);
|
|
163
|
-
if (proc_info_result.tag != DDOG_VOID_RESULT_OK) {
|
|
164
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
165
|
-
ddog_Error_drop(&proc_info_result.err);
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
ddog_VoidResult os_info_result = ddog_crasht_CrashInfoBuilder_with_os_info_this_machine(builder);
|
|
170
|
-
if (os_info_result.tag != DDOG_VOID_RESULT_OK) {
|
|
171
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
172
|
-
ddog_Error_drop(&os_info_result.err);
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
ddog_VoidResult message_result = ddog_crasht_CrashInfoBuilder_with_message(builder, char_slice_from_ruby_string(message));
|
|
177
|
-
if (message_result.tag != DDOG_VOID_RESULT_OK) {
|
|
178
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
179
|
-
ddog_Error_drop(&message_result.err);
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Create and populate stack trace
|
|
184
|
-
ddog_crasht_StackTrace_NewResult stack_result = ddog_crasht_StackTrace_new();
|
|
185
|
-
if (stack_result.tag != DDOG_CRASHT_STACK_TRACE_NEW_RESULT_OK) {
|
|
186
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
187
|
-
ddog_Error_drop(&stack_result.err);
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
stack_trace = &stack_result.ok;
|
|
192
|
-
|
|
193
|
-
bool frames_processed_successfully = process_crash_frames(frames_data, stack_trace);
|
|
194
|
-
|
|
195
|
-
// Only mark as complete if we successfully processed all frames
|
|
196
|
-
if (frames_processed_successfully) {
|
|
197
|
-
ddog_VoidResult complete_result = ddog_crasht_StackTrace_set_complete(stack_trace);
|
|
198
|
-
if (complete_result.tag != DDOG_VOID_RESULT_OK) {
|
|
199
|
-
ddog_crasht_StackTrace_drop(stack_trace);
|
|
200
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
201
|
-
ddog_Error_drop(&complete_result.err);
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
// If frames processing failed, we still include the stack trace (which may be empty or partial)
|
|
206
|
-
// but don't mark it as complete, indicating it's incomplete
|
|
207
|
-
|
|
208
|
-
ddog_VoidResult with_stack_result = ddog_crasht_CrashInfoBuilder_with_stack(builder, stack_trace);
|
|
209
|
-
if (with_stack_result.tag != DDOG_VOID_RESULT_OK) {
|
|
210
|
-
ddog_crasht_StackTrace_drop(stack_trace);
|
|
211
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
212
|
-
ddog_Error_drop(&with_stack_result.err);
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Builder takes ownership of stack_trace, so we don't need to clean it up anymore
|
|
217
|
-
stack_trace = NULL;
|
|
218
|
-
|
|
219
|
-
// Build and upload crash info
|
|
220
|
-
ddog_crasht_CrashInfo_NewResult crash_info_result = ddog_crasht_CrashInfoBuilder_build(builder);
|
|
221
|
-
if (crash_info_result.tag != DDOG_CRASHT_RESULT_HANDLE_CRASH_INFO_OK_HANDLE_CRASH_INFO) {
|
|
222
|
-
ddog_crasht_CrashInfoBuilder_drop(builder);
|
|
223
|
-
ddog_Error_drop(&crash_info_result.err);
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
ddog_crasht_Handle_CrashInfo *crash_info = &crash_info_result.ok;
|
|
228
|
-
ddog_VoidResult upload_result = ddog_crasht_CrashInfo_upload_to_endpoint(crash_info, endpoint);
|
|
229
|
-
bool success = (upload_result.tag == DDOG_VOID_RESULT_OK);
|
|
230
|
-
if (!success) {
|
|
231
|
-
ddog_Error_drop(&upload_result.err);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
ddog_crasht_CrashInfo_drop(crash_info);
|
|
235
|
-
return success;
|
|
236
|
-
}
|
|
@@ -122,6 +122,24 @@ size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capa
|
|
|
122
122
|
return error_msg_size;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
static void verify_libdatadog_version(void) {
|
|
126
|
+
rb_eval_string(
|
|
127
|
+
"require 'libdatadog';"
|
|
128
|
+
"expected = '" EXPECTED_LIBDATADOG_VERSION "';"
|
|
129
|
+
"if expected != Libdatadog::VERSION;"
|
|
130
|
+
"raise(LoadError, <<MSG\n"
|
|
131
|
+
"The `datadog` gem needs to be reinstalled whenever the `libdatadog` gem version is changed. "
|
|
132
|
+
"The currently-installed version of `datadog` was built to work with `libdatadog` gem version #{expected} "
|
|
133
|
+
"but the currently-loaded version of `libdatadog` is #{Libdatadog::VERSION}. "
|
|
134
|
+
"To fix this, reinstall the `datadog` gem (e.g. `bundle exec gem pristine datadog`) "
|
|
135
|
+
"or contact Datadog support for help at <https://docs.datadoghq.com/help/>.\n"
|
|
136
|
+
"MSG\n"
|
|
137
|
+
");"
|
|
138
|
+
"end"
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
125
142
|
void datadog_ruby_common_init(void) {
|
|
126
143
|
telemetry_message_id = rb_intern("@telemetry_message");
|
|
144
|
+
verify_libdatadog_version();
|
|
127
145
|
}
|
|
@@ -102,3 +102,13 @@ static inline VALUE get_error_details_and_drop(ddog_Error *error) {
|
|
|
102
102
|
// Returns the amount of characters written to string (which are necessarily
|
|
103
103
|
// bounded by capacity - 1 since the string will be null-terminated).
|
|
104
104
|
size_t read_ddogerr_string_and_drop(ddog_Error *error, char *string, size_t capacity);
|
|
105
|
+
|
|
106
|
+
#define IMEMO_MASK 0x0f
|
|
107
|
+
|
|
108
|
+
// Returns the imemo type of an imemo object.
|
|
109
|
+
// This mask is the same between Ruby 2.5 and 3.3-preview3. Furthermore, the intention of this method is to be used
|
|
110
|
+
// to call `rb_imemo_name` which correctly handles invalid numbers so even if the mask changes in the future, at most
|
|
111
|
+
// we'll get incorrect results (and never a VM crash)
|
|
112
|
+
static inline int ddtrace_imemo_type(VALUE imemo) {
|
|
113
|
+
return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK;
|
|
114
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#include <stdbool.h>
|
|
2
|
+
|
|
3
|
+
#include "datadog_ruby_common.h"
|
|
4
|
+
|
|
5
|
+
// Prototypes for Ruby functions declared in internal Ruby headers.
|
|
6
|
+
VALUE rb_iseqw_new(const void *iseq);
|
|
7
|
+
int rb_objspace_internal_object_p(VALUE obj);
|
|
8
|
+
void rb_objspace_each_objects(
|
|
9
|
+
int (*callback)(void *start, void *end, size_t stride, void *data),
|
|
10
|
+
void *data);
|
|
11
|
+
|
|
12
|
+
#define IMEMO_TYPE_ISEQ 7
|
|
13
|
+
|
|
14
|
+
// The ID value of the string "mesg" which is used in Ruby source as
|
|
15
|
+
// id_mesg or idMesg, and is used to set and retrieve the exception message
|
|
16
|
+
// from standard library exception classes like NameError.
|
|
17
|
+
static ID id_mesg;
|
|
18
|
+
|
|
19
|
+
// Returns whether the argument is an IMEMO of type ISEQ.
|
|
20
|
+
static bool ddtrace_imemo_iseq_p(VALUE v) {
|
|
21
|
+
return rb_objspace_internal_object_p(v) && RB_TYPE_P(v, T_IMEMO) && ddtrace_imemo_type(v) == IMEMO_TYPE_ISEQ;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static int ddtrace_di_os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
|
|
25
|
+
{
|
|
26
|
+
VALUE *array = (VALUE *)data;
|
|
27
|
+
|
|
28
|
+
VALUE v = (VALUE)vstart;
|
|
29
|
+
for (; v != (VALUE)vend; v += stride) {
|
|
30
|
+
if (ddtrace_imemo_iseq_p(v)) {
|
|
31
|
+
VALUE iseq = rb_iseqw_new((void *) v);
|
|
32
|
+
rb_ary_push(*array, iseq);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
Returns all RubyVM::InstructionSequence objects existing in the current process.
|
|
41
|
+
|
|
42
|
+
This uses the same approach as ruby/debug's iseq_collector.c:
|
|
43
|
+
https://github.com/ruby/debug/blob/master/ext/debug/iseq_collector.c
|
|
44
|
+
*/
|
|
45
|
+
static VALUE all_iseqs(DDTRACE_UNUSED VALUE _self) {
|
|
46
|
+
VALUE array = rb_ary_new();
|
|
47
|
+
rb_objspace_each_objects(ddtrace_di_os_obj_of_i, &array);
|
|
48
|
+
return array;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* call-seq:
|
|
53
|
+
* DI.exception_message(exception) -> String | Object
|
|
54
|
+
*
|
|
55
|
+
* Returns the exception message associated with the exception via the
|
|
56
|
+
* exception's constructor.
|
|
57
|
+
*
|
|
58
|
+
* This method does not invoke Ruby code and as such will not call
|
|
59
|
+
* the +message+ method, if one is defined on the exception object.
|
|
60
|
+
*
|
|
61
|
+
* Normally, the exception message is a string, however there is no
|
|
62
|
+
* type enforcement done by Ruby for the messages and objects of arbitrary
|
|
63
|
+
* classes can be passed to exception constructors and will, subsequently,
|
|
64
|
+
* be returned by this method.
|
|
65
|
+
*
|
|
66
|
+
* @param exception [Exception] The exception object
|
|
67
|
+
* @return [String | Object] The exception message
|
|
68
|
+
*/
|
|
69
|
+
static VALUE exception_message(DDTRACE_UNUSED VALUE _self, VALUE exception) {
|
|
70
|
+
return rb_ivar_get(exception, id_mesg);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
void di_init(VALUE datadog_module) {
|
|
74
|
+
id_mesg = rb_intern("mesg");
|
|
75
|
+
|
|
76
|
+
VALUE di_module = rb_define_module_under(datadog_module, "DI");
|
|
77
|
+
rb_define_singleton_method(di_module, "all_iseqs", all_iseqs, 0);
|
|
78
|
+
rb_define_singleton_method(di_module, "exception_message", exception_message, 1);
|
|
79
|
+
}
|