ddtrace 1.17.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -2
- 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 -0
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
- data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
- data/lib/datadog/appsec/remote.rb +12 -9
- 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/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/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -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,28 @@
|
|
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
|
+
|
5
27
|
## [1.17.0] - 2023-11-22
|
6
28
|
|
7
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:
|
@@ -23,7 +45,7 @@ For CI Visibility, you can now manually create CI traces and spans with the [new
|
|
23
45
|
### Changed
|
24
46
|
|
25
47
|
* Tracing: Set 128-bit trace_id to true by default ([#3266][])
|
26
|
-
* Tracing: Default trace propagation styles to `Datadog,b3multi,b3,tracecontext` ([#3248][]
|
48
|
+
* Tracing: Default trace propagation styles to `Datadog,b3multi,b3,tracecontext` ([#3248][],[#3267][])
|
27
49
|
* Ci-App: Upgraded `datadog-ci` dependency to 0.4 ([#3270][])
|
28
50
|
|
29
51
|
## [1.16.2] - 2023-11-10
|
@@ -2658,7 +2680,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2658
2680
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2659
2681
|
|
2660
2682
|
|
2661
|
-
[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
|
2662
2685
|
[1.17.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.2...v1.17.0
|
2663
2686
|
[1.16.2]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.1...v1.16.2
|
2664
2687
|
[1.16.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...v1.16.1
|
@@ -3870,6 +3893,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3870
3893
|
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3871
3894
|
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3872
3895
|
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3896
|
+
[#3229]: https://github.com/DataDog/dd-trace-rb/issues/3229
|
3873
3897
|
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3874
3898
|
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3875
3899
|
[#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
|
@@ -3877,11 +3901,21 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3877
3901
|
[#3248]: https://github.com/DataDog/dd-trace-rb/issues/3248
|
3878
3902
|
[#3252]: https://github.com/DataDog/dd-trace-rb/issues/3252
|
3879
3903
|
[#3255]: https://github.com/DataDog/dd-trace-rb/issues/3255
|
3904
|
+
[#3259]: https://github.com/DataDog/dd-trace-rb/issues/3259
|
3880
3905
|
[#3262]: https://github.com/DataDog/dd-trace-rb/issues/3262
|
3881
3906
|
[#3266]: https://github.com/DataDog/dd-trace-rb/issues/3266
|
3882
3907
|
[#3267]: https://github.com/DataDog/dd-trace-rb/issues/3267
|
3883
3908
|
[#3270]: https://github.com/DataDog/dd-trace-rb/issues/3270
|
3909
|
+
[#3271]: https://github.com/DataDog/dd-trace-rb/issues/3271
|
3884
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
|
3885
3919
|
[@AdrianLC]: https://github.com/AdrianLC
|
3886
3920
|
[@Azure7111]: https://github.com/Azure7111
|
3887
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)
|
@@ -47,6 +47,13 @@ module Datadog
|
|
47
47
|
data
|
48
48
|
end
|
49
49
|
|
50
|
+
def load_exclusions(ip_passlist: [])
|
51
|
+
exclusions = []
|
52
|
+
exclusions << [passlist_exclusions(ip_passlist)] if ip_passlist.any?
|
53
|
+
|
54
|
+
exclusions
|
55
|
+
end
|
56
|
+
|
50
57
|
private
|
51
58
|
|
52
59
|
def denylist_data(id, denylist)
|
@@ -56,6 +63,59 @@ module Datadog
|
|
56
63
|
'data' => denylist.map { |v| { 'value' => v.to_s, 'expiration' => 2**63 } }
|
57
64
|
}
|
58
65
|
end
|
66
|
+
|
67
|
+
def passlist_exclusions(ip_passlist) # rubocop:disable Metrics/MethodLength
|
68
|
+
case ip_passlist
|
69
|
+
when Array
|
70
|
+
pass = ip_passlist
|
71
|
+
monitor = []
|
72
|
+
when Hash
|
73
|
+
pass = ip_passlist[:pass]
|
74
|
+
monitor = ip_passlist[:monitor]
|
75
|
+
else
|
76
|
+
pass = []
|
77
|
+
monitor = []
|
78
|
+
end
|
79
|
+
|
80
|
+
exclusions = []
|
81
|
+
|
82
|
+
exclusions << {
|
83
|
+
'conditions' => [
|
84
|
+
{
|
85
|
+
'operator' => 'ip_match',
|
86
|
+
'parameters' => {
|
87
|
+
'inputs' => [
|
88
|
+
{
|
89
|
+
'address' => 'http.client_ip'
|
90
|
+
}
|
91
|
+
],
|
92
|
+
'list' => pass
|
93
|
+
}
|
94
|
+
}
|
95
|
+
],
|
96
|
+
'id' => SecureRandom.uuid,
|
97
|
+
}
|
98
|
+
|
99
|
+
exclusions << {
|
100
|
+
'conditions' => [
|
101
|
+
{
|
102
|
+
'operator' => 'ip_match',
|
103
|
+
'parameters' => {
|
104
|
+
'inputs' => [
|
105
|
+
{
|
106
|
+
'address' => 'http.client_ip'
|
107
|
+
}
|
108
|
+
],
|
109
|
+
'list' => monitor
|
110
|
+
}
|
111
|
+
}
|
112
|
+
],
|
113
|
+
'id' => SecureRandom.uuid,
|
114
|
+
'on_match' => 'monitor'
|
115
|
+
}
|
116
|
+
|
117
|
+
exclusions
|
118
|
+
end
|
59
119
|
end
|
60
120
|
end
|
61
121
|
end
|
@@ -12,15 +12,17 @@ module Datadog
|
|
12
12
|
class NoRulesError < StandardError; end
|
13
13
|
|
14
14
|
class << self
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
CAP_ASM_RESERVED_1 = 1 << 0 # RESERVED
|
16
|
+
CAP_ASM_ACTIVATION = 1 << 1 # Remote activation via ASM_FEATURES product
|
17
|
+
CAP_ASM_IP_BLOCKING = 1 << 2 # accept IP blocking data from ASM_DATA product
|
18
|
+
CAP_ASM_DD_RULES = 1 << 3 # read ASM rules from ASM_DD product
|
19
|
+
CAP_ASM_EXCLUSIONS = 1 << 4 # exclusion filters (passlist) via ASM product
|
20
|
+
CAP_ASM_REQUEST_BLOCKING = 1 << 5 # can block on request info
|
21
|
+
CAP_ASM_RESPONSE_BLOCKING = 1 << 6 # can block on response info
|
22
|
+
CAP_ASM_USER_BLOCKING = 1 << 7 # accept user blocking data from ASM_DATA product
|
23
|
+
CAP_ASM_CUSTOM_RULES = 1 << 8 # accept custom rules
|
24
|
+
CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9 # supports custom http code or redirect sa blocking response
|
25
|
+
CAP_ASM_TRUSTED_IPS = 1 << 10 # supports trusted ip
|
24
26
|
|
25
27
|
# TODO: we need to dynamically add CAP_ASM_ACTIVATION once we support it
|
26
28
|
ASM_CAPABILITIES = [
|
@@ -32,6 +34,7 @@ module Datadog
|
|
32
34
|
CAP_ASM_DD_RULES,
|
33
35
|
CAP_ASM_CUSTOM_RULES,
|
34
36
|
CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
|
37
|
+
CAP_ASM_TRUSTED_IPS,
|
35
38
|
].freeze
|
36
39
|
|
37
40
|
ASM_PRODUCTS = [
|
@@ -273,6 +273,10 @@ module Datadog
|
|
273
273
|
def handle_interrupt_shutdown!
|
274
274
|
logger = Datadog.logger
|
275
275
|
shutdown_thread = Thread.new { shutdown! }
|
276
|
+
unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
|
277
|
+
shutdown_thread.name = Datadog::Core::Configuration.name
|
278
|
+
end
|
279
|
+
|
276
280
|
print_message_treshold_seconds = 0.2
|
277
281
|
|
278
282
|
slow_shutdown = shutdown_thread.join(print_message_treshold_seconds).nil?
|
@@ -16,11 +16,13 @@ module Datadog
|
|
16
16
|
'(Could not open /proc/sys/kernel/core_pattern)'
|
17
17
|
end
|
18
18
|
|
19
|
+
enabled_status = "Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'"
|
20
|
+
|
19
21
|
if maximum_size <= 0
|
20
22
|
Kernel.warn("[ddtrace] Could not enable core dumps on crash, maximum size is #{maximum_size} (disabled).")
|
21
23
|
return
|
22
24
|
elsif maximum_size == current_size
|
23
|
-
Kernel.warn(
|
25
|
+
Kernel.warn("[ddtrace] Core dumps already enabled, nothing to do. #{enabled_status}")
|
24
26
|
return
|
25
27
|
end
|
26
28
|
|
@@ -35,12 +37,9 @@ module Datadog
|
|
35
37
|
end
|
36
38
|
|
37
39
|
if current_size == 0
|
38
|
-
Kernel.warn("[ddtrace] Enabled core dumps.
|
40
|
+
Kernel.warn("[ddtrace] Enabled core dumps. #{enabled_status}")
|
39
41
|
else
|
40
|
-
Kernel.warn(
|
41
|
-
"[ddtrace] Raised core dump limit. Old size: #{current_size} " \
|
42
|
-
"Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'"
|
43
|
-
)
|
42
|
+
Kernel.warn("[ddtrace] Raised core dump limit. Old size: #{current_size} #{enabled_status}")
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -171,12 +171,11 @@ module Datadog
|
|
171
171
|
return true
|
172
172
|
end
|
173
173
|
|
174
|
-
if defined?(::PhusionPassenger)
|
174
|
+
if (defined?(::PhusionPassenger) || Gem.loaded_specs['passenger']) && incompatible_passenger_version?
|
175
175
|
Datadog.logger.warn(
|
176
|
-
'Enabling the profiling "no signals" workaround because the passenger
|
177
|
-
'
|
178
|
-
'
|
179
|
-
'Profiling data will have lower quality.'
|
176
|
+
'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
|
177
|
+
'installed. Profiling data will have lower quality.' \
|
178
|
+
'To fix this, upgrade the passenger gem to version 6.0.19 or above.'
|
180
179
|
)
|
181
180
|
return true
|
182
181
|
end
|
@@ -237,6 +236,15 @@ module Datadog
|
|
237
236
|
true
|
238
237
|
end
|
239
238
|
end
|
239
|
+
|
240
|
+
# See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
|
241
|
+
private_class_method def self.incompatible_passenger_version?
|
242
|
+
if Gem.loaded_specs['passenger']
|
243
|
+
Gem.loaded_specs['passenger'].version < Gem::Version.new('6.0.19')
|
244
|
+
else
|
245
|
+
true
|
246
|
+
end
|
247
|
+
end
|
240
248
|
end
|
241
249
|
end
|
242
250
|
end
|
@@ -25,6 +25,11 @@ module Datadog
|
|
25
25
|
o.default false
|
26
26
|
end
|
27
27
|
|
28
|
+
option :error_handler do |o|
|
29
|
+
o.type :proc
|
30
|
+
o.default_proc(&Tracing::SpanOperation::Events::DEFAULT_ON_ERROR)
|
31
|
+
end
|
32
|
+
|
28
33
|
option :analytics_sample_rate do |o|
|
29
34
|
o.type :float
|
30
35
|
o.env Ext::ENV_ANALYTICS_SAMPLE_RATE
|
@@ -21,18 +21,24 @@ module Datadog
|
|
21
21
|
# PG::Connection patch methods
|
22
22
|
module InstanceMethods
|
23
23
|
def exec(sql, *args, &block)
|
24
|
+
return super unless enabled?
|
25
|
+
|
24
26
|
trace(Ext::SPAN_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
25
27
|
super(sql_statement, *args, &wrapped_block)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def exec_params(sql, params, *args, &block)
|
32
|
+
return super unless enabled?
|
33
|
+
|
30
34
|
trace(Ext::SPAN_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
31
35
|
super(sql_statement, params, *args, &wrapped_block)
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def exec_prepared(statement_name, params, *args, &block)
|
40
|
+
return super unless enabled?
|
41
|
+
|
36
42
|
trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
37
43
|
super(statement_name, params, *args, &wrapped_block)
|
38
44
|
end
|
@@ -40,6 +46,8 @@ module Datadog
|
|
40
46
|
|
41
47
|
# async_exec is an alias to exec
|
42
48
|
def async_exec(sql, *args, &block)
|
49
|
+
return super unless enabled?
|
50
|
+
|
43
51
|
trace(Ext::SPAN_ASYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
44
52
|
super(sql_statement, *args, &wrapped_block)
|
45
53
|
end
|
@@ -47,6 +55,8 @@ module Datadog
|
|
47
55
|
|
48
56
|
# async_exec_params is an alias to exec_params
|
49
57
|
def async_exec_params(sql, params, *args, &block)
|
58
|
+
return super unless enabled?
|
59
|
+
|
50
60
|
trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
51
61
|
super(sql_statement, params, *args, &wrapped_block)
|
52
62
|
end
|
@@ -54,24 +64,32 @@ module Datadog
|
|
54
64
|
|
55
65
|
# async_exec_prepared is an alias to exec_prepared
|
56
66
|
def async_exec_prepared(statement_name, params, *args, &block)
|
67
|
+
return super unless enabled?
|
68
|
+
|
57
69
|
trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
58
70
|
super(statement_name, params, *args, &wrapped_block)
|
59
71
|
end
|
60
72
|
end
|
61
73
|
|
62
74
|
def sync_exec(sql, *args, &block)
|
75
|
+
return super unless enabled?
|
76
|
+
|
63
77
|
trace(Ext::SPAN_SYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
64
78
|
super(sql_statement, *args, &wrapped_block)
|
65
79
|
end
|
66
80
|
end
|
67
81
|
|
68
82
|
def sync_exec_params(sql, params, *args, &block)
|
83
|
+
return super unless enabled?
|
84
|
+
|
69
85
|
trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
70
86
|
super(sql_statement, params, *args, &wrapped_block)
|
71
87
|
end
|
72
88
|
end
|
73
89
|
|
74
90
|
def sync_exec_prepared(statement_name, params, *args, &block)
|
91
|
+
return super unless enabled?
|
92
|
+
|
75
93
|
trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
76
94
|
super(statement_name, params, *args, &wrapped_block)
|
77
95
|
end
|
@@ -81,10 +99,12 @@ module Datadog
|
|
81
99
|
|
82
100
|
def trace(name, sql: nil, statement_name: nil, block: nil)
|
83
101
|
service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
|
102
|
+
error_handler = datadog_configuration[:error_handler]
|
84
103
|
resource = statement_name || sql
|
85
104
|
|
86
105
|
Tracing.trace(
|
87
106
|
name,
|
107
|
+
on_error: error_handler,
|
88
108
|
service: service,
|
89
109
|
resource: resource,
|
90
110
|
type: Tracing::Metadata::Ext::SQL::TYPE
|
@@ -172,6 +192,10 @@ module Datadog
|
|
172
192
|
def comment_propagation
|
173
193
|
datadog_configuration[:comment_propagation]
|
174
194
|
end
|
195
|
+
|
196
|
+
def enabled?
|
197
|
+
datadog_configuration[:enabled]
|
198
|
+
end
|
175
199
|
end
|
176
200
|
end
|
177
201
|
end
|
@@ -69,6 +69,7 @@ module Datadog
|
|
69
69
|
Datadog.logger.debug { "Starting thread for: #{self}" }
|
70
70
|
@worker = Thread.new { perform }
|
71
71
|
@worker.name = self.class.name unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
|
72
|
+
@worker.thread_variable_set(:fork_safe, true)
|
72
73
|
|
73
74
|
nil
|
74
75
|
end
|
data/lib/ddtrace/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.2.
|
33
|
+
version: 3.2.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.2.
|
40
|
+
version: 3.2.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: libddwaf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.5.0
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.5.0
|
83
83
|
description: |
|
84
84
|
ddtrace is Datadog's tracing client for Ruby. It is used to trace requests
|
85
85
|
as they flow across web servers, databases and microservices so that developers
|
@@ -890,7 +890,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
890
890
|
- !ruby/object:Gem::Version
|
891
891
|
version: 2.0.0
|
892
892
|
requirements: []
|
893
|
-
rubygems_version: 3.4.
|
893
|
+
rubygems_version: 3.4.21
|
894
894
|
signing_key:
|
895
895
|
specification_version: 4
|
896
896
|
summary: Datadog tracing code for your Ruby applications
|