datadog 2.45.0 → 2.47.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 +49 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +31 -14
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +5 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +5 -0
- data/ext/datadog_profiling_native_extension/profiling.c +6 -0
- data/ext/libdatadog_api/di.c +30 -5
- data/ext/libdatadog_api/extconf.rb +2 -0
- data/ext/libdatadog_api/otel_thread_context.c +20 -14
- data/ext/libdatadog_api/process_discovery.c +15 -1
- data/ext/libdatadog_api/trace_exporter.c +105 -25
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +29 -2
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +14 -2
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
- data/lib/datadog/appsec/security_engine/engine.rb +2 -1
- data/lib/datadog/core/configuration/components.rb +40 -18
- data/lib/datadog/core/configuration/components_state.rb +8 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +7 -2
- data/lib/datadog/core/process_discovery.rb +5 -1
- data/lib/datadog/core/remote/client/capabilities.rb +34 -29
- data/lib/datadog/core/remote/client.rb +44 -3
- data/lib/datadog/core/remote/component.rb +28 -12
- data/lib/datadog/core/remote/dispatcher.rb +47 -6
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
- data/lib/datadog/di/component.rb +108 -3
- data/lib/datadog/di/configuration.rb +53 -2
- data/lib/datadog/di/context.rb +7 -2
- data/lib/datadog/di/contrib/active_record.rb +8 -2
- data/lib/datadog/di/evaluation_failure.rb +28 -0
- data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
- data/lib/datadog/di/guardrails_telemetry.rb +203 -0
- data/lib/datadog/di/instrumenter.rb +65 -15
- data/lib/datadog/di/logger.rb +30 -8
- data/lib/datadog/di/probe_manager.rb +48 -5
- data/lib/datadog/di/probe_notification_builder.rb +28 -26
- data/lib/datadog/di/probe_notifier_worker.rb +56 -6
- data/lib/datadog/di/remote.rb +46 -2
- data/lib/datadog/di/serializer.rb +147 -55
- data/lib/datadog/di/snapshot_event.rb +38 -0
- data/lib/datadog/di/transport/http.rb +13 -3
- data/lib/datadog/di/transport/input.rb +32 -7
- data/lib/datadog/open_feature/activation.rb +268 -0
- data/lib/datadog/open_feature/component.rb +31 -15
- data/lib/datadog/open_feature/configuration.rb +6 -0
- data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
- data/lib/datadog/open_feature/provider.rb +304 -8
- data/lib/datadog/open_feature.rb +31 -1
- data/lib/datadog/profiling/collectors/info.rb +37 -6
- data/lib/datadog/profiling/component.rb +22 -20
- data/lib/datadog/profiling/exporter.rb +3 -5
- data/lib/datadog/tracing/component.rb +21 -2
- data/lib/datadog/tracing/configuration/ext.rb +2 -0
- data/lib/datadog/tracing/configuration/settings.rb +14 -1
- data/lib/datadog/tracing/context_provider.rb +8 -0
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +10 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -4
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +16 -1
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +8 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -4
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +10 -3
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +102 -0
- data/lib/datadog/tracing/otel_thread_context.rb +3 -5
- data/lib/datadog/tracing/remote.rb +50 -19
- data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
- data/lib/datadog/tracing/transport/http/traces.rb +2 -0
- data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
- data/lib/datadog/tracing/transport/native.rb +16 -1
- data/lib/datadog/tracing/transport/telemetry.rb +62 -0
- data/lib/datadog/tracing/transport/traces.rb +82 -15
- data/lib/datadog/version.rb +1 -1
- metadata +19 -10
- data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f4a11a75d5b532014ee82ed0628621a2586ca9b05ab6b00c7136357b7b0a5445
|
|
4
|
+
data.tar.gz: d51c04201a7f931546374be3adc2c6445e523e98713b60c3e7167398da2dede2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 344ce6f6622f0c6879f598917bab789aef9345a0498d3164b7481df27fdd916b8a4b65b69893fda1527db16ad01da921340441e35a880df4207ae6806966c31a
|
|
7
|
+
data.tar.gz: 2a77c07e5af10203211755104d3b4e117a70ef64d673d04330769b01a350d2bc8de024b5f7fad2954d95c50a99fa3526c1a473f169653437ad73cb51cea7e542
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [2.47.0] - 2026-10-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* Tracing: Add quantized request paths to outbound HTTP client resource names, such as `GET /users/*`; enable with `DD_TRACE_HTTP_CLIENT_RESOURCE_NAME_QUANTIZE=true`. ([#6298][])
|
|
10
|
+
* Open Feature: Let evaluations opt out of flag evaluation events, metrics, and span tags with `dd_evaluation_telemetry_opt_out: true` in the evaluation context; enable it with `DD_FEATURE_FLAGS_EVALUATION_TELEMETRY_PER_SUBJECT_OPT_OUT_ENABLED=true`. ([#6486][])
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
* AppSec: Update `libddwaf` to 1.30.0.1.0. ([#6548][])
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* Core: Fix forked processes, such as Puma and Unicorn workers, reporting no runtime metrics when the parent process traced before forking. ([#6500][]) ([@dduugg][])
|
|
19
|
+
* Profiling: Fix the "no signals" workaround being enabled when `mysql2` uses MariaDB Connector/C 3.x. ([#6543][])
|
|
20
|
+
* AppSec: Fix ruleset updates with Remote Configuration. ([#6547][])
|
|
21
|
+
* AppSec: Fix duplicate JSON serialization of Rails and Sinatra response objects when application security is enabled. ([#6548][])
|
|
22
|
+
|
|
23
|
+
## [2.46.0] - 2026-10-19
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
* Tracing: Add OpenTelemetry Thread Context support on Linux so that compatible agents can correlate Workload Protection events with application traces. ([#6454][])
|
|
28
|
+
* Open Feature: Start Feature Flags delivery during provider initialization, including for applications that never receive traced requests. ([#6418][])
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
* SSI: Reduce the single-step injection init image by about 35 MB, lowering download size and disk use when installing the library. ([#6469][], [#6474][], [#6481][], [#6485][], [#6488][])
|
|
33
|
+
* Profiling: Upgrade `datadog-ruby_core_source` to support Ruby 4.1.0-preview1. ([#6470][])
|
|
34
|
+
* Dynamic Instrumentation: Bound snapshot captures by the `DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS` budget (default `150`). `DD_DYNAMIC_INSTRUMENTATION_MAX_TIME_TO_SERIALIZE` is deprecated. ([#6205][])
|
|
35
|
+
|
|
5
36
|
## [2.45.0] - 2026-10-13
|
|
6
37
|
|
|
7
38
|
### Changed
|
|
@@ -3838,7 +3869,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
|
3838
3869
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3839
3870
|
|
|
3840
3871
|
|
|
3841
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.
|
|
3872
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.47.0...master
|
|
3873
|
+
[2.47.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.46.0...v2.47.0
|
|
3874
|
+
[2.46.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.45.0...v2.46.0
|
|
3842
3875
|
[2.45.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.44.0...v2.45.0
|
|
3843
3876
|
[2.44.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.43.0...v2.44.0
|
|
3844
3877
|
[2.43.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.42.0...v2.43.0
|
|
@@ -5669,6 +5702,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5669
5702
|
[#6142]: https://github.com/DataDog/dd-trace-rb/issues/6142
|
|
5670
5703
|
[#6173]: https://github.com/DataDog/dd-trace-rb/issues/6173
|
|
5671
5704
|
[#6176]: https://github.com/DataDog/dd-trace-rb/issues/6176
|
|
5705
|
+
[#6205]: https://github.com/DataDog/dd-trace-rb/issues/6205
|
|
5672
5706
|
[#6213]: https://github.com/DataDog/dd-trace-rb/issues/6213
|
|
5673
5707
|
[#6219]: https://github.com/DataDog/dd-trace-rb/issues/6219
|
|
5674
5708
|
[#6220]: https://github.com/DataDog/dd-trace-rb/issues/6220
|
|
@@ -5679,6 +5713,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5679
5713
|
[#6261]: https://github.com/DataDog/dd-trace-rb/issues/6261
|
|
5680
5714
|
[#6286]: https://github.com/DataDog/dd-trace-rb/issues/6286
|
|
5681
5715
|
[#6291]: https://github.com/DataDog/dd-trace-rb/issues/6291
|
|
5716
|
+
[#6298]: https://github.com/DataDog/dd-trace-rb/issues/6298
|
|
5682
5717
|
[#6316]: https://github.com/DataDog/dd-trace-rb/issues/6316
|
|
5683
5718
|
[#6320]: https://github.com/DataDog/dd-trace-rb/issues/6320
|
|
5684
5719
|
[#6339]: https://github.com/DataDog/dd-trace-rb/issues/6339
|
|
@@ -5695,10 +5730,23 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5695
5730
|
[#6401]: https://github.com/DataDog/dd-trace-rb/issues/6401
|
|
5696
5731
|
[#6407]: https://github.com/DataDog/dd-trace-rb/issues/6407
|
|
5697
5732
|
[#6412]: https://github.com/DataDog/dd-trace-rb/issues/6412
|
|
5733
|
+
[#6418]: https://github.com/DataDog/dd-trace-rb/issues/6418
|
|
5698
5734
|
[#6419]: https://github.com/DataDog/dd-trace-rb/issues/6419
|
|
5699
5735
|
[#6427]: https://github.com/DataDog/dd-trace-rb/issues/6427
|
|
5700
5736
|
[#6433]: https://github.com/DataDog/dd-trace-rb/issues/6433
|
|
5701
5737
|
[#6441]: https://github.com/DataDog/dd-trace-rb/issues/6441
|
|
5738
|
+
[#6454]: https://github.com/DataDog/dd-trace-rb/issues/6454
|
|
5739
|
+
[#6469]: https://github.com/DataDog/dd-trace-rb/issues/6469
|
|
5740
|
+
[#6470]: https://github.com/DataDog/dd-trace-rb/issues/6470
|
|
5741
|
+
[#6474]: https://github.com/DataDog/dd-trace-rb/issues/6474
|
|
5742
|
+
[#6481]: https://github.com/DataDog/dd-trace-rb/issues/6481
|
|
5743
|
+
[#6485]: https://github.com/DataDog/dd-trace-rb/issues/6485
|
|
5744
|
+
[#6486]: https://github.com/DataDog/dd-trace-rb/issues/6486
|
|
5745
|
+
[#6488]: https://github.com/DataDog/dd-trace-rb/issues/6488
|
|
5746
|
+
[#6500]: https://github.com/DataDog/dd-trace-rb/issues/6500
|
|
5747
|
+
[#6543]: https://github.com/DataDog/dd-trace-rb/issues/6543
|
|
5748
|
+
[#6547]: https://github.com/DataDog/dd-trace-rb/issues/6547
|
|
5749
|
+
[#6548]: https://github.com/DataDog/dd-trace-rb/issues/6548
|
|
5702
5750
|
[@AdrianLC]: https://github.com/AdrianLC
|
|
5703
5751
|
[@Azure7111]: https://github.com/Azure7111
|
|
5704
5752
|
[@BabyGroot]: https://github.com/BabyGroot
|
|
@@ -41,7 +41,7 @@ static const char *get_or_compute_native_filename(void *function, st_table *nati
|
|
|
41
41
|
static void initialize_static_ruby_actual_filename(VALUE profiling_module);
|
|
42
42
|
static void add_truncated_frames_placeholder(ddog_prof_Location *locations);
|
|
43
43
|
static void record_placeholder_stack_in_native_code(VALUE recorder_instance, sample_values values, sample_labels labels);
|
|
44
|
-
static void maybe_trim_template_random_ids(ddog_CharSlice *
|
|
44
|
+
static void maybe_trim_template_random_ids(ddog_CharSlice *frame_name, ddog_CharSlice method_name, ddog_CharSlice filename);
|
|
45
45
|
|
|
46
46
|
// NULL if we weren't able to get the native filename for the Ruby VM.
|
|
47
47
|
// On a static Ruby without libruby.so, `get_or_compute_native_filename` returns `ruby_native_filename` but
|
|
@@ -438,7 +438,7 @@ void sample_thread(
|
|
|
438
438
|
frame_name = name_slice;
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
maybe_trim_template_random_ids(&frame_name,
|
|
441
|
+
maybe_trim_template_random_ids(&frame_name, name_slice, filename_slice);
|
|
442
442
|
|
|
443
443
|
int libdatadog_stores_stacks_flipped_from_rb_profile_frames_index = top_of_stack_position - i;
|
|
444
444
|
|
|
@@ -548,33 +548,50 @@ static const char *get_or_compute_native_filename(void *function, st_table *nati
|
|
|
548
548
|
// the extra "_".)
|
|
549
549
|
//
|
|
550
550
|
// This method trims these suffixes, so that we keep less data + the names correctly aggregate together.
|
|
551
|
-
|
|
551
|
+
//
|
|
552
|
+
// We match on `method_name` because it always ends with the ids, while `frame_name` can have DDTRACE_BLOCK_SUFFIX
|
|
553
|
+
// after them ("Foo#_app_views_articles_index_html_erb__123_456 (block)"); in that case we move the suffix left over
|
|
554
|
+
// the ids. A `frame_name` that is a Ruby String ends with the ids we just matched, so that write only ever lands on
|
|
555
|
+
// a name we composed in the sample's own buffer.
|
|
556
|
+
static void maybe_trim_template_random_ids(ddog_CharSlice *frame_name, ddog_CharSlice method_name, ddog_CharSlice filename) {
|
|
552
557
|
// Check filename doesn't end with ".rb"; templates are usually along the lines of .html.erb/.html.haml/...
|
|
553
|
-
if (
|
|
558
|
+
if (filename.len < 3 || memcmp(filename.ptr + filename.len - 3, ".rb", 3) == 0) return;
|
|
554
559
|
|
|
555
|
-
if (
|
|
556
|
-
if (
|
|
560
|
+
if (method_name.len > 1024) return;
|
|
561
|
+
if (method_name.len == 0) return;
|
|
557
562
|
|
|
558
|
-
int pos = ((int)
|
|
563
|
+
int pos = ((int) method_name.len) - 1;
|
|
559
564
|
|
|
560
565
|
// Let's match on something__number_number:
|
|
561
566
|
// Find start of id suffix from the end...
|
|
562
|
-
if (
|
|
567
|
+
if (method_name.ptr[pos] < '0' || method_name.ptr[pos] > '9') return;
|
|
563
568
|
|
|
564
569
|
// ...now match a bunch of numbers and interspersed underscores
|
|
565
570
|
for (int underscores = 0; pos >= 0 && underscores < 2; pos--) {
|
|
566
|
-
if (
|
|
567
|
-
else if (
|
|
571
|
+
if (method_name.ptr[pos] == '_') underscores++;
|
|
572
|
+
else if (method_name.ptr[pos] < '0' || method_name.ptr[pos] > '9') return;
|
|
568
573
|
}
|
|
569
574
|
|
|
570
575
|
// Make sure there's something left before the underscores (hence the <= instead of <) + match the last underscore
|
|
571
|
-
if (pos <= 0 ||
|
|
576
|
+
if (pos <= 0 || method_name.ptr[pos] != '_') return;
|
|
572
577
|
|
|
573
578
|
// Does it have the optional third underscore? If so, remove it as well
|
|
574
|
-
if (pos > 1 &&
|
|
579
|
+
if (pos > 1 && method_name.ptr[pos-1] == '_') pos--;
|
|
580
|
+
|
|
581
|
+
// If we got here, we matched on our pattern. Let's remove the ids from the end of the frame name.
|
|
582
|
+
size_t random_ids_len = method_name.len - pos;
|
|
583
|
+
|
|
584
|
+
static const char block_suffix[] = DDTRACE_BLOCK_SUFFIX;
|
|
585
|
+
size_t block_suffix_len = sizeof(block_suffix) - 1;
|
|
586
|
+
|
|
587
|
+
if (
|
|
588
|
+
frame_name->len >= random_ids_len + block_suffix_len &&
|
|
589
|
+
memcmp(frame_name->ptr + frame_name->len - block_suffix_len, block_suffix, block_suffix_len) == 0
|
|
590
|
+
) {
|
|
591
|
+
memcpy((char *) frame_name->ptr + frame_name->len - block_suffix_len - random_ids_len, block_suffix, block_suffix_len);
|
|
592
|
+
}
|
|
575
593
|
|
|
576
|
-
|
|
577
|
-
name_slice->len = pos;
|
|
594
|
+
frame_name->len -= random_ids_len;
|
|
578
595
|
}
|
|
579
596
|
|
|
580
597
|
static void add_truncated_frames_placeholder(ddog_prof_Location *locations) {
|
|
@@ -893,6 +893,10 @@ const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
|
|
|
893
893
|
}
|
|
894
894
|
#endif
|
|
895
895
|
|
|
896
|
+
int imemo_mask(void) {
|
|
897
|
+
return IMEMO_MASK;
|
|
898
|
+
}
|
|
899
|
+
|
|
896
900
|
// This is used to workaround a VM bug. See "handle_sampling_signal" in "collectors_cpu_and_wall_time_worker" for details.
|
|
897
901
|
#ifdef NO_POSTPONED_TRIGGER
|
|
898
902
|
void *objspace_ptr_for_gc_finalize_deferred_workaround(void) {
|
|
@@ -1132,7 +1136,7 @@ static ssize_t calculate_iseq_label(VALUE owner, const rb_iseq_t *iseq, char *bu
|
|
|
1132
1136
|
// We use "Foo#bar (block)" because it's much faster and looks better in the UI.
|
|
1133
1137
|
const rb_iseq_t* method_iseq = ISEQ_BODY(iseq)->local_iseq;
|
|
1134
1138
|
|
|
1135
|
-
static const char suffix[] =
|
|
1139
|
+
static const char suffix[] = DDTRACE_BLOCK_SUFFIX;
|
|
1136
1140
|
size_t suffix_len = sizeof(suffix) - 1;
|
|
1137
1141
|
|
|
1138
1142
|
// Only use the result if there is enough space for both parts
|
|
@@ -75,6 +75,8 @@ void self_test_mn_enabled(void);
|
|
|
75
75
|
// Provides more specific information on what kind an imemo is
|
|
76
76
|
const char *imemo_kind(VALUE imemo);
|
|
77
77
|
|
|
78
|
+
int imemo_mask(void);
|
|
79
|
+
|
|
78
80
|
#ifdef NO_POSTPONED_TRIGGER
|
|
79
81
|
void *objspace_ptr_for_gc_finalize_deferred_workaround(void);
|
|
80
82
|
#endif
|
|
@@ -100,6 +102,9 @@ VALUE ddtrace_alloc_free_rb_mod_name(VALUE mod);
|
|
|
100
102
|
// if the module does not have a permanent name (e.g. `#<Module:0x0123>::Foo`).
|
|
101
103
|
VALUE ddtrace_permanent_mod_name(VALUE mod);
|
|
102
104
|
|
|
105
|
+
// Suffix ddtrace_location_label() adds to blocks, e.g. "Foo#bar (block)"
|
|
106
|
+
#define DDTRACE_BLOCK_SUFFIX " (block)"
|
|
107
|
+
|
|
103
108
|
ssize_t ddtrace_location_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, char *buf, size_t buf_size);
|
|
104
109
|
VALUE ddtrace_location_base_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq);
|
|
105
110
|
void* ddtrace_cme_cfunc_func(const rb_callable_method_entry_t *cme);
|
|
@@ -47,6 +47,7 @@ static VALUE _native_enforce_success(DDTRACE_UNUSED VALUE _self, VALUE syserr_er
|
|
|
47
47
|
static void *trigger_enforce_success(void *trigger_args);
|
|
48
48
|
static VALUE _native_malloc_stats(DDTRACE_UNUSED VALUE _self);
|
|
49
49
|
static VALUE _native_safe_object_info(DDTRACE_UNUSED VALUE _self, VALUE obj);
|
|
50
|
+
static VALUE _native_imemo_mask(DDTRACE_UNUSED VALUE _self);
|
|
50
51
|
|
|
51
52
|
void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
52
53
|
// The profiler still has a lot of limitations around being used in Ractors BUT for now we're choosing to take care of those
|
|
@@ -101,6 +102,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
|
101
102
|
rb_define_singleton_method(testing_module, "_native_enforce_success", _native_enforce_success, 2);
|
|
102
103
|
rb_define_singleton_method(testing_module, "_native_malloc_stats", _native_malloc_stats, 0);
|
|
103
104
|
rb_define_singleton_method(testing_module, "_native_safe_object_info", _native_safe_object_info, 1);
|
|
105
|
+
rb_define_singleton_method(testing_module, "_native_imemo_mask", _native_imemo_mask, 0);
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
static VALUE native_working_p(DDTRACE_UNUSED VALUE _self) {
|
|
@@ -329,3 +331,7 @@ static VALUE _native_malloc_stats(DDTRACE_UNUSED VALUE _self) {
|
|
|
329
331
|
static VALUE _native_safe_object_info(DDTRACE_UNUSED VALUE _self, VALUE obj) {
|
|
330
332
|
return rb_str_new_cstr(safe_object_info(obj));
|
|
331
333
|
}
|
|
334
|
+
|
|
335
|
+
static VALUE _native_imemo_mask(DDTRACE_UNUSED VALUE _self) {
|
|
336
|
+
return INT2NUM(imemo_mask());
|
|
337
|
+
}
|
data/ext/libdatadog_api/di.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include <stdbool.h>
|
|
2
|
+
#include <string.h>
|
|
2
3
|
|
|
3
4
|
#include "datadog_ruby_common.h"
|
|
4
5
|
|
|
@@ -12,15 +13,19 @@ VALUE rb_iseqw_new(const void *iseq);
|
|
|
12
13
|
// rb_iseqw_to_iseq unwraps a RubyVM::InstructionSequence object back
|
|
13
14
|
// to its internal iseq pointer.
|
|
14
15
|
const void *rb_iseqw_to_iseq(VALUE iseqw);
|
|
16
|
+
#ifdef HAVE_RB_IMEMO_NAME
|
|
17
|
+
const char *rb_imemo_name(int imemo_type);
|
|
18
|
+
#endif
|
|
15
19
|
int rb_objspace_internal_object_p(VALUE obj);
|
|
16
20
|
void rb_objspace_each_objects(
|
|
17
21
|
int (*callback)(void *start, void *end, size_t stride, void *data),
|
|
18
22
|
void *data);
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#define IMEMO_MASK 0x0f
|
|
24
|
+
#ifdef HAVE_SHIFTED_IMEMO_MASK // Ruby 4.1+
|
|
25
|
+
#define IMEMO_MASK (FL_USER0 | FL_USER1 | FL_USER2 | FL_USER3 | FL_USER4)
|
|
26
|
+
#else
|
|
27
|
+
#define IMEMO_MASK 0x0f
|
|
28
|
+
#endif
|
|
24
29
|
#define IMEMO_TYPE_ISEQ 7
|
|
25
30
|
|
|
26
31
|
// The ID value of the string "mesg" which is used in Ruby source as
|
|
@@ -37,7 +42,11 @@ static ID id_datadog_di_in_probe;
|
|
|
37
42
|
// Returns the imemo type of an imemo object, that is `imemo_type()` from CRuby's internal/imemo.h.
|
|
38
43
|
// The caller must have already checked the object is a T_IMEMO, otherwise the result is meaningless.
|
|
39
44
|
static inline int ddtrace_imemo_type(VALUE imemo) {
|
|
40
|
-
|
|
45
|
+
#ifdef HAVE_SHIFTED_IMEMO_MASK // Ruby 4.1+
|
|
46
|
+
return (RBASIC(imemo)->flags & IMEMO_MASK) >> FL_USHIFT;
|
|
47
|
+
#else
|
|
48
|
+
return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK;
|
|
49
|
+
#endif
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
// Returns whether the argument is an IMEMO of type ISEQ.
|
|
@@ -199,7 +208,20 @@ static VALUE iseq_type(DDTRACE_UNUSED VALUE _self, VALUE iseq_val) {
|
|
|
199
208
|
}
|
|
200
209
|
#endif
|
|
201
210
|
|
|
211
|
+
static VALUE _native_imemo_mask(DDTRACE_UNUSED VALUE _self) {
|
|
212
|
+
return INT2NUM(IMEMO_MASK);
|
|
213
|
+
}
|
|
214
|
+
|
|
202
215
|
void di_init(VALUE datadog_module) {
|
|
216
|
+
#ifdef HAVE_RB_IMEMO_NAME
|
|
217
|
+
const char *iseq_name = rb_imemo_name(IMEMO_TYPE_ISEQ);
|
|
218
|
+
if (strcmp(iseq_name, "iseq") != 0) {
|
|
219
|
+
rb_raise(rb_eRuntimeError,
|
|
220
|
+
"IMEMO_TYPE_ISEQ self-test failed: rb_imemo_name(%d) returned '%s' instead of 'iseq'",
|
|
221
|
+
IMEMO_TYPE_ISEQ, iseq_name);
|
|
222
|
+
}
|
|
223
|
+
#endif
|
|
224
|
+
|
|
203
225
|
id_mesg = rb_intern("mesg");
|
|
204
226
|
id_datadog_di_in_probe = rb_intern("datadog_di_in_probe");
|
|
205
227
|
|
|
@@ -213,6 +235,9 @@ void di_init(VALUE datadog_module) {
|
|
|
213
235
|
#ifdef HAVE_RB_ISEQ_TYPE
|
|
214
236
|
rb_define_singleton_method(di_module, "iseq_type", iseq_type, 1);
|
|
215
237
|
#endif
|
|
238
|
+
|
|
239
|
+
VALUE testing_module = rb_define_module_under(di_module, "Testing");
|
|
240
|
+
rb_define_singleton_method(testing_module, "_native_imemo_mask", _native_imemo_mask, 0);
|
|
216
241
|
}
|
|
217
242
|
|
|
218
243
|
#endif // TRUFFLERUBY
|
|
@@ -98,6 +98,8 @@ EXTENSION_NAME = "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}".fr
|
|
|
98
98
|
|
|
99
99
|
have_func("rb_iseq_type")
|
|
100
100
|
|
|
101
|
+
$defs << "-DHAVE_RB_IMEMO_NAME" if RUBY_VERSION >= "3.0"
|
|
102
|
+
$defs << "-DHAVE_SHIFTED_IMEMO_MASK" if RUBY_VERSION >= "4.1"
|
|
101
103
|
$defs << "-DHAVE_RUBY_THREAD_STORAGE_API" if RUBY_VERSION >= "3.3"
|
|
102
104
|
$defs << "-DHAVE_RUBY_THREAD_HAS_GVL_P" if have_func("ruby_thread_has_gvl_p")
|
|
103
105
|
|
|
@@ -30,7 +30,6 @@ DDTRACE_UNUSED static bool otel_context_enabled = false;
|
|
|
30
30
|
|
|
31
31
|
static VALUE native_set(VALUE _self, VALUE trace_id, VALUE span_id, VALUE local_root_span_id);
|
|
32
32
|
static VALUE native_clear(VALUE _self);
|
|
33
|
-
static VALUE native_supported_p(VALUE _self);
|
|
34
33
|
static VALUE native_enable(VALUE _self);
|
|
35
34
|
static VALUE native_read(VALUE _self);
|
|
36
35
|
|
|
@@ -42,7 +41,6 @@ void otel_thread_context_init(VALUE tracing_module) {
|
|
|
42
41
|
rb_define_method(otel_thread_context_class, "_native_enable", native_enable, 0);
|
|
43
42
|
rb_define_method(otel_thread_context_class, "_native_set", native_set, 3);
|
|
44
43
|
rb_define_method(otel_thread_context_class, "_native_clear", native_clear, 0);
|
|
45
|
-
rb_define_method(otel_thread_context_class, "_native_supported?", native_supported_p, 0);
|
|
46
44
|
|
|
47
45
|
VALUE testing_module = rb_define_module_under(otel_thread_context_class, "Testing");
|
|
48
46
|
rb_define_singleton_method(testing_module, "_native_read", native_read, 0);
|
|
@@ -100,6 +98,19 @@ void otel_thread_context_init(VALUE tracing_module) {
|
|
|
100
98
|
) {
|
|
101
99
|
ddog_otel_thread_ctx_detach();
|
|
102
100
|
}
|
|
101
|
+
|
|
102
|
+
// CRuby fires RUBY_EVENT_THREAD_END only after the thread body returns,
|
|
103
|
+
// and Thread#kill unwinds the body via EC_JUMP_TAG(TAG_FATAL):
|
|
104
|
+
// https://github.com/ruby/ruby/blob/v3_1_4/thread.c#L744-L775
|
|
105
|
+
static void on_thread_begin(
|
|
106
|
+
DDTRACE_UNUSED rb_event_flag_t evflag,
|
|
107
|
+
DDTRACE_UNUSED VALUE data,
|
|
108
|
+
DDTRACE_UNUSED VALUE self,
|
|
109
|
+
DDTRACE_UNUSED ID mid,
|
|
110
|
+
DDTRACE_UNUSED VALUE klass
|
|
111
|
+
) {
|
|
112
|
+
ddog_otel_thread_ctx_detach();
|
|
113
|
+
}
|
|
103
114
|
#endif
|
|
104
115
|
|
|
105
116
|
#ifdef HAVE_RUBY_THREAD_STORAGE_API
|
|
@@ -166,6 +177,11 @@ static VALUE native_enable(DDTRACE_UNUSED VALUE _self) {
|
|
|
166
177
|
rb_internal_thread_add_event_hook(on_thread_exited, RUBY_INTERNAL_THREAD_EVENT_EXITED, NULL);
|
|
167
178
|
#else
|
|
168
179
|
rb_add_event_hook(on_thread_end, RUBY_EVENT_THREAD_END, Qnil);
|
|
180
|
+
// RUBY_EVENT_THREAD_END does not fire for threads terminated via Thread#kill
|
|
181
|
+
// on Ruby < 3.2, so a killed thread's otel_thread_ctx_v1 TLS stays attached
|
|
182
|
+
// on a native thread CRuby may recycle for a later Ruby thread. Detach on
|
|
183
|
+
// thread begin to drop that stale record before the new thread runs.
|
|
184
|
+
rb_add_event_hook(on_thread_begin, RUBY_EVENT_THREAD_BEGIN, Qnil);
|
|
169
185
|
#endif
|
|
170
186
|
|
|
171
187
|
// These hooks only matter under the M:N thread scheduler (Ruby 3.3+),
|
|
@@ -179,15 +195,7 @@ static VALUE native_enable(DDTRACE_UNUSED VALUE _self) {
|
|
|
179
195
|
|
|
180
196
|
return Qtrue;
|
|
181
197
|
#else
|
|
182
|
-
|
|
183
|
-
#endif
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
static VALUE native_supported_p(DDTRACE_UNUSED VALUE _self) {
|
|
187
|
-
#ifdef OTEL_THREAD_CONTEXT_SUPPORTED
|
|
188
|
-
return Qtrue;
|
|
189
|
-
#else
|
|
190
|
-
return Qfalse;
|
|
198
|
+
raise_error(rb_eRuntimeError, "OTel thread context is not supported on this platform");
|
|
191
199
|
#endif
|
|
192
200
|
}
|
|
193
201
|
|
|
@@ -216,9 +224,7 @@ static VALUE native_set(
|
|
|
216
224
|
store_current_fiber_handle(handle);
|
|
217
225
|
ddog_otel_thread_ctx_attach(handle);
|
|
218
226
|
} else {
|
|
219
|
-
|
|
220
|
-
ddog_otel_thread_ctx_attach(handle);
|
|
221
|
-
ddog_otel_thread_ctx_update(&trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
|
|
227
|
+
ddog_otel_thread_ctx_update_and_attach(handle, &trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
|
|
222
228
|
}
|
|
223
229
|
|
|
224
230
|
return Qtrue;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <datadog/library-config.h>
|
|
5
5
|
|
|
6
6
|
#include "datadog_ruby_common.h"
|
|
7
|
+
#include "helpers.h"
|
|
7
8
|
|
|
8
9
|
static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
|
|
9
10
|
static VALUE _native_to_rb_int(DDTRACE_UNUSED VALUE _self, VALUE tracer_memfd);
|
|
@@ -38,8 +39,9 @@ void process_discovery_init(VALUE core_module) {
|
|
|
38
39
|
|
|
39
40
|
static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
40
41
|
VALUE logger;
|
|
42
|
+
VALUE otel_thread_context_enabled;
|
|
41
43
|
VALUE options;
|
|
42
|
-
rb_scan_args(argc, argv, "
|
|
44
|
+
rb_scan_args(argc, argv, "2:", &logger, &otel_thread_context_enabled, &options);
|
|
43
45
|
if (options == Qnil) options = rb_hash_new();
|
|
44
46
|
|
|
45
47
|
VALUE runtime_id = rb_hash_fetch(options, ID2SYM(rb_intern("runtime_id")));
|
|
@@ -61,6 +63,7 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
61
63
|
ENFORCE_TYPE(service_version, T_STRING);
|
|
62
64
|
ENFORCE_TYPE(process_tags, T_STRING);
|
|
63
65
|
ENFORCE_TYPE(container_id, T_STRING);
|
|
66
|
+
ENFORCE_BOOLEAN(otel_thread_context_enabled);
|
|
64
67
|
|
|
65
68
|
void* builder = ddog_tracer_metadata_new();
|
|
66
69
|
|
|
@@ -74,6 +77,16 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
74
77
|
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_PROCESS_TAGS, StringValueCStr(process_tags));
|
|
75
78
|
ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_CONTAINER_ID, StringValueCStr(container_id));
|
|
76
79
|
|
|
80
|
+
if (RTEST(otel_thread_context_enabled)) {
|
|
81
|
+
ddog_VoidResult include_result = ddog_tracer_metadata_include_otel_thread_context(builder);
|
|
82
|
+
|
|
83
|
+
if (include_result.tag == DDOG_VOID_RESULT_ERR) {
|
|
84
|
+
ddog_tracer_metadata_free(builder);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
CHECK_VOID_RESULT("Failed to include OTel thread context metadata", include_result);
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
ddog_Result_TracerMemfdHandle result = ddog_tracer_metadata_store(builder);
|
|
78
91
|
ddog_tracer_metadata_free(builder);
|
|
79
92
|
|
|
@@ -89,6 +102,7 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
|
|
|
89
102
|
*fd = result.ok.fd;
|
|
90
103
|
VALUE tracer_memfd_class = rb_const_get(self, rb_intern("TracerMemfd"));
|
|
91
104
|
VALUE tracer_memfd = TypedData_Wrap_Struct(tracer_memfd_class, &tracer_memfd_type, fd);
|
|
105
|
+
|
|
92
106
|
return tracer_memfd;
|
|
93
107
|
}
|
|
94
108
|
|
|
@@ -104,6 +104,8 @@ static VALUE serializable_backtrace_class = Qnil;
|
|
|
104
104
|
/* Response class (loaded from Ruby) */
|
|
105
105
|
static VALUE response_class = Qnil;
|
|
106
106
|
static ID id_new;
|
|
107
|
+
static ID id_handle_interrupt;
|
|
108
|
+
static VALUE observation_interrupt_mask = Qnil;
|
|
107
109
|
|
|
108
110
|
/* Response keyword-argument IDs, cached to avoid re-interning per send */
|
|
109
111
|
static ID kw_ok;
|
|
@@ -1464,6 +1466,11 @@ static VALUE _native_exporter_new(
|
|
|
1464
1466
|
/* Phase 2: configure before creating the separately-owned runtime. */
|
|
1465
1467
|
ddog_TraceExporterConfig *config = NULL;
|
|
1466
1468
|
ddog_trace_exporter_config_new(&config);
|
|
1469
|
+
ddog_TraceExporterError *observation_error = ddog_trace_exporter_config_enable_observations(config);
|
|
1470
|
+
if (observation_error != NULL) {
|
|
1471
|
+
ddog_trace_exporter_config_free(config);
|
|
1472
|
+
check_exporter_error("Failed to select exporter observations", observation_error);
|
|
1473
|
+
}
|
|
1467
1474
|
|
|
1468
1475
|
set_config_field(config, ddog_trace_exporter_config_set_url, rb_url, "url");
|
|
1469
1476
|
set_config_field(config, ddog_trace_exporter_config_set_tracer_version, rb_tracer_version, "tracer_version");
|
|
@@ -1621,6 +1628,7 @@ typedef struct {
|
|
|
1621
1628
|
const ddog_TraceExporter *exporter;
|
|
1622
1629
|
ddog_TracerTraceChunks *chunks;
|
|
1623
1630
|
ddog_TraceExporterResponse *response;
|
|
1631
|
+
ddog_TraceExporterObservations observations;
|
|
1624
1632
|
ddog_TraceExporterCancelToken *cancel_token; /* borrowed, not owned */
|
|
1625
1633
|
ddog_TraceExporterErrorCode error_code;
|
|
1626
1634
|
bool failed;
|
|
@@ -1629,8 +1637,8 @@ typedef struct {
|
|
|
1629
1637
|
|
|
1630
1638
|
static void *send_chunks_without_gvl(void *data) {
|
|
1631
1639
|
send_chunks_args_t *args = (send_chunks_args_t *)data;
|
|
1632
|
-
ddog_TraceExporterError *err =
|
|
1633
|
-
args->exporter, args->chunks, &args->response, args->cancel_token);
|
|
1640
|
+
ddog_TraceExporterError *err = ddog_trace_exporter_send_trace_chunks_observed(
|
|
1641
|
+
args->exporter, args->chunks, &args->response, &args->observations, args->cancel_token);
|
|
1634
1642
|
if (err != NULL) {
|
|
1635
1643
|
args->error_code = err->code;
|
|
1636
1644
|
args->failed = true;
|
|
@@ -1698,8 +1706,73 @@ typedef struct {
|
|
|
1698
1706
|
long trace_count;
|
|
1699
1707
|
raw_span_owner span_owner;
|
|
1700
1708
|
ddog_TracerTraceChunks *chunks; /* NULL after send consumes it */
|
|
1709
|
+
ddog_TraceExporterResponse *response;
|
|
1701
1710
|
} send_traces_ctx;
|
|
1702
1711
|
|
|
1712
|
+
typedef struct {
|
|
1713
|
+
const ddog_TraceExporterObservations *report;
|
|
1714
|
+
VALUE block;
|
|
1715
|
+
} observations_callback_args;
|
|
1716
|
+
|
|
1717
|
+
static VALUE yield_observations(VALUE arg) {
|
|
1718
|
+
observations_callback_args *callback = (observations_callback_args *)arg;
|
|
1719
|
+
const ddog_TraceExporterObservations *report = callback->report;
|
|
1720
|
+
VALUE values = rb_hash_new();
|
|
1721
|
+
#define ADD_OBSERVATION(field) if (report->field > 0) rb_hash_aset(values, ID2SYM(rb_intern_const(#field)), ULL2NUM(report->field))
|
|
1722
|
+
ADD_OBSERVATION(requests_count);
|
|
1723
|
+
ADD_OBSERVATION(errors_network);
|
|
1724
|
+
ADD_OBSERVATION(errors_timeout);
|
|
1725
|
+
ADD_OBSERVATION(errors_status_code);
|
|
1726
|
+
ADD_OBSERVATION(bytes_sent);
|
|
1727
|
+
ADD_OBSERVATION(chunks_sent);
|
|
1728
|
+
ADD_OBSERVATION(chunks_dropped_serialization_error);
|
|
1729
|
+
ADD_OBSERVATION(chunks_dropped_send_failure);
|
|
1730
|
+
ADD_OBSERVATION(spans_enqueued_for_serialization);
|
|
1731
|
+
ADD_OBSERVATION(spans_dropped_serialization_error);
|
|
1732
|
+
ADD_OBSERVATION(spans_dropped_api_error);
|
|
1733
|
+
ADD_OBSERVATION(responses_count);
|
|
1734
|
+
ADD_OBSERVATION(status_code);
|
|
1735
|
+
#undef ADD_OBSERVATION
|
|
1736
|
+
return rb_proc_call_with_block(callback->block, 1, &values, Qnil);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
static VALUE ignore_observation_error(DDTRACE_UNUSED VALUE arg, DDTRACE_UNUSED VALUE error) {
|
|
1740
|
+
return Qnil;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
static VALUE protected_observations(RB_BLOCK_CALL_FUNC_ARGLIST(yielded, arg)) {
|
|
1744
|
+
(void)yielded;
|
|
1745
|
+
(void)argc;
|
|
1746
|
+
(void)argv;
|
|
1747
|
+
(void)blockarg;
|
|
1748
|
+
return rb_rescue2(yield_observations, arg, ignore_observation_error, Qnil,
|
|
1749
|
+
rb_eStandardError, (VALUE)0);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
static VALUE forward_observations(VALUE arg) {
|
|
1753
|
+
observations_callback_args callback = {
|
|
1754
|
+
.report = (const ddog_TraceExporterObservations *)arg,
|
|
1755
|
+
.block = rb_block_proc(),
|
|
1756
|
+
};
|
|
1757
|
+
/* Deliver fresh interrupts after the callback's StandardError rescue has ended. */
|
|
1758
|
+
VALUE result = rb_block_call(rb_cThread, id_handle_interrupt, 1, &observation_interrupt_mask,
|
|
1759
|
+
protected_observations, (VALUE)&callback);
|
|
1760
|
+
RB_GC_GUARD(callback.block);
|
|
1761
|
+
return result;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
static VALUE ensure_observations(VALUE arg) {
|
|
1765
|
+
int ignored_state = 0;
|
|
1766
|
+
/* The original interruption wins over any callback failure or non-local exit. */
|
|
1767
|
+
rb_protect(forward_observations, arg, &ignored_state);
|
|
1768
|
+
return Qnil;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
static VALUE rethrow_interrupt(VALUE tag) {
|
|
1772
|
+
rb_jump_tag(FIX2INT(tag));
|
|
1773
|
+
return Qnil;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1703
1776
|
/*
|
|
1704
1777
|
* Body: build trace chunks from Ruby spans, then send them.
|
|
1705
1778
|
* Passed to rb_ensure as the "try" block.
|
|
@@ -1777,40 +1850,37 @@ static VALUE build_and_send_traces(VALUE arg) {
|
|
|
1777
1850
|
if (args.send_ran) {
|
|
1778
1851
|
ctx->chunks = NULL;
|
|
1779
1852
|
}
|
|
1853
|
+
ctx->response = args.response;
|
|
1854
|
+
|
|
1855
|
+
/* A completed send can race with cancellation; retain its report while unwinding. */
|
|
1856
|
+
if (!pending_exception) {
|
|
1857
|
+
pending_exception = check_if_pending_exception();
|
|
1858
|
+
}
|
|
1859
|
+
if (args.send_ran && rb_block_given_p()) {
|
|
1860
|
+
if (pending_exception) {
|
|
1861
|
+
/* rb_ensure preserves Thread#kill's fatal sentinel, which rb_set_errinfo cannot restore. */
|
|
1862
|
+
rb_ensure(rethrow_interrupt, INT2FIX(pending_exception),
|
|
1863
|
+
ensure_observations, (VALUE)&args.observations);
|
|
1864
|
+
} else {
|
|
1865
|
+
forward_observations((VALUE)&args.observations);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
if (pending_exception) {
|
|
1869
|
+
rb_jump_tag(pending_exception);
|
|
1870
|
+
}
|
|
1780
1871
|
|
|
1781
1872
|
/* Extract the response body as a Ruby string before freeing. */
|
|
1782
1873
|
VALUE payload = Qnil;
|
|
1783
1874
|
if (args.response != NULL) {
|
|
1784
|
-
ddog_ByteSlice body =
|
|
1785
|
-
ddog_trace_exporter_response_get_body(args.response);
|
|
1875
|
+
ddog_ByteSlice body = ddog_trace_exporter_response_get_body(args.response);
|
|
1786
1876
|
if (body.len > 0) {
|
|
1787
1877
|
payload = rb_str_new((const char *)body.ptr, (long)body.len);
|
|
1788
1878
|
}
|
|
1789
1879
|
ddog_trace_exporter_response_free(args.response);
|
|
1880
|
+
ctx->response = NULL;
|
|
1790
1881
|
args.response = NULL;
|
|
1791
1882
|
}
|
|
1792
1883
|
|
|
1793
|
-
/*
|
|
1794
|
-
* Re-check for a pending interrupt unconditionally before deciding the
|
|
1795
|
-
* outcome. In a race, the unblock function (interrupt_exporter_call) can
|
|
1796
|
-
* fire -- cancelling the token -- while the send still completes, so
|
|
1797
|
-
* rb_thread_call_without_gvl2 returns with args.send_ran == true. In that
|
|
1798
|
-
* case the loop above exits without ever calling check_if_pending_exception(),
|
|
1799
|
-
* leaving the interrupt pending. If we did not check here, the cancelled
|
|
1800
|
-
* send would fall through and be reported as an ordinary transport error
|
|
1801
|
-
* response, swallowing the interrupt (e.g. Thread#kill / shutdown).
|
|
1802
|
-
*
|
|
1803
|
-
* This runs after the response has already been extracted and freed and
|
|
1804
|
-
* after chunks have been handed off to the ensure handler, so re-raising
|
|
1805
|
-
* here leaks nothing.
|
|
1806
|
-
*/
|
|
1807
|
-
if (!pending_exception) {
|
|
1808
|
-
pending_exception = check_if_pending_exception();
|
|
1809
|
-
}
|
|
1810
|
-
if (pending_exception) {
|
|
1811
|
-
rb_jump_tag(pending_exception);
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
1884
|
if (args.failed) {
|
|
1815
1885
|
VALUE err_resp = create_error_response(args.error_code, ctx->trace_count);
|
|
1816
1886
|
return rb_ary_new_from_args(1, err_resp);
|
|
@@ -1827,6 +1897,10 @@ static VALUE build_and_send_traces(VALUE arg) {
|
|
|
1827
1897
|
static VALUE free_send_resources(VALUE arg) {
|
|
1828
1898
|
send_traces_ctx *ctx = (send_traces_ctx *)arg;
|
|
1829
1899
|
free_raw_span((VALUE)&ctx->span_owner);
|
|
1900
|
+
if (ctx->response != NULL) {
|
|
1901
|
+
ddog_trace_exporter_response_free(ctx->response);
|
|
1902
|
+
ctx->response = NULL;
|
|
1903
|
+
}
|
|
1830
1904
|
if (ctx->chunks != NULL) {
|
|
1831
1905
|
ddog_tracer_trace_chunks_free(ctx->chunks);
|
|
1832
1906
|
ctx->chunks = NULL;
|
|
@@ -1883,6 +1957,12 @@ static VALUE _native_send_traces(VALUE self, VALUE traces, VALUE native_events_s
|
|
|
1883
1957
|
* ======================================================================== */
|
|
1884
1958
|
|
|
1885
1959
|
void trace_exporter_init(VALUE tracing_module) {
|
|
1960
|
+
id_handle_interrupt = rb_intern("handle_interrupt");
|
|
1961
|
+
observation_interrupt_mask = rb_hash_new();
|
|
1962
|
+
rb_hash_aset(observation_interrupt_mask, rb_cObject, ID2SYM(rb_intern("never")));
|
|
1963
|
+
rb_obj_freeze(observation_interrupt_mask);
|
|
1964
|
+
rb_global_variable(&observation_interrupt_mask);
|
|
1965
|
+
|
|
1886
1966
|
/* -- Module hierarchy -- */
|
|
1887
1967
|
VALUE transport_module = rb_define_module_under(tracing_module, "Transport");
|
|
1888
1968
|
VALUE native_module =
|
|
@@ -11,7 +11,7 @@ module Datadog
|
|
|
11
11
|
module LibdatadogExtconfHelpers
|
|
12
12
|
# Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
|
|
13
13
|
# may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
|
|
14
|
-
LIBDATADOG_VERSION = "~>
|
|
14
|
+
LIBDATADOG_VERSION = "~> 46.1.0.1.1"
|
|
15
15
|
|
|
16
16
|
# Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
|
|
17
17
|
# libdatadog are moved after the extension gets compiled.
|