ddtrace 1.16.0 → 1.18.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 +86 -1
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +8 -1
- data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -10
- data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +78 -18
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +1 -0
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +1 -3
- data/lib/datadog/appsec/component.rb +4 -1
- data/lib/datadog/appsec/configuration/settings.rb +4 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +0 -46
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -5
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -10
- data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
- data/lib/datadog/appsec/remote.rb +12 -9
- data/lib/datadog/core/configuration/settings.rb +1 -1
- data/lib/datadog/core/configuration.rb +4 -0
- data/lib/datadog/core/remote/worker.rb +1 -0
- data/lib/datadog/core/workers/async.rb +1 -0
- data/lib/datadog/kit/enable_core_dumps.rb +5 -6
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +39 -8
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +102 -3
- data/lib/datadog/opentracer/text_map_propagator.rb +2 -1
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -0
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/component.rb +13 -5
- data/lib/datadog/tracing/configuration/ext.rb +3 -0
- data/lib/datadog/tracing/configuration/settings.rb +18 -3
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
- data/lib/datadog/tracing/distributed/datadog.rb +0 -1
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/trace_digest.rb +31 -0
- data/lib/datadog/tracing/workers.rb +1 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69e775ab06a83ce14114a7287056e3d3fb575191b7ff6ccdc5c7b33f7fd58172
|
4
|
+
data.tar.gz: 13b607a4e29e516be4988dca7827eca09b79e968cf98e0641a155039d2ec3273
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d345e07c8b0a654974c51a7457b3fc6d3d7eb99226cfc5555d6bc8ee3e65b17b3782b1e582591be925297c09dd104108007b2081e28ee43c103f8f2fec3ffe5b
|
7
|
+
data.tar.gz: '085ea801f5fae16ed58cd79bab86839cd1aa23fa09261b39219264f603455633e19dbb8f60d647e407c7218d7d00052ef7b593405ec5af828af56ffecd58227d'
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,66 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [1.18.0] - 2023-12-07
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
* Tracing: Support lib injection for ARM64 architecture ([#3307][])
|
10
|
+
* Tracing: Add `error_handler` for `pg` instrumentation ([#3303][])
|
11
|
+
* Appsec: Enable "Trusted IPs", a.k.a passlist with optional monitoring ([#3229][])
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
|
15
|
+
* Mark ddtrace threads as fork-safe ([#3279][])
|
16
|
+
* Bump `datadog-ci` dependency to 0.5.0 ([#3308][])
|
17
|
+
* Bump `debase-ruby_core_source` dependency to 3.2.3 ([#3284][])
|
18
|
+
* Profiling: Disable profiler on Ruby 3.3 when running with RUBY_MN_THREADS=1 ([#3259][])
|
19
|
+
* Profiling: Run without "no signals" workaround on passenger 6.0.19+ ([#3280][])
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
* Tracing: Fix `pg` instrumentation `enabled` settings ([#3271][])
|
24
|
+
* Profiling: Fix potential crash by importing upstream `rb_profile_frames` fix ([#3289][])
|
25
|
+
* Appsec: Call `devise` RegistrationsController block ([#3286][])
|
26
|
+
|
27
|
+
## [1.17.0] - 2023-11-22
|
28
|
+
|
29
|
+
For W3C Trace Context, this release adds [`tracecontext`](https://www.w3.org/TR/trace-context/) to the default trace propagation extraction and injection styles. The new defaults are:
|
30
|
+
* Extraction: `Datadog,b3multi,b3,tracecontext`
|
31
|
+
* Injection: `Datadog,tracecontext`
|
32
|
+
|
33
|
+
And to increase interoperability with `tracecontext`, 128-bit Trace ID generation is now the default.
|
34
|
+
|
35
|
+
For OpenTelemetry, this release adds support for converting [OpenTelemetry Trace Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/general/trace/) into equivalent Datadog trace semantics. Also, it's now possible to configure top-level Datadog span fields using OpenTelemetry span attributes (https://github.com/DataDog/dd-trace-rb/pull/3262).
|
36
|
+
|
37
|
+
For CI Visibility, you can now manually create CI traces and spans with the [newly released API](https://github.com/DataDog/datadog-ci-rb/releases/tag/v0.4.0).
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
* OpenTelemetry: Parse OpenTelemetry semantic conventions to Datadog's ([#3273][])
|
42
|
+
* OpenTelemetry: Support span reserved attribute overrides ([#3262][])
|
43
|
+
* Tracing: Ensure W3C `tracestate` is always propagated ([#3255][])
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
|
47
|
+
* Tracing: Set 128-bit trace_id to true by default ([#3266][])
|
48
|
+
* Tracing: Default trace propagation styles to `Datadog,b3multi,b3,tracecontext` ([#3248][],[#3267][])
|
49
|
+
* Ci-App: Upgraded `datadog-ci` dependency to 0.4 ([#3270][])
|
50
|
+
|
51
|
+
## [1.16.2] - 2023-11-10
|
52
|
+
|
53
|
+
This release reverts a change to appsec response body parsing that was introduced in [1.16.0 ](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.16.0) that may cause memory leaks.
|
54
|
+
|
55
|
+
### Fixed
|
56
|
+
* Appsec: [Revert parse response body fix introduced in 1.16.0](https://github.com/DataDog/dd-trace-rb/pull/3153) ([#3252][])
|
57
|
+
|
58
|
+
## [1.16.1] - 2023-11-08
|
59
|
+
|
60
|
+
### Fixed
|
61
|
+
|
62
|
+
* Tracing: Fix `concurrent-ruby` future propagation without `active_trace` ([#3242][])
|
63
|
+
* Tracing: Fix host injection error handling ([#3240][])
|
64
|
+
|
5
65
|
## [1.16.0] - 2023-11-03
|
6
66
|
|
7
67
|
**This release includes a security change for the Tracing Redis integration:**
|
@@ -2620,7 +2680,11 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2620
2680
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2621
2681
|
|
2622
2682
|
|
2623
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.
|
2683
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.18.0...master
|
2684
|
+
[1.18.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.17.0...v1.18.0
|
2685
|
+
[1.17.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.2...v1.17.0
|
2686
|
+
[1.16.2]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.1...v1.16.2
|
2687
|
+
[1.16.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...v1.16.1
|
2624
2688
|
[1.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.15.0...v1.16.0
|
2625
2689
|
[1.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.14.0...v1.15.0
|
2626
2690
|
[1.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.1...1.14.0
|
@@ -3829,8 +3893,29 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3829
3893
|
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3830
3894
|
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3831
3895
|
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3896
|
+
[#3229]: https://github.com/DataDog/dd-trace-rb/issues/3229
|
3832
3897
|
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3833
3898
|
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3899
|
+
[#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
|
3900
|
+
[#3242]: https://github.com/DataDog/dd-trace-rb/issues/3242
|
3901
|
+
[#3248]: https://github.com/DataDog/dd-trace-rb/issues/3248
|
3902
|
+
[#3252]: https://github.com/DataDog/dd-trace-rb/issues/3252
|
3903
|
+
[#3255]: https://github.com/DataDog/dd-trace-rb/issues/3255
|
3904
|
+
[#3259]: https://github.com/DataDog/dd-trace-rb/issues/3259
|
3905
|
+
[#3262]: https://github.com/DataDog/dd-trace-rb/issues/3262
|
3906
|
+
[#3266]: https://github.com/DataDog/dd-trace-rb/issues/3266
|
3907
|
+
[#3267]: https://github.com/DataDog/dd-trace-rb/issues/3267
|
3908
|
+
[#3270]: https://github.com/DataDog/dd-trace-rb/issues/3270
|
3909
|
+
[#3271]: https://github.com/DataDog/dd-trace-rb/issues/3271
|
3910
|
+
[#3273]: https://github.com/DataDog/dd-trace-rb/issues/3273
|
3911
|
+
[#3279]: https://github.com/DataDog/dd-trace-rb/issues/3279
|
3912
|
+
[#3280]: https://github.com/DataDog/dd-trace-rb/issues/3280
|
3913
|
+
[#3284]: https://github.com/DataDog/dd-trace-rb/issues/3284
|
3914
|
+
[#3286]: https://github.com/DataDog/dd-trace-rb/issues/3286
|
3915
|
+
[#3289]: https://github.com/DataDog/dd-trace-rb/issues/3289
|
3916
|
+
[#3303]: https://github.com/DataDog/dd-trace-rb/issues/3303
|
3917
|
+
[#3307]: https://github.com/DataDog/dd-trace-rb/issues/3307
|
3918
|
+
[#3308]: https://github.com/DataDog/dd-trace-rb/issues/3308
|
3834
3919
|
[@AdrianLC]: https://github.com/AdrianLC
|
3835
3920
|
[@Azure7111]: https://github.com/Azure7111
|
3836
3921
|
[@BabyGroot]: https://github.com/BabyGroot
|
@@ -25,6 +25,9 @@ void self_test_clock_id(void) {
|
|
25
25
|
// Safety: This function is assumed never to raise exceptions by callers
|
26
26
|
thread_cpu_time_id thread_cpu_time_id_for(VALUE thread) {
|
27
27
|
rb_nativethread_id_t thread_id = pthread_id_for(thread);
|
28
|
+
|
29
|
+
if (thread_id == 0) return (thread_cpu_time_id) {.valid = false};
|
30
|
+
|
28
31
|
clockid_t clock_id;
|
29
32
|
|
30
33
|
int error = pthread_getcpuclockid(thread_id, &clock_id);
|
@@ -1150,6 +1150,7 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
|
|
1150
1150
|
// Since this is stack allocated, be careful about moving it
|
1151
1151
|
ddog_CharSlice class_name;
|
1152
1152
|
ddog_CharSlice *optional_class_name = NULL;
|
1153
|
+
char imemo_type[100];
|
1153
1154
|
|
1154
1155
|
if (state->allocation_type_enabled) {
|
1155
1156
|
optional_class_name = &class_name;
|
@@ -1197,7 +1198,13 @@ void thread_context_collector_sample_allocation(VALUE self_instance, unsigned in
|
|
1197
1198
|
class_name = ruby_value_type_to_class_name(type);
|
1198
1199
|
}
|
1199
1200
|
} else if (type == RUBY_T_IMEMO) {
|
1200
|
-
|
1201
|
+
const char *imemo_string = imemo_kind(new_object);
|
1202
|
+
if (imemo_string != NULL) {
|
1203
|
+
snprintf(imemo_type, 100, "(VM Internal, T_IMEMO, %s)", imemo_string);
|
1204
|
+
class_name = (ddog_CharSlice) {.ptr = imemo_type, .len = strlen(imemo_type)};
|
1205
|
+
} else { // Ruby < 3
|
1206
|
+
class_name = DDOG_CHARSLICE_C("(VM Internal, T_IMEMO)");
|
1207
|
+
}
|
1201
1208
|
} else {
|
1202
1209
|
class_name = ruby_vm_type; // For other weird internal things we just use the VM type
|
1203
1210
|
}
|
@@ -81,10 +81,7 @@ end
|
|
81
81
|
|
82
82
|
# Because we can't control what compiler versions our customers use, shipping with -Werror by default is a no-go.
|
83
83
|
# But we can enable it in CI, so that we quickly spot any new warnings that just got introduced.
|
84
|
-
|
85
|
-
# @ivoanjo TODO: 3.3.0-preview releases are causing issues in CI because `have_header('vm_core.h')` below triggers warnings;
|
86
|
-
# I've chosen to disable `-Werror` for this Ruby version for now, and we can revisit this on a later 3.3 release.
|
87
|
-
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true' && !RUBY_DESCRIPTION.include?('3.3.0preview')
|
84
|
+
add_compiler_flag '-Werror' if ENV['DDTRACE_CI'] == 'true'
|
88
85
|
|
89
86
|
# Older gcc releases may not default to C99 and we need to ask for this. This is also used:
|
90
87
|
# * by upstream Ruby -- search for gnu99 in the codebase
|
@@ -102,9 +99,6 @@ add_compiler_flag '-Wno-declaration-after-statement'
|
|
102
99
|
# cause a segfault later. Let's ensure that never happens.
|
103
100
|
add_compiler_flag '-Werror-implicit-function-declaration'
|
104
101
|
|
105
|
-
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
106
|
-
add_compiler_flag '-Wunused-parameter'
|
107
|
-
|
108
102
|
# The native extension is not intended to expose any symbols/functions for other native libraries to use;
|
109
103
|
# the sole exception being `Init_ddtrace_profiling_native_extension` which needs to be visible for Ruby to call it when
|
110
104
|
# it `dlopen`s the library.
|
@@ -131,6 +125,9 @@ if RUBY_PLATFORM.include?('linux')
|
|
131
125
|
$defs << '-DHAVE_PTHREAD_GETCPUCLOCKID'
|
132
126
|
end
|
133
127
|
|
128
|
+
# On older Rubies, M:N threads were not available
|
129
|
+
$defs << '-DNO_MN_THREADS_AVAILABLE' if RUBY_VERSION < '3.3'
|
130
|
+
|
134
131
|
# On older Rubies, we did not need to include the ractor header (this was built into the MJIT header)
|
135
132
|
$defs << '-DNO_RACTOR_HEADER_INCLUDE' if RUBY_VERSION < '3.3'
|
136
133
|
|
@@ -152,12 +149,18 @@ $defs << '-DNO_PRIMITIVE_POP' if RUBY_VERSION < '3.2'
|
|
152
149
|
# On older Rubies, there was no tid member in the internal thread structure
|
153
150
|
$defs << '-DNO_THREAD_TID' if RUBY_VERSION < '3.1'
|
154
151
|
|
152
|
+
# On older Rubies, there was no jit_return member on the rb_control_frame_t struct
|
153
|
+
$defs << '-DNO_JIT_RETURN' if RUBY_VERSION < '3.1'
|
154
|
+
|
155
155
|
# On older Rubies, we need to use a backported version of this function. See private_vm_api_access.h for details.
|
156
156
|
$defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
|
157
157
|
|
158
158
|
# On older Rubies, there are no Ractors
|
159
159
|
$defs << '-DNO_RACTORS' if RUBY_VERSION < '3'
|
160
160
|
|
161
|
+
# On older Rubies, rb_imemo_name did not exist
|
162
|
+
$defs << '-DNO_IMEMO_NAME' if RUBY_VERSION < '3'
|
163
|
+
|
161
164
|
# On older Rubies, objects would not move
|
162
165
|
$defs << '-DNO_T_MOVED' if RUBY_VERSION < '2.7'
|
163
166
|
|
@@ -238,6 +241,10 @@ if Datadog::Profiling::NativeExtensionHelpers::CAN_USE_MJIT_HEADER
|
|
238
241
|
# NOTE: This needs to come after all changes to $defs
|
239
242
|
create_header
|
240
243
|
|
244
|
+
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
245
|
+
# See the comment on the same flag below for why this is done last.
|
246
|
+
add_compiler_flag '-Wunused-parameter'
|
247
|
+
|
241
248
|
create_makefile EXTENSION_NAME
|
242
249
|
else
|
243
250
|
# The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on
|
@@ -253,9 +260,20 @@ else
|
|
253
260
|
Debase::RubyCoreSource
|
254
261
|
.create_makefile_with_core(
|
255
262
|
proc do
|
256
|
-
|
257
|
-
|
258
|
-
|
263
|
+
headers_available =
|
264
|
+
have_header('vm_core.h') &&
|
265
|
+
have_header('iseq.h') &&
|
266
|
+
(RUBY_VERSION < '3.3' || have_header('ractor_core.h'))
|
267
|
+
|
268
|
+
if headers_available
|
269
|
+
# Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
|
270
|
+
# This is added as late as possible because in some Rubies we support (e.g. 3.3), adding this flag before
|
271
|
+
# checking if internal VM headers are available causes those checks to fail because of this warning (and not
|
272
|
+
# because the headers are not available.)
|
273
|
+
add_compiler_flag '-Wunused-parameter'
|
274
|
+
end
|
275
|
+
|
276
|
+
headers_available
|
259
277
|
end,
|
260
278
|
EXTENSION_NAME,
|
261
279
|
)
|
@@ -16,7 +16,6 @@ static ID agent_id; // id of :agent in Ruby
|
|
16
16
|
|
17
17
|
static ID log_failure_to_process_tag_id; // id of :log_failure_to_process_tag in Ruby
|
18
18
|
|
19
|
-
static VALUE http_transport_class = Qnil;
|
20
19
|
static VALUE library_version_string = Qnil;
|
21
20
|
|
22
21
|
struct call_exporter_without_gvl_arguments {
|
@@ -54,7 +53,7 @@ static void interrupt_exporter_call(void *cancel_token);
|
|
54
53
|
static VALUE ddtrace_version(void);
|
55
54
|
|
56
55
|
void http_transport_init(VALUE profiling_module) {
|
57
|
-
http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
|
56
|
+
VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
|
58
57
|
|
59
58
|
rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
|
60
59
|
rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 12);
|
@@ -180,6 +179,10 @@ static ddog_Vec_Tag convert_tags(VALUE tags_as_array) {
|
|
180
179
|
}
|
181
180
|
|
182
181
|
static VALUE log_failure_to_process_tag(VALUE err_details) {
|
182
|
+
VALUE datadog_module = rb_const_get(rb_cObject, rb_intern("Datadog"));
|
183
|
+
VALUE profiling_module = rb_const_get(datadog_module, rb_intern("Profiling"));
|
184
|
+
VALUE http_transport_class = rb_const_get(profiling_module, rb_intern("HttpTransport"));
|
185
|
+
|
183
186
|
return rb_funcall(http_transport_class, log_failure_to_process_tag_id, 1, err_details);
|
184
187
|
}
|
185
188
|
|
@@ -58,9 +58,12 @@ static inline rb_thread_t *thread_struct_from_object(VALUE thread) {
|
|
58
58
|
}
|
59
59
|
|
60
60
|
rb_nativethread_id_t pthread_id_for(VALUE thread) {
|
61
|
-
// struct rb_native_thread was introduced in Ruby 3.2
|
61
|
+
// struct rb_native_thread was introduced in Ruby 3.2: https://github.com/ruby/ruby/pull/5836
|
62
62
|
#ifndef NO_RB_NATIVE_THREAD
|
63
|
-
|
63
|
+
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
64
|
+
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
65
|
+
if (native_thread == NULL) return 0;
|
66
|
+
return native_thread->thread_id;
|
64
67
|
#else
|
65
68
|
return thread_struct_from_object(thread)->thread_id;
|
66
69
|
#endif
|
@@ -113,15 +116,16 @@ bool is_current_thread_holding_the_gvl(void) {
|
|
113
116
|
|
114
117
|
if (current_owner == NULL) return (current_gvl_owner) {.valid = false};
|
115
118
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
119
|
+
#ifndef NO_RB_NATIVE_THREAD
|
120
|
+
struct rb_native_thread* current_owner_native_thread = current_owner->nt;
|
121
|
+
|
122
|
+
// This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
|
123
|
+
if (current_owner_native_thread == NULL) return (current_gvl_owner) {.valid = false};
|
124
|
+
|
125
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
|
126
|
+
#else
|
127
|
+
return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
|
128
|
+
#endif
|
125
129
|
}
|
126
130
|
#else
|
127
131
|
current_gvl_owner gvl_owner(void) {
|
@@ -182,7 +186,9 @@ uint64_t native_thread_id_for(VALUE thread) {
|
|
182
186
|
// The tid is only available on Ruby >= 3.1 + Linux (and FreeBSD). It's the same as `gettid()` aka the task id as seen in /proc
|
183
187
|
#if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
|
184
188
|
#ifndef NO_RB_NATIVE_THREAD
|
185
|
-
|
189
|
+
struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
|
190
|
+
if (native_thread == NULL) rb_raise(rb_eRuntimeError, "BUG: rb_native_thread* is null. Is this Ruby running with RUBY_MN_THREADS=1?");
|
191
|
+
return native_thread->tid;
|
186
192
|
#else
|
187
193
|
return thread_struct_from_object(thread)->tid;
|
188
194
|
#endif
|
@@ -407,6 +413,7 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
|
|
407
413
|
// the `VALUE` returned by rb_profile_frames returns `(eval)` instead of the path of the file where the `eval`
|
408
414
|
// was called from.
|
409
415
|
// * Imported fix from https://github.com/ruby/ruby/pull/7116 to avoid sampling threads that are still being created
|
416
|
+
// * Imported fix from https://github.com/ruby/ruby/pull/8415 to avoid potential crash when using YJIT.
|
410
417
|
//
|
411
418
|
// What is rb_profile_frames?
|
412
419
|
// `rb_profile_frames` is a Ruby VM debug API added for use by profilers for sampling the stack trace of a Ruby thread.
|
@@ -442,12 +449,15 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, VALUE *buff, i
|
|
442
449
|
// Modified from upstream: Instead of using `GET_EC` to collect info from the current thread,
|
443
450
|
// support sampling any thread (including the current) passed as an argument
|
444
451
|
rb_thread_t *th = thread_struct_from_object(thread);
|
445
|
-
#ifndef USE_THREAD_INSTEAD_OF_EXECUTION_CONTEXT // Modern Rubies
|
446
|
-
|
447
|
-
#else // Ruby < 2.5
|
448
|
-
|
449
|
-
#endif
|
452
|
+
#ifndef USE_THREAD_INSTEAD_OF_EXECUTION_CONTEXT // Modern Rubies
|
453
|
+
const rb_execution_context_t *ec = th->ec;
|
454
|
+
#else // Ruby < 2.5
|
455
|
+
const rb_thread_t *ec = th;
|
456
|
+
#endif
|
450
457
|
const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
|
458
|
+
#ifndef NO_JIT_RETURN
|
459
|
+
const rb_control_frame_t *top = cfp;
|
460
|
+
#endif
|
451
461
|
const rb_callable_method_entry_t *cme;
|
452
462
|
|
453
463
|
// Avoid sampling dead threads
|
@@ -522,7 +532,20 @@ int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, VALUE *buff, i
|
|
522
532
|
buff[i] = (VALUE)cfp->iseq;
|
523
533
|
}
|
524
534
|
|
525
|
-
|
535
|
+
// The topmost frame may not have an updated PC because the JIT
|
536
|
+
// may not have set one. The JIT compiler will update the PC
|
537
|
+
// before entering a new function (so that `caller` will work),
|
538
|
+
// so only the topmost frame could possibly have an out of date PC
|
539
|
+
#ifndef NO_JIT_RETURN
|
540
|
+
if (cfp == top && cfp->jit_return) {
|
541
|
+
lines[i] = 0;
|
542
|
+
} else {
|
543
|
+
lines[i] = calc_lineno(cfp->iseq, cfp->pc);
|
544
|
+
}
|
545
|
+
#else // Ruby < 3.1
|
546
|
+
lines[i] = calc_lineno(cfp->iseq, cfp->pc);
|
547
|
+
#endif
|
548
|
+
|
526
549
|
is_ruby_frame[i] = true;
|
527
550
|
i++;
|
528
551
|
}
|
@@ -811,3 +834,40 @@ VALUE invoke_location_for(VALUE thread, int *line_location) {
|
|
811
834
|
*line_location = NUM2INT(rb_iseq_first_lineno(iseq));
|
812
835
|
return rb_iseq_path(iseq);
|
813
836
|
}
|
837
|
+
|
838
|
+
void self_test_mn_enabled(void) {
|
839
|
+
#ifdef NO_MN_THREADS_AVAILABLE
|
840
|
+
return;
|
841
|
+
#else
|
842
|
+
if (ddtrace_get_ractor()->threads.sched.enable_mn_threads == true) {
|
843
|
+
rb_raise(rb_eRuntimeError, "Ruby VM is running with RUBY_MN_THREADS=1. This is not yet supported");
|
844
|
+
}
|
845
|
+
#endif
|
846
|
+
}
|
847
|
+
|
848
|
+
// Taken from upstream imemo.h at commit 6ebcf25de2859b5b6402b7e8b181066c32d0e0bf (November 2023, master branch)
|
849
|
+
// (See the Ruby project copyright and license above)
|
850
|
+
// to enable calling rb_imemo_name
|
851
|
+
//
|
852
|
+
// Modifications:
|
853
|
+
// * Added IMEMO_MASK define
|
854
|
+
// * Changed return type to int to avoid having to define `enum imemo_type`
|
855
|
+
static inline int ddtrace_imemo_type(VALUE imemo) {
|
856
|
+
// This mask is the same between Ruby 2.5 and 3.3-preview3. Furthermore, the intention of this method is to be used
|
857
|
+
// to call `rb_imemo_name` which correctly handles invalid numbers so even if the mask changes in the future, at most
|
858
|
+
// we'll get incorrect results (and never a VM crash)
|
859
|
+
#define IMEMO_MASK 0x0f
|
860
|
+
return (RBASIC(imemo)->flags >> FL_USHIFT) & IMEMO_MASK;
|
861
|
+
}
|
862
|
+
|
863
|
+
// Safety: This function assumes the object passed in is of the imemo type. But in the worst case, you'll just get
|
864
|
+
// a string that doesn't make any sense.
|
865
|
+
#ifndef NO_IMEMO_NAME
|
866
|
+
const char *imemo_kind(VALUE imemo) {
|
867
|
+
return rb_imemo_name(ddtrace_imemo_type(imemo));
|
868
|
+
}
|
869
|
+
#else
|
870
|
+
const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
|
871
|
+
return NULL;
|
872
|
+
}
|
873
|
+
#endif
|
@@ -49,3 +49,9 @@ bool ddtrace_rb_ractor_main_p(void);
|
|
49
49
|
// This is what Ruby shows in `Thread#to_s`.
|
50
50
|
// The file is returned directly, and the line is recorded onto *line_location.
|
51
51
|
VALUE invoke_location_for(VALUE thread, int *line_location);
|
52
|
+
|
53
|
+
// Check if RUBY_MN_THREADS is enabled (aka main Ractor is not doing 1:1 threads)
|
54
|
+
void self_test_mn_enabled(void);
|
55
|
+
|
56
|
+
// Provides more specific information on what kind an imemo is
|
57
|
+
const char *imemo_kind(VALUE imemo);
|
@@ -129,8 +129,6 @@
|
|
129
129
|
static VALUE ok_symbol = Qnil; // :ok in Ruby
|
130
130
|
static VALUE error_symbol = Qnil; // :error in Ruby
|
131
131
|
|
132
|
-
static VALUE stack_recorder_class = Qnil;
|
133
|
-
|
134
132
|
// Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
|
135
133
|
// `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
|
136
134
|
// tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
|
@@ -217,7 +215,7 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
|
|
217
215
|
static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */);
|
218
216
|
|
219
217
|
void stack_recorder_init(VALUE profiling_module) {
|
220
|
-
stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
218
|
+
VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
|
221
219
|
// Hosts methods used for testing the native code using RSpec
|
222
220
|
VALUE testing_module = rb_define_module_under(stack_recorder_class, "Testing");
|
223
221
|
|
@@ -38,12 +38,15 @@ module Datadog
|
|
38
38
|
|
39
39
|
data = AppSec::Processor::RuleLoader.load_data(
|
40
40
|
ip_denylist: settings.appsec.ip_denylist,
|
41
|
-
user_id_denylist: settings.appsec.user_id_denylist
|
41
|
+
user_id_denylist: settings.appsec.user_id_denylist,
|
42
42
|
)
|
43
43
|
|
44
|
+
exclusions = AppSec::Processor::RuleLoader.load_exclusions(ip_passlist: settings.appsec.ip_passlist)
|
45
|
+
|
44
46
|
ruleset = AppSec::Processor::RuleMerger.merge(
|
45
47
|
rules: [rules],
|
46
48
|
data: data,
|
49
|
+
exclusions: exclusions,
|
47
50
|
)
|
48
51
|
|
49
52
|
processor = Processor.new(ruleset: ruleset)
|
@@ -54,6 +54,10 @@ module Datadog
|
|
54
54
|
o.default :recommended
|
55
55
|
end
|
56
56
|
|
57
|
+
option :ip_passlist do |o|
|
58
|
+
o.default []
|
59
|
+
end
|
60
|
+
|
57
61
|
option :ip_denylist do |o|
|
58
62
|
o.type :array
|
59
63
|
o.default []
|
@@ -188,12 +192,6 @@ module Datadog
|
|
188
192
|
end
|
189
193
|
end
|
190
194
|
end
|
191
|
-
|
192
|
-
option :parse_response_body do |o|
|
193
|
-
o.type :bool
|
194
|
-
o.env 'DD_API_SECURITY_PARSE_RESPONSE_BODY'
|
195
|
-
o.default true
|
196
|
-
end
|
197
195
|
end
|
198
196
|
end
|
199
197
|
end
|
@@ -19,55 +19,9 @@ module Datadog
|
|
19
19
|
@scope = scope
|
20
20
|
end
|
21
21
|
|
22
|
-
def parsed_body
|
23
|
-
return unless Datadog.configuration.appsec.parse_response_body
|
24
|
-
|
25
|
-
unless body.instance_of?(Array)
|
26
|
-
Datadog.logger.debug do
|
27
|
-
"Response body type unsupported: #{body.class}"
|
28
|
-
end
|
29
|
-
return
|
30
|
-
end
|
31
|
-
|
32
|
-
return unless json_content_type?
|
33
|
-
|
34
|
-
result = ''.dup
|
35
|
-
all_body_parts_are_string = true
|
36
|
-
|
37
|
-
body.each do |body_part|
|
38
|
-
if body_part.is_a?(String)
|
39
|
-
result.concat(body_part)
|
40
|
-
else
|
41
|
-
all_body_parts_are_string = false
|
42
|
-
break
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
return unless all_body_parts_are_string
|
47
|
-
|
48
|
-
begin
|
49
|
-
JSON.parse(result)
|
50
|
-
rescue JSON::ParserError => e
|
51
|
-
Datadog.logger.debug { "Failed to parse response body. Error #{e.class}. Message #{e.message}" }
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
22
|
def response
|
57
23
|
@response ||= ::Rack::Response.new(body, status, headers)
|
58
24
|
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
VALID_JSON_TYPES = [
|
63
|
-
'application/json',
|
64
|
-
'text/json'
|
65
|
-
].freeze
|
66
|
-
|
67
|
-
def json_content_type?
|
68
|
-
content_type = headers['content-type']
|
69
|
-
VALID_JSON_TYPES.include?(content_type)
|
70
|
-
end
|
71
25
|
end
|
72
26
|
end
|
73
27
|
end
|
@@ -10,7 +10,6 @@ module Datadog
|
|
10
10
|
ADDRESSES = [
|
11
11
|
'response.status',
|
12
12
|
'response.headers',
|
13
|
-
'response.body',
|
14
13
|
].freeze
|
15
14
|
private_constant :ADDRESSES
|
16
15
|
|
@@ -18,7 +17,6 @@ module Datadog
|
|
18
17
|
catch(:block) do
|
19
18
|
op.publish('response.status', gateway_response.status)
|
20
19
|
op.publish('response.headers', gateway_response.headers)
|
21
|
-
op.publish('response.body', gateway_response.parsed_body)
|
22
20
|
|
23
21
|
nil
|
24
22
|
end
|
@@ -31,7 +29,6 @@ module Datadog
|
|
31
29
|
response_status = values[0]
|
32
30
|
response_headers = values[1]
|
33
31
|
response_headers_no_cookies = response_headers.dup.tap { |h| h.delete('set-cookie') }
|
34
|
-
response_body = values[2]
|
35
32
|
|
36
33
|
waf_args = {
|
37
34
|
'server.response.status' => response_status.to_s,
|
@@ -39,8 +36,6 @@ module Datadog
|
|
39
36
|
'server.response.headers.no_cookies' => response_headers_no_cookies,
|
40
37
|
}
|
41
38
|
|
42
|
-
waf_args['server.response.body'] = response_body if response_body
|
43
|
-
|
44
39
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
45
40
|
result = waf_context.run(waf_args, waf_timeout)
|
46
41
|
|
@@ -66,16 +66,6 @@ module Datadog
|
|
66
66
|
request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
|
67
67
|
end
|
68
68
|
|
69
|
-
if request_return[2].respond_to?(:to_ary)
|
70
|
-
# Following the Rack specification. The response body should only call :each once.
|
71
|
-
# Calling :to_ary returns an array with identical content as the produced when calling :each
|
72
|
-
# replacing request_return[2] with that new value allow us to safely operate on the response body.
|
73
|
-
# On Gateway::Response#parsed_body we might iterate over the reposne body using :each
|
74
|
-
# https://github.com/rack/rack/blob/main/SPEC.rdoc#enumerable-body-
|
75
|
-
consumed_body = request_return[2].to_ary
|
76
|
-
request_return[2] = consumed_body if consumed_body
|
77
|
-
end
|
78
|
-
|
79
69
|
gateway_response = Gateway::Response.new(
|
80
70
|
request_return[2],
|
81
71
|
request_return[0],
|