datadog 2.23.0 → 2.24.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 +44 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +17 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +1 -9
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +14 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +2 -1
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/process.rb +9 -1
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +6 -4
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +3 -16
- data/lib/datadog/core/remote/transport/http/config.rb +4 -44
- data/lib/datadog/core/remote/transport/http/negotiation.rb +0 -39
- data/lib/datadog/core/remote/transport/http.rb +13 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +7 -16
- data/lib/datadog/core/telemetry/component.rb +52 -13
- data/lib/datadog/core/telemetry/event/app_started.rb +34 -0
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -32
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -10
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +19 -8
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +9 -0
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/only_once_successful.rb +2 -0
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams/transport/http/stats.rb +1 -36
- data/lib/datadog/data_streams/transport/http.rb +5 -6
- data/lib/datadog/data_streams/transport/stats.rb +3 -17
- data/lib/datadog/di/contrib/active_record.rb +31 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +17 -4
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_manager.rb +37 -31
- data/lib/datadog/di/probe_notification_builder.rb +15 -2
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +7 -35
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -31
- data/lib/datadog/di/transport/http/input.rb +1 -31
- data/lib/datadog/di/transport/http.rb +28 -17
- data/lib/datadog/di/transport/input.rb +7 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/open_feature/evaluation_engine.rb +2 -1
- data/lib/datadog/open_feature/remote.rb +3 -10
- data/lib/datadog/open_feature/transport.rb +9 -11
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -2
- data/lib/datadog/opentelemetry/metrics.rb +21 -14
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -8
- data/lib/datadog/profiling/collectors/code_provenance.rb +27 -2
- data/lib/datadog/profiling/collectors/info.rb +2 -1
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +31 -32
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +2 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +6 -3
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/traces.rb +6 -66
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- metadata +7 -13
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/data_streams/transport/http/api.rb +0 -33
- data/lib/datadog/data_streams/transport/http/client.rb +0 -21
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1e3df0d4845537939ee39a49f98f9645cf0b5f3cd8f62cd9b7c8dd7f7cf112f
|
|
4
|
+
data.tar.gz: e84c39b5b0d3b464aa5d9c1d050a215374520575832bee48671549bbf9696973
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f00d5556de98278dc5f80d1146374b378e6d21e32c041239e0e6a6237f4169d79061f1e94df1f8221255a2a807ed6a3ff6f80668ff3421030737c6ec7bf35f76
|
|
7
|
+
data.tar.gz: 94a76fd5432c238ee71c261419cb99e943143e802092ba0ec4aa9391e988f5ed6e9c307295211f0c16951d47e060633b62b40f982c83834aa179b6e66b03af91
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [2.24.0] - 2026-01-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* Core: Add support for installing the gem on Ruby 4.0.x stable ([#5157][])
|
|
10
|
+
* Tracing: Add origin detection using extra headers and the `DD_EXTERNAL_ENV` variable. ([#5028][])
|
|
11
|
+
* Dynamic Instrumentation: Add one-click enablement support ([#5150][])
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
* Profiling: Remove profiler warning related to the Ractor issue ([#5194][])
|
|
16
|
+
* Profiling: Disable heap profiling on Ruby 4 due to incompatibility ([#5148][])
|
|
17
|
+
* Dynamic Instrumentation: Stop using customer-provided time provider for method duration calculation ([#5153][])
|
|
18
|
+
* Live Debugger / Dynamic Instrumentation: Improve probe instrumentation ([#5165][])
|
|
19
|
+
* Live Debugger / Dynamic Instrumentation: Improve instrumentation reliability for probes ([#5169][])
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
* Core: Improve reliability of worker shutdown ([#5176][])
|
|
24
|
+
* Core: Fix RDoc error when installing the `datadog` gem ([#5145][])
|
|
25
|
+
* Tracing: Ensure `Tracing.continue_from!` keeps the active trace for the full block duration. ([#4941][])
|
|
26
|
+
* Profiling: Fix and refine profiler thread state categorization for Ruby 4 ([#5197][])
|
|
27
|
+
* Profiling: Fix profiler error triggering `Bundler::PermissionError` ([#5146][])
|
|
28
|
+
* Live Debugger / Dynamic Instrumentation: Fix Live Debugger and Dynamic Instrumentation UI for forking web servers ([#5159][])
|
|
29
|
+
* Live Debugger / Dynamic Instrumentation: Fix method probe leak when a referenced class loads after the probe reaches the application ([#5168][])
|
|
30
|
+
|
|
5
31
|
## [2.23.0] - 2025-12-11
|
|
6
32
|
|
|
7
33
|
### Added
|
|
@@ -3392,7 +3418,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
|
3392
3418
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3393
3419
|
|
|
3394
3420
|
|
|
3395
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.
|
|
3421
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.24.0...master
|
|
3422
|
+
[2.24.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.23.0...v2.24.0
|
|
3396
3423
|
[2.23.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.22.0...v2.23.0
|
|
3397
3424
|
[2.22.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.21.0...v2.22.0
|
|
3398
3425
|
[2.21.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.20.0...v2.21.0
|
|
@@ -5010,6 +5037,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5010
5037
|
[#4914]: https://github.com/DataDog/dd-trace-rb/issues/4914
|
|
5011
5038
|
[#4918]: https://github.com/DataDog/dd-trace-rb/issues/4918
|
|
5012
5039
|
[#4919]: https://github.com/DataDog/dd-trace-rb/issues/4919
|
|
5040
|
+
[#4941]: https://github.com/DataDog/dd-trace-rb/issues/4941
|
|
5013
5041
|
[#4957]: https://github.com/DataDog/dd-trace-rb/issues/4957
|
|
5014
5042
|
[#4965]: https://github.com/DataDog/dd-trace-rb/issues/4965
|
|
5015
5043
|
[#4969]: https://github.com/DataDog/dd-trace-rb/issues/4969
|
|
@@ -5024,6 +5052,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5024
5052
|
[#5021]: https://github.com/DataDog/dd-trace-rb/issues/5021
|
|
5025
5053
|
[#5024]: https://github.com/DataDog/dd-trace-rb/issues/5024
|
|
5026
5054
|
[#5025]: https://github.com/DataDog/dd-trace-rb/issues/5025
|
|
5055
|
+
[#5028]: https://github.com/DataDog/dd-trace-rb/issues/5028
|
|
5027
5056
|
[#5031]: https://github.com/DataDog/dd-trace-rb/issues/5031
|
|
5028
5057
|
[#5033]: https://github.com/DataDog/dd-trace-rb/issues/5033
|
|
5029
5058
|
[#5042]: https://github.com/DataDog/dd-trace-rb/issues/5042
|
|
@@ -5036,6 +5065,19 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5036
5065
|
[#5086]: https://github.com/DataDog/dd-trace-rb/issues/5086
|
|
5037
5066
|
[#5091]: https://github.com/DataDog/dd-trace-rb/issues/5091
|
|
5038
5067
|
[#5122]: https://github.com/DataDog/dd-trace-rb/issues/5122
|
|
5068
|
+
[#5145]: https://github.com/DataDog/dd-trace-rb/issues/5145
|
|
5069
|
+
[#5146]: https://github.com/DataDog/dd-trace-rb/issues/5146
|
|
5070
|
+
[#5148]: https://github.com/DataDog/dd-trace-rb/issues/5148
|
|
5071
|
+
[#5150]: https://github.com/DataDog/dd-trace-rb/issues/5150
|
|
5072
|
+
[#5153]: https://github.com/DataDog/dd-trace-rb/issues/5153
|
|
5073
|
+
[#5157]: https://github.com/DataDog/dd-trace-rb/issues/5157
|
|
5074
|
+
[#5159]: https://github.com/DataDog/dd-trace-rb/issues/5159
|
|
5075
|
+
[#5165]: https://github.com/DataDog/dd-trace-rb/issues/5165
|
|
5076
|
+
[#5168]: https://github.com/DataDog/dd-trace-rb/issues/5168
|
|
5077
|
+
[#5169]: https://github.com/DataDog/dd-trace-rb/issues/5169
|
|
5078
|
+
[#5176]: https://github.com/DataDog/dd-trace-rb/issues/5176
|
|
5079
|
+
[#5194]: https://github.com/DataDog/dd-trace-rb/issues/5194
|
|
5080
|
+
[#5197]: https://github.com/DataDog/dd-trace-rb/issues/5197
|
|
5039
5081
|
[@AdrianLC]: https://github.com/AdrianLC
|
|
5040
5082
|
[@Azure7111]: https://github.com/Azure7111
|
|
5041
5083
|
[@BabyGroot]: https://github.com/BabyGroot
|
|
@@ -5190,4 +5232,4 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
|
5190
5232
|
[@y-yagi]: https://github.com/y-yagi
|
|
5191
5233
|
[@yujideveloper]: https://github.com/yujideveloper
|
|
5192
5234
|
[@yukimurasawa]: https://github.com/yukimurasawa
|
|
5193
|
-
[@zachmccormick]: https://github.com/zachmccormick
|
|
5235
|
+
[@zachmccormick]: https://github.com/zachmccormick
|
|
@@ -347,8 +347,10 @@ void sample_thread(
|
|
|
347
347
|
} else if (CHARSLICE_EQUALS("select", name_slice)) { // Expected to be Kernel.select
|
|
348
348
|
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
349
349
|
} else if (
|
|
350
|
-
CHARSLICE_EQUALS("synchronize", name_slice) || // Expected to be Monitor/Mutex#synchronize
|
|
351
|
-
|
|
350
|
+
CHARSLICE_EQUALS("synchronize", name_slice) || // Expected to be Monitor/Mutex#synchronize on Ruby 2 & 3, and Monitor#synchronize on 4 (Mutex becomes <internal:thread_sync>)
|
|
351
|
+
#ifdef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby < 4
|
|
352
|
+
CHARSLICE_EQUALS("lock", name_slice) || // Expected to be Mutex#lock
|
|
353
|
+
#endif
|
|
352
354
|
CHARSLICE_EQUALS("join", name_slice) // Expected to be Thread#join
|
|
353
355
|
) {
|
|
354
356
|
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
@@ -366,9 +368,19 @@ void sample_thread(
|
|
|
366
368
|
#endif
|
|
367
369
|
} else {
|
|
368
370
|
#ifndef NO_PRIMITIVE_POP // Ruby >= 3.2
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
371
|
+
if (CHARSLICE_EQUALS("<internal:thread_sync>", filename_slice)) {
|
|
372
|
+
if (CHARSLICE_EQUALS("pop", name_slice)) { // Expected to be Queue/SizedQueue#pop
|
|
373
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
374
|
+
}
|
|
375
|
+
#ifndef NO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE // Ruby >= 4
|
|
376
|
+
else if (CHARSLICE_EQUALS("synchronize", name_slice) || CHARSLICE_EQUALS("lock", name_slice)) { // Expected to be Mutex#lock/synchronize
|
|
377
|
+
state_label->str = DDOG_CHARSLICE_C("blocked");
|
|
378
|
+
} else if (CHARSLICE_EQUALS("sleep", name_slice)) { // Expected to be Mutex#sleep
|
|
379
|
+
state_label->str = DDOG_CHARSLICE_C("sleeping");
|
|
380
|
+
} else if (CHARSLICE_EQUALS("wait", name_slice)) { // Expected to be ConditionVariable#wait
|
|
381
|
+
state_label->str = DDOG_CHARSLICE_C("waiting");
|
|
382
|
+
}
|
|
383
|
+
#endif
|
|
372
384
|
}
|
|
373
385
|
#endif
|
|
374
386
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// NOTE: This file is a part of the profiling native extension even though the
|
|
2
|
+
// runtime stacks feature is consumed by the crashtracker. The profiling
|
|
3
|
+
// extension already carries all the Ruby VM private header access and build
|
|
4
|
+
// plumbing required to safely poke at internal structures. Sharing that setup
|
|
5
|
+
// avoids duplicating another native extension with the same (fragile) access
|
|
6
|
+
// patterns, and keeps the overall install/build surface area smaller.
|
|
7
|
+
//
|
|
8
|
+
// This also means that this functionality is depend on the profiling native extension
|
|
9
|
+
// being available and built
|
|
10
|
+
#include "extconf.h"
|
|
11
|
+
|
|
12
|
+
#if defined(__linux__)
|
|
13
|
+
|
|
14
|
+
#include <datadog/crashtracker.h>
|
|
15
|
+
#include "datadog_ruby_common.h"
|
|
16
|
+
#include "private_vm_api_access.h"
|
|
17
|
+
#include <sys/mman.h>
|
|
18
|
+
#include <unistd.h>
|
|
19
|
+
#include <errno.h>
|
|
20
|
+
#include <string.h>
|
|
21
|
+
|
|
22
|
+
static const rb_data_type_t *crashtracker_thread_data_type = NULL;
|
|
23
|
+
|
|
24
|
+
static void ruby_runtime_stack_callback(
|
|
25
|
+
void (*emit_frame)(const ddog_crasht_RuntimeStackFrame*)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Use a fixed, preallocated buffer for crash-time runtime stacks to avoid
|
|
29
|
+
// heap allocation in the signal/crash path.
|
|
30
|
+
#define RUNTIME_STACK_MAX_FRAMES 512
|
|
31
|
+
static frame_info runtime_stack_buffer[RUNTIME_STACK_MAX_FRAMES];
|
|
32
|
+
|
|
33
|
+
#if defined(__x86_64__)
|
|
34
|
+
# define SYS_MINCORE 0x1B
|
|
35
|
+
#elif defined(__aarch64__)
|
|
36
|
+
# define SYS_MINCORE 0xE8
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
long syscall(long number, ...);
|
|
40
|
+
|
|
41
|
+
// align down to power of two
|
|
42
|
+
static inline uintptr_t align_down(uintptr_t x, uintptr_t align) {
|
|
43
|
+
return x & ~(align - 1u);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static uintptr_t cached_page_size = 0;
|
|
47
|
+
|
|
48
|
+
// TODO: This function is not necessarily Ruby specific. This will be moved to
|
|
49
|
+
// `libdatadog` in the future as a shared utility function.
|
|
50
|
+
static inline bool is_pointer_readable(const void *ptr, size_t size) {
|
|
51
|
+
if (!ptr || size == 0) return false;
|
|
52
|
+
|
|
53
|
+
uintptr_t page_size = cached_page_size;
|
|
54
|
+
|
|
55
|
+
const uintptr_t start = align_down((uintptr_t)ptr, page_size);
|
|
56
|
+
const uintptr_t end = ((uintptr_t)ptr + size - 1u);
|
|
57
|
+
const uintptr_t last = align_down(end, page_size);
|
|
58
|
+
|
|
59
|
+
// Number of pages spanned
|
|
60
|
+
size_t pages = 1u + (last != start);
|
|
61
|
+
if (pages > 2u) pages = 2u;
|
|
62
|
+
|
|
63
|
+
unsigned char vec[2];
|
|
64
|
+
|
|
65
|
+
int retries = 5;
|
|
66
|
+
for (;;) {
|
|
67
|
+
size_t len = pages * (size_t)page_size;
|
|
68
|
+
long rc = syscall(SYS_MINCORE, (void*)start, len, vec);
|
|
69
|
+
|
|
70
|
+
if (rc == 0) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
int e = errno;
|
|
75
|
+
if (e == ENOMEM || e == EFAULT) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (e == EAGAIN && retries-- > 0) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Unknown errno, we assume mapped to avoid cascading faults in crash path
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static inline ddog_CharSlice char_slice_from_cstr(const char *cstr) {
|
|
89
|
+
if (cstr == NULL) {
|
|
90
|
+
return (ddog_CharSlice){.ptr = NULL, .len = 0};
|
|
91
|
+
}
|
|
92
|
+
return (ddog_CharSlice){.ptr = cstr, .len = strlen(cstr)};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static ddog_CharSlice safe_string_value(VALUE str) {
|
|
96
|
+
if (str == Qnil) return DDOG_CHARSLICE_C("<nil>");
|
|
97
|
+
|
|
98
|
+
// Validate object and payload readability in one check
|
|
99
|
+
if (!is_pointer_readable((const void *)str, sizeof(struct RString))) return DDOG_CHARSLICE_C("<corrupted>");
|
|
100
|
+
if (!RB_TYPE_P(str, T_STRING)) return DDOG_CHARSLICE_C("<not_string>");
|
|
101
|
+
|
|
102
|
+
long len = RSTRING_LEN(str);
|
|
103
|
+
if (len < 0 || len > 1024) return DDOG_CHARSLICE_C("<length_over_limit>");
|
|
104
|
+
|
|
105
|
+
const char *ptr = RSTRING_PTR(str);
|
|
106
|
+
if (!ptr) return DDOG_CHARSLICE_C("<null>");
|
|
107
|
+
|
|
108
|
+
if (!is_pointer_readable(ptr, len > 0 ? len : 1)) return DDOG_CHARSLICE_C("<unreadable>");
|
|
109
|
+
|
|
110
|
+
return (ddog_CharSlice){.ptr = ptr, .len = (size_t)len};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static void emit_placeholder_frame(
|
|
114
|
+
void (*emit_frame)(const ddog_crasht_RuntimeStackFrame*),
|
|
115
|
+
const char *label
|
|
116
|
+
) {
|
|
117
|
+
ddog_crasht_RuntimeStackFrame frame = {
|
|
118
|
+
.type_name = DDOG_CHARSLICE_C(""),
|
|
119
|
+
.function = char_slice_from_cstr(label),
|
|
120
|
+
.file = DDOG_CHARSLICE_C("<unknown>"),
|
|
121
|
+
.line = 0,
|
|
122
|
+
.column = 0
|
|
123
|
+
};
|
|
124
|
+
emit_frame(&frame);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Collect the crashing thread's frames via ddtrace_rb_profile_frames into a static buffer, then emit
|
|
128
|
+
// them newest-first. If corruption is detected, emit placeholder frames so the crash report still
|
|
129
|
+
// completes. We lean on the Ruby VM helpers we already use for profiling and rely on crashtracker's
|
|
130
|
+
// safety nets so a failure here should not impact customers.
|
|
131
|
+
static void ruby_runtime_stack_callback(
|
|
132
|
+
void (*emit_frame)(const ddog_crasht_RuntimeStackFrame*)
|
|
133
|
+
) {
|
|
134
|
+
// Grab the Ruby thread we crashed on; crashtracker only runs once.
|
|
135
|
+
VALUE current_thread = rb_thread_current();
|
|
136
|
+
if (current_thread == Qnil) return;
|
|
137
|
+
|
|
138
|
+
if (crashtracker_thread_data_type == NULL) return;
|
|
139
|
+
|
|
140
|
+
if (!rb_typeddata_is_kind_of(current_thread, crashtracker_thread_data_type)) {
|
|
141
|
+
emit_placeholder_frame(emit_frame, "<runtime stack not found>");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Use the profiling helper to gather frames into our static buffer.
|
|
146
|
+
int frame_count = ddtrace_rb_profile_frames(
|
|
147
|
+
current_thread,
|
|
148
|
+
0,
|
|
149
|
+
RUNTIME_STACK_MAX_FRAMES,
|
|
150
|
+
runtime_stack_buffer
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (frame_count <= 0) {
|
|
154
|
+
emit_placeholder_frame(emit_frame, "<runtime stack not found>");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (int i = frame_count - 1; i >= 0; i--) {
|
|
159
|
+
frame_info *info = &runtime_stack_buffer[i];
|
|
160
|
+
|
|
161
|
+
if (info->is_ruby_frame) {
|
|
162
|
+
const void *iseq = (const void *)info->as.ruby_frame.iseq;
|
|
163
|
+
ddog_CharSlice function_slice = DDOG_CHARSLICE_C("<unknown>");
|
|
164
|
+
ddog_CharSlice file_slice = DDOG_CHARSLICE_C("<unknown>");
|
|
165
|
+
|
|
166
|
+
if (iseq && is_pointer_readable(iseq, sizeof_rb_iseq_t())) {
|
|
167
|
+
function_slice = safe_string_value(ddtrace_iseq_base_label(iseq));
|
|
168
|
+
file_slice = safe_string_value(ddtrace_iseq_path(iseq));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
ddog_crasht_RuntimeStackFrame frame = {
|
|
172
|
+
.type_name = DDOG_CHARSLICE_C(""),
|
|
173
|
+
.function = function_slice,
|
|
174
|
+
.file = file_slice,
|
|
175
|
+
.line = info->as.ruby_frame.line,
|
|
176
|
+
.column = 0
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
emit_frame(&frame);
|
|
180
|
+
} else {
|
|
181
|
+
ddog_CharSlice function_slice = DDOG_CHARSLICE_C("<C method>");
|
|
182
|
+
ddog_CharSlice file_slice = DDOG_CHARSLICE_C("<C extension>");
|
|
183
|
+
|
|
184
|
+
if (info->as.native_frame.method_id) {
|
|
185
|
+
const char *method_name = rb_id2name(info->as.native_frame.method_id);
|
|
186
|
+
if (is_pointer_readable(method_name, 256)) {
|
|
187
|
+
size_t method_name_len = strnlen(method_name, 256);
|
|
188
|
+
if (method_name_len > 0 && method_name_len < 256) {
|
|
189
|
+
function_slice = char_slice_from_cstr(method_name);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
ddog_crasht_RuntimeStackFrame frame = {
|
|
195
|
+
.type_name = DDOG_CHARSLICE_C(""),
|
|
196
|
+
.function = function_slice,
|
|
197
|
+
.file = file_slice,
|
|
198
|
+
.line = 0,
|
|
199
|
+
.column = 0
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
emit_frame(&frame);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (frame_count == RUNTIME_STACK_MAX_FRAMES) {
|
|
207
|
+
emit_placeholder_frame(emit_frame, "<truncated frames>");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void crashtracking_runtime_stacks_init(void) {
|
|
212
|
+
cached_page_size = (uintptr_t)sysconf(_SC_PAGESIZE);
|
|
213
|
+
if (cached_page_size == 0 || (cached_page_size & (cached_page_size - 1u))) {
|
|
214
|
+
cached_page_size = 4096;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (crashtracker_thread_data_type == NULL) {
|
|
218
|
+
VALUE current_thread = rb_thread_current();
|
|
219
|
+
if (current_thread == Qnil) {
|
|
220
|
+
rb_raise(rb_eRuntimeError, "crashtracking_runtime_stacks_init: rb_thread_current returned Qnil");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const rb_data_type_t *thread_data_type = RTYPEDDATA_TYPE(current_thread);
|
|
224
|
+
if (!thread_data_type) {
|
|
225
|
+
rb_raise(rb_eRuntimeError, "crashtracking_runtime_stacks_init: RTYPEDDATA_TYPE returned NULL");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
crashtracker_thread_data_type = thread_data_type;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Register immediately so Ruby doesn't need to manage this explicitly.
|
|
232
|
+
ddog_crasht_register_runtime_frame_callback(ruby_runtime_stack_callback);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
#else
|
|
236
|
+
// Keep init symbol to satisfy linkage on non linux platforms, but do nothing
|
|
237
|
+
void crashtracking_runtime_stacks_init(void) {}
|
|
238
|
+
#endif
|
|
239
|
+
|
|
@@ -138,8 +138,11 @@ if have_header("dlfcn.h")
|
|
|
138
138
|
have_func("dladdr")
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
+
# On older Rubies, there was no primitive mutex and condition variable implemented in `thread_sync.rb` (internal)
|
|
142
|
+
$defs << "-DNO_PRIMITIVE_MUTEX_AND_CONDITION_VARIABLE" if RUBY_VERSION < "4"
|
|
143
|
+
|
|
141
144
|
# On Ruby 4, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
|
|
142
|
-
$defs << "-DNO_IMEMO_OBJECT_ID" unless RUBY_VERSION < "4
|
|
145
|
+
$defs << "-DNO_IMEMO_OBJECT_ID" unless RUBY_VERSION < "4"
|
|
143
146
|
|
|
144
147
|
# This symbol is exclusively visible on certain Ruby versions: 2.6 to 3.2, as well as 3.4 (but not 4.0+)
|
|
145
148
|
# It's only used to get extra information about an object when a failure happens, so it's a "very nice to have" but not
|
|
@@ -76,6 +76,18 @@ rb_nativethread_id_t pthread_id_for(VALUE thread) {
|
|
|
76
76
|
#endif
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
size_t sizeof_rb_iseq_t(void) {
|
|
80
|
+
return sizeof(rb_iseq_t);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
VALUE ddtrace_iseq_base_label(const void *iseq) {
|
|
84
|
+
return rb_iseq_base_label((const rb_iseq_t *)iseq);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
VALUE ddtrace_iseq_path(const void *iseq) {
|
|
88
|
+
return rb_iseq_path((const rb_iseq_t *)iseq);
|
|
89
|
+
}
|
|
90
|
+
|
|
79
91
|
// Queries if the current thread is the owner of the global VM lock.
|
|
80
92
|
//
|
|
81
93
|
// @ivoanjo: Ruby has a similarly-named `ruby_thread_has_gvl_p` but that API is insufficient for our needs because it can
|
|
@@ -47,6 +47,10 @@ VALUE thread_name_for(VALUE thread);
|
|
|
47
47
|
|
|
48
48
|
int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *stack_buffer);
|
|
49
49
|
|
|
50
|
+
size_t sizeof_rb_iseq_t(void);
|
|
51
|
+
VALUE ddtrace_iseq_base_label(const void *iseq);
|
|
52
|
+
VALUE ddtrace_iseq_path(const void *iseq);
|
|
53
|
+
|
|
50
54
|
// Returns true if the current thread belongs to the main Ractor or if Ruby has no Ractor support
|
|
51
55
|
bool ddtrace_rb_ractor_main_p(void);
|
|
52
56
|
|
|
@@ -23,6 +23,7 @@ void collectors_thread_context_init(VALUE profiling_module);
|
|
|
23
23
|
void encoded_profile_init(VALUE profiling_module);
|
|
24
24
|
void http_transport_init(VALUE profiling_module);
|
|
25
25
|
void stack_recorder_init(VALUE profiling_module);
|
|
26
|
+
void crashtracking_runtime_stacks_init(void);
|
|
26
27
|
|
|
27
28
|
static VALUE native_working_p(VALUE self);
|
|
28
29
|
static VALUE _native_grab_gvl_and_raise(DDTRACE_UNUSED VALUE _self, VALUE exception_class, VALUE test_message, VALUE test_message_arg, VALUE release_gvl);
|
|
@@ -65,6 +66,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
|
65
66
|
encoded_profile_init(profiling_module);
|
|
66
67
|
http_transport_init(profiling_module);
|
|
67
68
|
stack_recorder_init(profiling_module);
|
|
69
|
+
crashtracking_runtime_stacks_init();
|
|
68
70
|
unsafe_api_calls_check_init();
|
|
69
71
|
|
|
70
72
|
// Hosts methods used for testing the native code using RSpec
|
|
@@ -7,7 +7,8 @@ module Datadog
|
|
|
7
7
|
# This class accumulates the context over the request life-cycle and exposes
|
|
8
8
|
# interface sufficient for instrumentation to perform threat detection.
|
|
9
9
|
class Context
|
|
10
|
-
|
|
10
|
+
# Steep: https://github.com/soutaro/steep/issues/1880
|
|
11
|
+
ActiveContextError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
11
12
|
|
|
12
13
|
# TODO: add delegators for active trace span
|
|
13
14
|
attr_reader :trace, :span, :events
|
|
@@ -7,8 +7,6 @@ module Datadog
|
|
|
7
7
|
module AppSec
|
|
8
8
|
# Remote
|
|
9
9
|
module Remote
|
|
10
|
-
class ReadError < StandardError; end
|
|
11
|
-
|
|
12
10
|
class NoRulesError < StandardError; end
|
|
13
11
|
|
|
14
12
|
class << self
|
|
@@ -109,13 +107,7 @@ module Datadog
|
|
|
109
107
|
end
|
|
110
108
|
|
|
111
109
|
def parse_content(content)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
content.data.rewind
|
|
115
|
-
|
|
116
|
-
raise ReadError, 'EOF reached' if data.nil?
|
|
117
|
-
|
|
118
|
-
JSON.parse(data)
|
|
110
|
+
JSON.parse(content.data)
|
|
119
111
|
end
|
|
120
112
|
end
|
|
121
113
|
end
|
|
@@ -70,7 +70,8 @@ module Datadog
|
|
|
70
70
|
|
|
71
71
|
def initialize(duration_ext_ns:, input_truncated:)
|
|
72
72
|
@events = []
|
|
73
|
-
@actions =
|
|
73
|
+
@actions = {}.freeze
|
|
74
|
+
@attributes = {}.freeze
|
|
74
75
|
@duration_ns = 0
|
|
75
76
|
@duration_ext_ns = duration_ext_ns
|
|
76
77
|
@input_truncated = !!input_truncated
|
|
@@ -9,7 +9,7 @@ module Datadog
|
|
|
9
9
|
class ConfigHelper
|
|
10
10
|
def initialize(
|
|
11
11
|
source_env: ENV,
|
|
12
|
-
supported_configurations:
|
|
12
|
+
supported_configurations: SUPPORTED_CONFIGURATION_NAMES,
|
|
13
13
|
aliases: ALIASES,
|
|
14
14
|
alias_to_canonical: ALIAS_TO_CANONICAL,
|
|
15
15
|
raise_on_unknown_env_var: false
|
|
@@ -21,12 +21,12 @@ module Datadog
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
private_class_method def self.log_deprecated_environment_variables(logger, source_env, source_name, deprecations, alias_to_canonical)
|
|
24
|
-
deprecations.each do |deprecated_env_var
|
|
24
|
+
deprecations.each do |deprecated_env_var|
|
|
25
25
|
next unless source_env.key?(deprecated_env_var)
|
|
26
26
|
|
|
27
27
|
Datadog::Core.log_deprecation(disallowed_next_major: false, logger: logger) do
|
|
28
28
|
"#{deprecated_env_var} #{source_name} variable is deprecated" +
|
|
29
|
-
(alias_to_canonical[deprecated_env_var] ? ", use #{alias_to_canonical[deprecated_env_var]} instead." : ".
|
|
29
|
+
(alias_to_canonical[deprecated_env_var] ? ", use #{alias_to_canonical[deprecated_env_var]} instead." : ".")
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -42,7 +42,8 @@ module Datadog
|
|
|
42
42
|
# Acts as DSL for building OptionDefinitions
|
|
43
43
|
# @public_api
|
|
44
44
|
class Builder
|
|
45
|
-
|
|
45
|
+
# Steep: https://github.com/soutaro/steep/issues/1880
|
|
46
|
+
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
46
47
|
|
|
47
48
|
attr_reader \
|
|
48
49
|
:helpers
|
|
@@ -119,7 +120,8 @@ module Datadog
|
|
|
119
120
|
env_parser(&options[:env_parser]) if options.key?(:env_parser)
|
|
120
121
|
after_set(&options[:after_set]) if options.key?(:after_set)
|
|
121
122
|
resetter(&options[:resetter]) if options.key?(:resetter)
|
|
122
|
-
|
|
123
|
+
# Steep: https://github.com/soutaro/steep/issues/1979
|
|
124
|
+
setter(&options[:setter]) if options.key?(:setter) # steep:ignore BlockTypeMismatch
|
|
123
125
|
type(options[:type], **(options[:type_options] || {})) if options.key?(:type)
|
|
124
126
|
end
|
|
125
127
|
|
|
@@ -40,14 +40,16 @@ module Datadog
|
|
|
40
40
|
|
|
41
41
|
def default_helpers(name)
|
|
42
42
|
option_name = name.to_sym
|
|
43
|
-
#
|
|
44
|
-
|
|
43
|
+
# Steep: https://github.com/soutaro/steep/issues/335
|
|
44
|
+
# @type var opt_getter: Configuration::OptionDefinition::generic_proc
|
|
45
|
+
opt_getter = proc do # steep:ignore IncompatibleAssignment
|
|
45
46
|
# These Procs uses `get/set_option`, but we only add them to the OptionDefinition helpers here.
|
|
46
47
|
# Steep is right that these methods are not defined, but we only run these Procs in instance context.
|
|
47
48
|
get_option(option_name) # steep:ignore NoMethod
|
|
48
49
|
end
|
|
49
|
-
#
|
|
50
|
-
|
|
50
|
+
# Steep: https://github.com/soutaro/steep/issues/335
|
|
51
|
+
# @type var opt_setter: Configuration::OptionDefinition::generic_proc
|
|
52
|
+
opt_setter = proc do |value| # steep:ignore IncompatibleAssignment
|
|
51
53
|
set_option(option_name, value) # steep:ignore NoMethod
|
|
52
54
|
end
|
|
53
55
|
{
|
|
@@ -127,7 +129,8 @@ module Datadog
|
|
|
127
129
|
end
|
|
128
130
|
end
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
# Steep: https://github.com/soutaro/steep/issues/1880
|
|
133
|
+
InvalidOptionError = Class.new(StandardError) # steep:ignore IncompatibleAssignment
|
|
131
134
|
end
|
|
132
135
|
end
|
|
133
136
|
end
|
|
@@ -170,6 +170,20 @@ module Datadog
|
|
|
170
170
|
o.env Core::Environment::Ext::ENV_ENVIRONMENT
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
+
# Configuration for container environments. For internal use only.
|
|
174
|
+
# @!visibility private
|
|
175
|
+
settings :container do
|
|
176
|
+
# Data supplied by the container runner to assist in uniquely identifying this process.
|
|
177
|
+
# Used in [Origin Detection](https://docs.datadoghq.com/developers/dogstatsd/unix_socket/?tab=host#origin-detection)
|
|
178
|
+
#
|
|
179
|
+
# @default `DD_EXTERNAL_ENV` environment variable, otherwise `nil`
|
|
180
|
+
# @return [String,nil]
|
|
181
|
+
option :external_env do |o|
|
|
182
|
+
o.type :string, nilable: true
|
|
183
|
+
o.env Core::Environment::Ext::ENV_EXTERNAL_ENV
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
173
187
|
# Internal {Datadog::Statsd} metrics collection.
|
|
174
188
|
#
|
|
175
189
|
# @public_api
|
|
@@ -293,9 +307,6 @@ module Datadog
|
|
|
293
307
|
# for Ruby versions 2.x, 3.1.4+, 3.2.3+ and 3.3.0+
|
|
294
308
|
# (more details in {Datadog::Profiling::Component.enable_gc_profiling?})
|
|
295
309
|
#
|
|
296
|
-
# @warn Due to a VM bug in the Ractor implementation (https://bugs.ruby-lang.org/issues/19112) this feature
|
|
297
|
-
# stops working when Ractors get garbage collected.
|
|
298
|
-
#
|
|
299
310
|
# @default `DD_PROFILING_GC_ENABLED` environment variable, otherwise `true`
|
|
300
311
|
option :gc_enabled do |o|
|
|
301
312
|
o.type :bool
|
|
@@ -8,7 +8,7 @@ require 'set'
|
|
|
8
8
|
module Datadog
|
|
9
9
|
module Core
|
|
10
10
|
module Configuration
|
|
11
|
-
|
|
11
|
+
SUPPORTED_CONFIGURATION_NAMES =
|
|
12
12
|
Set["DD_AGENT_HOST",
|
|
13
13
|
"DD_API_KEY",
|
|
14
14
|
"DD_API_SECURITY_ENABLED",
|
|
@@ -47,6 +47,7 @@ module Datadog
|
|
|
47
47
|
"DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE",
|
|
48
48
|
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED",
|
|
49
49
|
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED",
|
|
50
|
+
"DD_EXTERNAL_ENV",
|
|
50
51
|
"DD_GIT_COMMIT_SHA",
|
|
51
52
|
"DD_GIT_REPOSITORY_URL",
|
|
52
53
|
"DD_HEALTH_METRICS_ENABLED",
|