datadog 2.14.0 → 2.15.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 +24 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +7 -6
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +3 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +69 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.h +7 -0
- data/ext/datadog_profiling_native_extension/http_transport.c +25 -32
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +22 -21
- data/ext/libdatadog_api/datadog_ruby_common.h +3 -0
- data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
- data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +0 -1344
- data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
- data/lib/datadog/appsec/assets/waf_rules/strict.json +0 -1344
- data/lib/datadog/appsec/component.rb +19 -17
- data/lib/datadog/appsec/compressed_json.rb +40 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/event.rb +21 -50
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +5 -5
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/transport/http/diagnostics.rb +0 -1
- data/lib/datadog/di/transport/http/input.rb +0 -1
- data/lib/datadog/di/transport/http.rb +0 -6
- data/lib/datadog/profiling/collectors/info.rb +3 -0
- data/lib/datadog/profiling/encoded_profile.rb +11 -0
- data/lib/datadog/profiling/exporter.rb +2 -3
- data/lib/datadog/profiling/ext.rb +0 -1
- data/lib/datadog/profiling/flush.rb +4 -7
- data/lib/datadog/profiling/http_transport.rb +10 -59
- data/lib/datadog/profiling/stack_recorder.rb +4 -4
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d17c177691be6204c922253f717344b69cbf2ccf0e6cc51b5d2063e484ffcf9
|
4
|
+
data.tar.gz: fb55233c5db1aa2d80562d7d2a0f7297f4d13b0b1f1c8a3f3a6feec8f15bb947
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef69c8e13819833ce2b1a0987ec66a674a15ca029bd4ad0a29703a613c7dd263015ca0018433ac366f69e655fa264a74aa949a1d6b12e30753b249fa8b7d62c2
|
7
|
+
data.tar.gz: 1d44dca02ab71b49b87e371825bbdda696fbd686bc9d24662d5d90c5091c4ddf82226abda23c56da9da8e8274ab06759a90b73fd3eb44cecc081598fd8cc188a
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [2.15.0] - 2025-04-17
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
* AppSec: Add auto-patching for `activerecord` with sql injection detection ([#4581][])
|
10
|
+
* Tracing: Add option for `opensearch` to set resource with relative path ([#4509][])
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
* AppSec: Update In-App WAF rules, processors, and scanners ([#4568][])
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
* AppSec: Fix blocked requests not marked correctly when using custom redirect blocking action ([#4580][])
|
19
|
+
* AppSec: Fix UTF-8 unsafe payloads in InApp-WAF causing runtime exceptions ([#4573][])
|
20
|
+
|
5
21
|
## [2.14.0] - 2025-04-04
|
6
22
|
|
7
23
|
### Added
|
@@ -3178,7 +3194,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
3178
3194
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
3179
3195
|
|
3180
3196
|
|
3181
|
-
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.
|
3197
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.15.0...master
|
3198
|
+
[2.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.14.0...v2.15.0
|
3182
3199
|
[2.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.13.0...v2.14.0
|
3183
3200
|
[2.13.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.2...v2.13.0
|
3184
3201
|
[2.12.2]: https://github.com/DataDog/dd-trace-rb/compare/v2.12.1...v2.12.2
|
@@ -4693,6 +4710,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
4693
4710
|
[#4498]: https://github.com/DataDog/dd-trace-rb/issues/4498
|
4694
4711
|
[#4505]: https://github.com/DataDog/dd-trace-rb/issues/4505
|
4695
4712
|
[#4507]: https://github.com/DataDog/dd-trace-rb/issues/4507
|
4713
|
+
[#4509]: https://github.com/DataDog/dd-trace-rb/issues/4509
|
4696
4714
|
[#4526]: https://github.com/DataDog/dd-trace-rb/issues/4526
|
4697
4715
|
[#4528]: https://github.com/DataDog/dd-trace-rb/issues/4528
|
4698
4716
|
[#4530]: https://github.com/DataDog/dd-trace-rb/issues/4530
|
@@ -4701,6 +4719,10 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
4701
4719
|
[#4549]: https://github.com/DataDog/dd-trace-rb/issues/4549
|
4702
4720
|
[#4552]: https://github.com/DataDog/dd-trace-rb/issues/4552
|
4703
4721
|
[#4558]: https://github.com/DataDog/dd-trace-rb/issues/4558
|
4722
|
+
[#4568]: https://github.com/DataDog/dd-trace-rb/issues/4568
|
4723
|
+
[#4573]: https://github.com/DataDog/dd-trace-rb/issues/4573
|
4724
|
+
[#4580]: https://github.com/DataDog/dd-trace-rb/issues/4580
|
4725
|
+
[#4581]: https://github.com/DataDog/dd-trace-rb/issues/4581
|
4704
4726
|
[@AdrianLC]: https://github.com/AdrianLC
|
4705
4727
|
[@Azure7111]: https://github.com/Azure7111
|
4706
4728
|
[@BabyGroot]: https://github.com/BabyGroot
|
@@ -4852,4 +4874,4 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
4852
4874
|
[@y-yagi]: https://github.com/y-yagi
|
4853
4875
|
[@yujideveloper]: https://github.com/yujideveloper
|
4854
4876
|
[@yukimurasawa]: https://github.com/yukimurasawa
|
4855
|
-
[@zachmccormick]: https://github.com/zachmccormick
|
4877
|
+
[@zachmccormick]: https://github.com/zachmccormick
|
@@ -297,7 +297,7 @@ static void otel_without_ddtrace_trace_identifiers_for(
|
|
297
297
|
static otel_span otel_span_from(VALUE otel_context, VALUE otel_current_span_key);
|
298
298
|
static uint64_t otel_span_id_to_uint(VALUE otel_span_id);
|
299
299
|
static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE key);
|
300
|
-
static VALUE
|
300
|
+
static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance);
|
301
301
|
|
302
302
|
void collectors_thread_context_init(VALUE profiling_module) {
|
303
303
|
VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
|
@@ -329,7 +329,7 @@ void collectors_thread_context_init(VALUE profiling_module) {
|
|
329
329
|
rb_define_singleton_method(testing_module, "_native_gc_tracking", _native_gc_tracking, 1);
|
330
330
|
rb_define_singleton_method(testing_module, "_native_new_empty_thread", _native_new_empty_thread, 0);
|
331
331
|
rb_define_singleton_method(testing_module, "_native_sample_skipped_allocation_samples", _native_sample_skipped_allocation_samples, 2);
|
332
|
-
rb_define_singleton_method(testing_module, "
|
332
|
+
rb_define_singleton_method(testing_module, "_native_system_epoch_time_now_ns", _native_system_epoch_time_now_ns, 1);
|
333
333
|
#ifndef NO_GVL_INSTRUMENTATION
|
334
334
|
rb_define_singleton_method(testing_module, "_native_on_gvl_waiting", _native_on_gvl_waiting, 1);
|
335
335
|
rb_define_singleton_method(testing_module, "_native_gvl_waiting_at_for", _native_gvl_waiting_at_for, 1);
|
@@ -1308,7 +1308,7 @@ static long thread_id_for(VALUE thread) {
|
|
1308
1308
|
}
|
1309
1309
|
|
1310
1310
|
VALUE enforce_thread_context_collector_instance(VALUE object) {
|
1311
|
-
|
1311
|
+
ENFORCE_TYPED_DATA(object, &thread_context_collector_typed_data);
|
1312
1312
|
return object;
|
1313
1313
|
}
|
1314
1314
|
|
@@ -2160,11 +2160,12 @@ static VALUE safely_lookup_hash_without_going_into_ruby_code(VALUE hash, VALUE k
|
|
2160
2160
|
return state.result;
|
2161
2161
|
}
|
2162
2162
|
|
2163
|
-
static VALUE
|
2163
|
+
static VALUE _native_system_epoch_time_now_ns(DDTRACE_UNUSED VALUE self, VALUE collector_instance) {
|
2164
2164
|
thread_context_collector_state *state;
|
2165
2165
|
TypedData_Get_Struct(collector_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
|
2166
2166
|
|
2167
|
-
|
2167
|
+
long current_monotonic_wall_time_ns = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
|
2168
|
+
long system_epoch_time_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns);
|
2168
2169
|
|
2169
|
-
return
|
2170
|
+
return LONG2NUM(system_epoch_time_ns);
|
2170
2171
|
}
|
@@ -27,6 +27,9 @@
|
|
27
27
|
#define ENFORCE_BOOLEAN(value) \
|
28
28
|
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
|
29
29
|
|
30
|
+
#define ENFORCE_TYPED_DATA(value, type) \
|
31
|
+
{ if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), "TypedData of type " ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
|
32
|
+
|
30
33
|
NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
|
31
34
|
|
32
35
|
// Helper to retrieve Datadog::VERSION::STRING
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#include "encoded_profile.h"
|
2
|
+
#include "datadog_ruby_common.h"
|
3
|
+
#include "libdatadog_helpers.h"
|
4
|
+
|
5
|
+
// This class exists to wrap a ddog_prof_EncodedProfile into a Ruby object
|
6
|
+
// This file implements the native bits of the Datadog::Profiling::EncodedProfile class
|
7
|
+
|
8
|
+
static void encoded_profile_typed_data_free(void *state_ptr);
|
9
|
+
static VALUE _native_bytes(VALUE self);
|
10
|
+
|
11
|
+
static VALUE encoded_profile_class = Qnil;
|
12
|
+
|
13
|
+
void encoded_profile_init(VALUE profiling_module) {
|
14
|
+
encoded_profile_class = rb_define_class_under(profiling_module, "EncodedProfile", rb_cObject);
|
15
|
+
|
16
|
+
rb_undef_alloc_func(encoded_profile_class); // Class cannot be created from Ruby code
|
17
|
+
rb_global_variable(&encoded_profile_class);
|
18
|
+
|
19
|
+
rb_define_method(encoded_profile_class, "_native_bytes", _native_bytes, 0);
|
20
|
+
}
|
21
|
+
|
22
|
+
// This structure is used to define a Ruby object that stores a `ddog_prof_EncodedProfile`
|
23
|
+
// See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
|
24
|
+
static const rb_data_type_t encoded_profile_typed_data = {
|
25
|
+
.wrap_struct_name = "Datadog::Profiling::EncodedProfile",
|
26
|
+
.function = {
|
27
|
+
.dmark = NULL, // We don't store references to Ruby objects so we don't need to mark any of them
|
28
|
+
.dfree = encoded_profile_typed_data_free,
|
29
|
+
.dsize = NULL, // We don't track memory usage (although it'd be cool if we did!)
|
30
|
+
//.dcompact = NULL, // Not needed -- we don't store references to Ruby objects
|
31
|
+
},
|
32
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
33
|
+
};
|
34
|
+
|
35
|
+
VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile) {
|
36
|
+
ddog_prof_EncodedProfile *state = ruby_xcalloc(1, sizeof(ddog_prof_EncodedProfile));
|
37
|
+
*state = profile;
|
38
|
+
return TypedData_Wrap_Struct(encoded_profile_class, &encoded_profile_typed_data, state);
|
39
|
+
}
|
40
|
+
|
41
|
+
static void encoded_profile_typed_data_free(void *state_ptr) {
|
42
|
+
ddog_prof_EncodedProfile *state = (ddog_prof_EncodedProfile *) state_ptr;
|
43
|
+
|
44
|
+
// This drops the profile itself
|
45
|
+
ddog_prof_EncodedProfile_drop(state);
|
46
|
+
|
47
|
+
// This drops the tiny bit of memory we allocated to contain the ` ddog_prof_EncodedProfile` struct
|
48
|
+
ruby_xfree(state);
|
49
|
+
}
|
50
|
+
|
51
|
+
static VALUE _native_bytes(VALUE self) {
|
52
|
+
ddog_prof_EncodedProfile *state;
|
53
|
+
TypedData_Get_Struct(self, ddog_prof_EncodedProfile, &encoded_profile_typed_data, state);
|
54
|
+
|
55
|
+
return ruby_string_from_vec_u8(state->buffer);
|
56
|
+
|
57
|
+
// TODO: This will be used for libdatadog 17
|
58
|
+
/*ddog_prof_Result_ByteSlice raw_bytes = ddog_prof_EncodedProfile_bytes(state);
|
59
|
+
if (raw_bytes.tag == DDOG_PROF_RESULT_BYTE_SLICE_ERR_BYTE_SLICE) {
|
60
|
+
rb_raise(rb_eRuntimeError, "Failed to get bytes from profile: %"PRIsVALUE, get_error_details_and_drop(&raw_bytes.err));
|
61
|
+
}
|
62
|
+
|
63
|
+
return rb_str_new((const char *) raw_bytes.ok.ptr, raw_bytes.ok.len);*/
|
64
|
+
}
|
65
|
+
|
66
|
+
VALUE enforce_encoded_profile_instance(VALUE object) {
|
67
|
+
ENFORCE_TYPED_DATA(object, &encoded_profile_typed_data);
|
68
|
+
return object;
|
69
|
+
}
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#include "helpers.h"
|
5
5
|
#include "libdatadog_helpers.h"
|
6
6
|
#include "ruby_helpers.h"
|
7
|
+
#include "encoded_profile.h"
|
7
8
|
|
8
9
|
// Used to report profiling data to Datadog.
|
9
10
|
// This file implements the native bits of the Datadog::Profiling::HttpTransport class
|
@@ -29,17 +30,11 @@ static VALUE _native_do_export(
|
|
29
30
|
VALUE self,
|
30
31
|
VALUE exporter_configuration,
|
31
32
|
VALUE upload_timeout_milliseconds,
|
33
|
+
VALUE flush,
|
32
34
|
VALUE start_timespec_seconds,
|
33
35
|
VALUE start_timespec_nanoseconds,
|
34
36
|
VALUE finish_timespec_seconds,
|
35
|
-
VALUE finish_timespec_nanoseconds
|
36
|
-
VALUE pprof_file_name,
|
37
|
-
VALUE pprof_data,
|
38
|
-
VALUE code_provenance_file_name,
|
39
|
-
VALUE code_provenance_data,
|
40
|
-
VALUE tags_as_array,
|
41
|
-
VALUE internal_metadata_json,
|
42
|
-
VALUE info_json
|
37
|
+
VALUE finish_timespec_nanoseconds
|
43
38
|
);
|
44
39
|
static void *call_exporter_without_gvl(void *call_args);
|
45
40
|
static void interrupt_exporter_call(void *cancel_token);
|
@@ -48,7 +43,7 @@ void http_transport_init(VALUE profiling_module) {
|
|
48
43
|
VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
|
49
44
|
|
50
45
|
rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
|
51
|
-
rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export,
|
46
|
+
rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 7);
|
52
47
|
|
53
48
|
ok_symbol = ID2SYM(rb_intern_const("ok"));
|
54
49
|
error_symbol = ID2SYM(rb_intern_const("error"));
|
@@ -84,22 +79,17 @@ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
|
|
84
79
|
ENFORCE_TYPE(exporter_working_mode, T_SYMBOL);
|
85
80
|
ID working_mode = SYM2ID(exporter_working_mode);
|
86
81
|
|
87
|
-
|
88
|
-
ID agent_id = rb_intern("agent");
|
89
|
-
|
90
|
-
if (working_mode != agentless_id && working_mode != agent_id) {
|
91
|
-
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
|
92
|
-
}
|
93
|
-
|
94
|
-
if (working_mode == agentless_id) {
|
82
|
+
if (working_mode == rb_intern("agentless")) {
|
95
83
|
VALUE site = rb_ary_entry(exporter_configuration, 1);
|
96
84
|
VALUE api_key = rb_ary_entry(exporter_configuration, 2);
|
97
85
|
|
98
86
|
return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
|
99
|
-
} else
|
87
|
+
} else if (working_mode == rb_intern("agent")) {
|
100
88
|
VALUE base_url = rb_ary_entry(exporter_configuration, 1);
|
101
89
|
|
102
90
|
return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
|
91
|
+
} else {
|
92
|
+
rb_raise(rb_eArgError, "Failed to initialize transport: Unexpected working mode, expected :agentless or :agent");
|
103
93
|
}
|
104
94
|
}
|
105
95
|
|
@@ -139,7 +129,6 @@ static VALUE perform_export(
|
|
139
129
|
ddog_Timespec finish,
|
140
130
|
ddog_prof_Exporter_Slice_File files_to_compress_and_export,
|
141
131
|
ddog_prof_Exporter_Slice_File files_to_export_unmodified,
|
142
|
-
ddog_Vec_Tag *additional_tags,
|
143
132
|
ddog_CharSlice internal_metadata,
|
144
133
|
ddog_CharSlice info
|
145
134
|
) {
|
@@ -150,7 +139,7 @@ static VALUE perform_export(
|
|
150
139
|
finish,
|
151
140
|
files_to_compress_and_export,
|
152
141
|
files_to_export_unmodified,
|
153
|
-
|
142
|
+
/* optional_additional_tags: */ NULL,
|
154
143
|
endpoints_stats,
|
155
144
|
&internal_metadata,
|
156
145
|
&info
|
@@ -214,26 +203,27 @@ static VALUE _native_do_export(
|
|
214
203
|
DDTRACE_UNUSED VALUE _self,
|
215
204
|
VALUE exporter_configuration,
|
216
205
|
VALUE upload_timeout_milliseconds,
|
206
|
+
VALUE flush,
|
217
207
|
VALUE start_timespec_seconds,
|
218
208
|
VALUE start_timespec_nanoseconds,
|
219
209
|
VALUE finish_timespec_seconds,
|
220
|
-
VALUE finish_timespec_nanoseconds
|
221
|
-
VALUE pprof_file_name,
|
222
|
-
VALUE pprof_data,
|
223
|
-
VALUE code_provenance_file_name,
|
224
|
-
VALUE code_provenance_data,
|
225
|
-
VALUE tags_as_array,
|
226
|
-
VALUE internal_metadata_json,
|
227
|
-
VALUE info_json
|
210
|
+
VALUE finish_timespec_nanoseconds
|
228
211
|
) {
|
212
|
+
VALUE encoded_profile = rb_funcall(flush, rb_intern("encoded_profile"), 0);
|
213
|
+
VALUE code_provenance_file_name = rb_funcall(flush, rb_intern("code_provenance_file_name"), 0);
|
214
|
+
VALUE code_provenance_data = rb_funcall(flush, rb_intern("code_provenance_data"), 0);
|
215
|
+
VALUE tags_as_array = rb_funcall(flush, rb_intern("tags_as_array"), 0);
|
216
|
+
VALUE internal_metadata_json = rb_funcall(flush, rb_intern("internal_metadata_json"), 0);
|
217
|
+
VALUE info_json = rb_funcall(flush, rb_intern("info_json"), 0);
|
218
|
+
|
229
219
|
ENFORCE_TYPE(upload_timeout_milliseconds, T_FIXNUM);
|
230
220
|
ENFORCE_TYPE(start_timespec_seconds, T_FIXNUM);
|
231
221
|
ENFORCE_TYPE(start_timespec_nanoseconds, T_FIXNUM);
|
232
222
|
ENFORCE_TYPE(finish_timespec_seconds, T_FIXNUM);
|
233
223
|
ENFORCE_TYPE(finish_timespec_nanoseconds, T_FIXNUM);
|
234
|
-
|
235
|
-
ENFORCE_TYPE(pprof_data, T_STRING);
|
224
|
+
enforce_encoded_profile_instance(encoded_profile);
|
236
225
|
ENFORCE_TYPE(code_provenance_file_name, T_STRING);
|
226
|
+
ENFORCE_TYPE(tags_as_array, T_ARRAY);
|
237
227
|
ENFORCE_TYPE(internal_metadata_json, T_STRING);
|
238
228
|
ENFORCE_TYPE(info_json, T_STRING);
|
239
229
|
|
@@ -256,6 +246,11 @@ static VALUE _native_do_export(
|
|
256
246
|
ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
|
257
247
|
ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
|
258
248
|
|
249
|
+
// TODO: Hardcoding the file name will go away with libdatadog 17
|
250
|
+
VALUE pprof_file_name = rb_str_new_cstr("rubyprofile.pprof");
|
251
|
+
VALUE pprof_data = rb_funcall(encoded_profile, rb_intern("_native_bytes"), 0);
|
252
|
+
ENFORCE_TYPE(pprof_data, T_STRING);
|
253
|
+
|
259
254
|
already_compressed[0] = (ddog_prof_Exporter_File) {
|
260
255
|
.name = char_slice_from_ruby_string(pprof_file_name),
|
261
256
|
.file = byte_slice_from_ruby_string(pprof_data),
|
@@ -268,7 +263,6 @@ static VALUE _native_do_export(
|
|
268
263
|
};
|
269
264
|
}
|
270
265
|
|
271
|
-
ddog_Vec_Tag *null_additional_tags = NULL;
|
272
266
|
ddog_CharSlice internal_metadata = char_slice_from_ruby_string(internal_metadata_json);
|
273
267
|
ddog_CharSlice info = char_slice_from_ruby_string(info_json);
|
274
268
|
|
@@ -293,7 +287,6 @@ static VALUE _native_do_export(
|
|
293
287
|
finish,
|
294
288
|
files_to_compress_and_export,
|
295
289
|
files_to_export_unmodified,
|
296
|
-
null_additional_tags,
|
297
290
|
internal_metadata,
|
298
291
|
info
|
299
292
|
);
|
@@ -20,6 +20,7 @@ void collectors_dynamic_sampling_rate_init(VALUE profiling_module);
|
|
20
20
|
void collectors_idle_sampling_helper_init(VALUE profiling_module);
|
21
21
|
void collectors_stack_init(VALUE profiling_module);
|
22
22
|
void collectors_thread_context_init(VALUE profiling_module);
|
23
|
+
void encoded_profile_init(VALUE profiling_module);
|
23
24
|
void http_transport_init(VALUE profiling_module);
|
24
25
|
void stack_recorder_init(VALUE profiling_module);
|
25
26
|
|
@@ -61,6 +62,7 @@ void DDTRACE_EXPORT Init_datadog_profiling_native_extension(void) {
|
|
61
62
|
collectors_idle_sampling_helper_init(profiling_module);
|
62
63
|
collectors_stack_init(profiling_module);
|
63
64
|
collectors_thread_context_init(profiling_module);
|
65
|
+
encoded_profile_init(profiling_module);
|
64
66
|
http_transport_init(profiling_module);
|
65
67
|
stack_recorder_init(profiling_module);
|
66
68
|
unsafe_api_calls_check_init();
|
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "ruby_helpers.h"
|
9
9
|
#include "time_helpers.h"
|
10
10
|
#include "heap_recorder.h"
|
11
|
+
#include "encoded_profile.h"
|
11
12
|
|
12
13
|
// Used to wrap a ddog_prof_Profile in a Ruby object and expose Ruby-level serialization APIs
|
13
14
|
// This file implements the native bits of the Datadog::Profiling::StackRecorder class
|
@@ -181,6 +182,7 @@ typedef struct {
|
|
181
182
|
typedef struct {
|
182
183
|
ddog_prof_Profile profile;
|
183
184
|
stats_slot stats;
|
185
|
+
ddog_Timespec start_timestamp;
|
184
186
|
} profile_slot;
|
185
187
|
|
186
188
|
// Contains native state for each instance
|
@@ -252,7 +254,7 @@ static ddog_Timespec system_epoch_now_timespec(void);
|
|
252
254
|
static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
|
253
255
|
static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time);
|
254
256
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
|
255
|
-
static void reset_profile_slot(profile_slot *slot, ddog_Timespec
|
257
|
+
static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
|
256
258
|
static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
|
257
259
|
static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
|
258
260
|
static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
|
@@ -358,24 +360,26 @@ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
|
|
358
360
|
}
|
359
361
|
|
360
362
|
static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
|
363
|
+
ddog_Timespec start_timestamp = system_epoch_now_timespec();
|
364
|
+
|
361
365
|
ddog_prof_Profile_NewResult slot_one_profile_result =
|
362
|
-
ddog_prof_Profile_new(sample_types, NULL /* period is optional */,
|
366
|
+
ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
|
363
367
|
|
364
368
|
if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
365
369
|
rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
|
366
370
|
}
|
367
371
|
|
368
|
-
state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok };
|
372
|
+
state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
|
369
373
|
|
370
374
|
ddog_prof_Profile_NewResult slot_two_profile_result =
|
371
|
-
ddog_prof_Profile_new(sample_types, NULL /* period is optional */,
|
375
|
+
ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
|
372
376
|
|
373
377
|
if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
|
374
378
|
// Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
|
375
379
|
rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
|
376
380
|
}
|
377
381
|
|
378
|
-
state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok };
|
382
|
+
state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
|
379
383
|
}
|
380
384
|
|
381
385
|
static void stack_recorder_typed_data_free(void *state_ptr) {
|
@@ -564,18 +568,14 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
|
|
564
568
|
|
565
569
|
state->stats_lifetime.serialization_successes++;
|
566
570
|
|
567
|
-
|
568
|
-
|
569
|
-
ddog_Timespec ddprof_start = serialized_profile.ok.start;
|
570
|
-
ddog_Timespec ddprof_finish = serialized_profile.ok.end;
|
571
|
+
// Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it
|
572
|
+
VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
|
571
573
|
|
572
|
-
|
573
|
-
|
574
|
-
VALUE start = ruby_time_from(ddprof_start);
|
575
|
-
VALUE finish = ruby_time_from(ddprof_finish);
|
574
|
+
VALUE start = ruby_time_from(args.slot->start_timestamp);
|
575
|
+
VALUE finish = ruby_time_from(finish_timestamp);
|
576
576
|
VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
|
577
577
|
|
578
|
-
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish,
|
578
|
+
return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
|
579
579
|
}
|
580
580
|
|
581
581
|
static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
|
@@ -780,7 +780,7 @@ static void *call_serialize_without_gvl(void *call_args) {
|
|
780
780
|
}
|
781
781
|
|
782
782
|
VALUE enforce_recorder_instance(VALUE object) {
|
783
|
-
|
783
|
+
ENFORCE_TYPED_DATA(object, &stack_recorder_typed_data);
|
784
784
|
return object;
|
785
785
|
}
|
786
786
|
|
@@ -889,9 +889,9 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
|
|
889
889
|
// In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
|
890
890
|
// resulting state is inconsistent, we make sure to reset it back to the initial state.
|
891
891
|
initialize_slot_concurrency_control(state);
|
892
|
-
|
893
|
-
reset_profile_slot(&state->profile_slot_one,
|
894
|
-
reset_profile_slot(&state->profile_slot_two,
|
892
|
+
ddog_Timespec start_timestamp = system_epoch_now_timespec();
|
893
|
+
reset_profile_slot(&state->profile_slot_one, start_timestamp);
|
894
|
+
reset_profile_slot(&state->profile_slot_two, start_timestamp);
|
895
895
|
|
896
896
|
heap_recorder_after_fork(state->heap_recorder);
|
897
897
|
|
@@ -903,7 +903,7 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
|
|
903
903
|
static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) {
|
904
904
|
// Before making this profile active, we reset it so that it uses the correct start_time for its start
|
905
905
|
profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one;
|
906
|
-
reset_profile_slot(next_profile_slot,
|
906
|
+
reset_profile_slot(next_profile_slot, start_time);
|
907
907
|
}
|
908
908
|
|
909
909
|
static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
|
@@ -948,11 +948,12 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
|
|
948
948
|
return Qnil;
|
949
949
|
}
|
950
950
|
|
951
|
-
static void reset_profile_slot(profile_slot *slot, ddog_Timespec
|
952
|
-
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile,
|
951
|
+
static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
|
952
|
+
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile, &start_timestamp);
|
953
953
|
if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
|
954
954
|
rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
|
955
955
|
}
|
956
|
+
slot->start_timestamp = start_timestamp;
|
956
957
|
slot->stats = (stats_slot) {};
|
957
958
|
}
|
958
959
|
|
@@ -27,6 +27,9 @@
|
|
27
27
|
#define ENFORCE_BOOLEAN(value) \
|
28
28
|
{ if (RB_UNLIKELY(value != Qtrue && value != Qfalse)) raise_unexpected_type(value, ADD_QUOTES(value), "true or false", __FILE__, __LINE__, __func__); }
|
29
29
|
|
30
|
+
#define ENFORCE_TYPED_DATA(value, type) \
|
31
|
+
{ if (RB_UNLIKELY(!rb_typeddata_is_kind_of(value, type))) raise_unexpected_type(value, ADD_QUOTES(value), "TypedData of type " ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
|
32
|
+
|
30
33
|
NORETURN(void raise_unexpected_type(VALUE value, const char *value_name, const char *type_name, const char *file, int line, const char* function_name));
|
31
34
|
|
32
35
|
// Helper to retrieve Datadog::VERSION::STRING
|
@@ -1,7 +1,52 @@
|
|
1
|
-
|
1
|
+
AppSec WAF rules based on [appsec-event-rules](https://github.com/datadog/appsec-event-rules) builds
|
2
2
|
|
3
|
-
|
4
|
-
these rules.
|
3
|
+
## How to update
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
> [!WARNING]
|
6
|
+
> This process is a temporary workaround to maintain compatibility with the existing code structure and will be changed.
|
7
|
+
|
8
|
+
1. Download `recommended.json` and `strict.json` of the desired version from [appsec-event-rules](https://github.com/datadog/appsec-event-rules) (example: [v1.13.3](https://github.com/DataDog/appsec-event-rules/tree/1.13.3/build))
|
9
|
+
2. Run the script below inside `waf_rules` folder to extract scanners and processors into separate files
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'json'
|
13
|
+
|
14
|
+
recommended_rules = JSON.parse(File.read(File.expand_path('recommended.json', __dir__)))
|
15
|
+
strict_rules = JSON.parse(File.read(File.expand_path('strict.json', __dir__)))
|
16
|
+
|
17
|
+
recommended_processors = recommended_rules.delete('processors')
|
18
|
+
strict_processors = strict_rules.delete('processors')
|
19
|
+
|
20
|
+
if recommended_processors.sort_by { |processor| processor['id'] } !=
|
21
|
+
strict_processors.sort_by { |processor| processor['id'] }
|
22
|
+
raise 'Processors are not the same, unable to extract them'
|
23
|
+
end
|
24
|
+
|
25
|
+
puts 'Extracting processors...'
|
26
|
+
File.open(File.expand_path('processors.json', __dir__), 'wb') do |file|
|
27
|
+
file.write(JSON.pretty_generate(recommended_processors))
|
28
|
+
end
|
29
|
+
|
30
|
+
recommended_scanners = recommended_rules.delete('scanners')
|
31
|
+
strict_scanners = strict_rules.delete('scanners')
|
32
|
+
|
33
|
+
if recommended_scanners.sort_by { |processor| processor['id'] } !=
|
34
|
+
strict_scanners.sort_by { |processor| processor['id'] }
|
35
|
+
raise 'Scanners are not the same, unable to extract them'
|
36
|
+
end
|
37
|
+
|
38
|
+
puts 'Extracting scanners...'
|
39
|
+
File.open(File.expand_path('scanners.json', __dir__), 'wb') do |file|
|
40
|
+
file.write(JSON.pretty_generate(recommended_scanners))
|
41
|
+
end
|
42
|
+
|
43
|
+
puts 'Updating rules...'
|
44
|
+
|
45
|
+
File.open(File.expand_path('recommended.json', __dir__), 'wb') do |file|
|
46
|
+
file.write(JSON.pretty_generate(recommended_rules))
|
47
|
+
end
|
48
|
+
|
49
|
+
File.open(File.expand_path('strict.json', __dir__), 'wb') do |file|
|
50
|
+
file.write(JSON.pretty_generate(strict_rules))
|
51
|
+
end
|
52
|
+
```
|