datadog 2.41.0 → 2.43.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -1
  3. data/README.md +3 -0
  4. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +120 -61
  6. data/ext/datadog_profiling_native_extension/collectors_stack.c +11 -3
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +156 -108
  8. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +7 -3
  9. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -10
  10. data/ext/datadog_profiling_native_extension/extconf.rb +52 -93
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +351 -255
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
  13. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -24
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +518 -442
  15. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +15 -3
  16. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -79
  18. data/ext/datadog_profiling_native_extension/ruby_helpers.h +0 -7
  19. data/ext/datadog_profiling_native_extension/stack_recorder.c +106 -61
  20. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -4
  21. data/ext/datadog_profiling_native_extension/time_helpers.h +2 -1
  22. data/ext/libdatadog_api/datadog_ruby_common.h +0 -10
  23. data/ext/libdatadog_api/di.c +10 -0
  24. data/ext/libdatadog_api/extconf.rb +3 -0
  25. data/ext/libdatadog_api/init.c +2 -0
  26. data/ext/libdatadog_api/otel_thread_context.c +247 -0
  27. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  28. data/ext/libdatadog_api/trace_exporter.c +642 -22
  29. data/ext/libdatadog_extconf_helpers.rb +1 -1
  30. data/lib/datadog/appsec/assets/blocked.html +1 -108
  31. data/lib/datadog/core/configuration/components.rb +1 -0
  32. data/lib/datadog/core/crashtracking/component.rb +5 -1
  33. data/lib/datadog/data_streams/pathway_context.rb +20 -22
  34. data/lib/datadog/data_streams/processor.rb +31 -0
  35. data/lib/datadog/di/instrumenter.rb +41 -1
  36. data/lib/datadog/di/logger.rb +2 -2
  37. data/lib/datadog/di/probe.rb +9 -1
  38. data/lib/datadog/di/probe_notification_builder.rb +1 -0
  39. data/lib/datadog/di/remote.rb +3 -3
  40. data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
  41. data/lib/datadog/open_feature/exposures/event.rb +10 -3
  42. data/lib/datadog/open_feature/ext.rb +19 -0
  43. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
  44. data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
  45. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
  46. data/lib/datadog/open_feature/native_evaluator.rb +33 -6
  47. data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
  48. data/lib/datadog/open_feature/provider.rb +11 -2
  49. data/lib/datadog/open_feature/transport.rb +5 -0
  50. data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
  51. data/lib/datadog/opentelemetry/trace.rb +3 -0
  52. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -0
  53. data/lib/datadog/profiling/collectors/info.rb +2 -6
  54. data/lib/datadog/profiling/collectors/thread_context.rb +0 -4
  55. data/lib/datadog/profiling/component.rb +8 -16
  56. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  57. data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
  58. data/lib/datadog/tracing/contrib/sequel/utils.rb +49 -62
  59. data/lib/datadog/tracing/distributed/baggage.rb +0 -1
  60. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  61. data/lib/datadog/tracing/distributed/propagation.rb +3 -0
  62. data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
  63. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  64. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  65. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  66. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  67. data/lib/datadog/tracing/otel_thread_context.rb +34 -0
  68. data/lib/datadog/tracing/remote.rb +195 -27
  69. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  70. data/lib/datadog/tracing/trace_digest.rb +22 -4
  71. data/lib/datadog/tracing/trace_operation.rb +22 -10
  72. data/lib/datadog/tracing/tracer.rb +5 -5
  73. data/lib/datadog/tracing/transport/native.rb +17 -25
  74. data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
  75. data/lib/datadog/tracing/transport/traces.rb +2 -22
  76. data/lib/datadog/version.rb +1 -1
  77. metadata +16 -8
  78. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
@@ -0,0 +1,247 @@
1
+ #include <ruby.h>
2
+ #include <ruby/thread.h>
3
+
4
+ #include "datadog_ruby_common.h"
5
+ #include "otel_thread_context.h"
6
+
7
+ #ifdef __linux__
8
+ #include <datadog/otel-thread-ctx.h>
9
+ extern __thread const uint8_t *otel_thread_ctx_v1;
10
+
11
+ static void otel_ctx_handle_free(void *handle) {
12
+ ddog_otel_thread_ctx_free((ddog_ThreadContextHandle *) handle);
13
+ }
14
+
15
+ static const rb_data_type_t otel_ctx_handle_t = {
16
+ .wrap_struct_name = "Datadog::Tracing::OTelThreadContext handle",
17
+ .function = {.dfree = otel_ctx_handle_free},
18
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
19
+ };
20
+ #endif
21
+
22
+ static ID fiber_context_slot;
23
+
24
+ DDTRACE_UNUSED static bool otel_context_enabled = false;
25
+
26
+ static VALUE native_set(VALUE _self, VALUE trace_id, VALUE span_id, VALUE local_root_span_id);
27
+ static VALUE native_clear(VALUE _self);
28
+ static VALUE native_supported_p(VALUE _self);
29
+ static VALUE native_enable(VALUE _self);
30
+ static VALUE native_read(VALUE _self);
31
+
32
+ void otel_thread_context_init(VALUE tracing_module) {
33
+ fiber_context_slot = rb_intern("__dd_otel_fiber_context");
34
+
35
+ VALUE otel_thread_context_module = rb_define_module_under(tracing_module, "OTelThreadContext");
36
+
37
+ rb_define_singleton_method(otel_thread_context_module, "_native_enable", native_enable, 0);
38
+ rb_define_singleton_method(otel_thread_context_module, "_native_set", native_set, 3);
39
+ rb_define_singleton_method(otel_thread_context_module, "_native_clear", native_clear, 0);
40
+ rb_define_singleton_method(otel_thread_context_module, "_native_supported?", native_supported_p, 0);
41
+
42
+ VALUE testing_module = rb_define_module_under(otel_thread_context_module, "Testing");
43
+ rb_define_singleton_method(testing_module, "_native_read", native_read, 0);
44
+ }
45
+
46
+ #ifdef __linux__
47
+ static ddog_ThreadContextHandle *get_fiber_handle_for(VALUE thread) {
48
+ VALUE obj = rb_thread_local_aref(thread, fiber_context_slot);
49
+
50
+ if (!rb_typeddata_is_kind_of(obj, &otel_ctx_handle_t)) return NULL;
51
+
52
+ return RTYPEDDATA_DATA(obj);
53
+ }
54
+
55
+ static ddog_ThreadContextHandle *get_current_fiber_handle(void) {
56
+ return get_fiber_handle_for(rb_thread_current());
57
+ }
58
+
59
+ static void store_current_fiber_handle(ddog_ThreadContextHandle *handle) {
60
+ VALUE obj = TypedData_Wrap_Struct(rb_cObject, &otel_ctx_handle_t, handle);
61
+ rb_thread_local_aset(rb_thread_current(), fiber_context_slot, obj);
62
+ }
63
+
64
+ #ifdef RUBY_INTERNAL_THREAD_EVENT_EXITED
65
+ static void on_thread_exited(
66
+ DDTRACE_UNUSED rb_event_flag_t event,
67
+ DDTRACE_UNUSED const rb_internal_thread_event_data_t *event_data,
68
+ DDTRACE_UNUSED void *user_data
69
+ ) {
70
+ ddog_otel_thread_ctx_detach();
71
+ }
72
+ #else
73
+ static void on_thread_end(
74
+ DDTRACE_UNUSED rb_event_flag_t evflag,
75
+ DDTRACE_UNUSED VALUE data,
76
+ DDTRACE_UNUSED VALUE self,
77
+ DDTRACE_UNUSED ID mid,
78
+ DDTRACE_UNUSED VALUE klass
79
+ ) {
80
+ ddog_otel_thread_ctx_detach();
81
+ }
82
+ #endif
83
+
84
+ #ifdef HAVE_RUBY_THREAD_STORAGE_API
85
+ // This function is declared in internal/thread.h.
86
+ // It returns 0 when the current thread sits in a blocking region.
87
+ int ruby_thread_has_gvl_p(void);
88
+
89
+ static bool in_blocking_region(void) {
90
+ #ifdef HAVE_RUBY_THREAD_HAS_GVL_P
91
+ return ruby_thread_has_gvl_p() == 0;
92
+ #else
93
+ return false;
94
+ #endif
95
+ }
96
+
97
+ // Under M:N a Ruby thread can migrate between native threads,
98
+ // so we need to detach the context when the Ruby thread gets suspended.
99
+ static void on_thread_suspended(
100
+ DDTRACE_UNUSED rb_event_flag_t event,
101
+ DDTRACE_UNUSED const rb_internal_thread_event_data_t *event_data,
102
+ DDTRACE_UNUSED void *user_data
103
+ ) {
104
+ // Ruby pins threads that release GVL to call into a native extension,
105
+ // so we know the thread will not migrate.
106
+ if (in_blocking_region()) return;
107
+
108
+ ddog_otel_thread_ctx_detach();
109
+ }
110
+
111
+ static void on_thread_resumed(
112
+ DDTRACE_UNUSED rb_event_flag_t event,
113
+ const rb_internal_thread_event_data_t *event_data,
114
+ DDTRACE_UNUSED void *user_data
115
+ ) {
116
+ ddog_ThreadContextHandle *handle = get_fiber_handle_for(event_data->thread);
117
+
118
+ if (handle != NULL) ddog_otel_thread_ctx_attach(handle);
119
+ }
120
+ #endif
121
+
122
+ static void on_fiber_switch(
123
+ DDTRACE_UNUSED rb_event_flag_t evflag,
124
+ DDTRACE_UNUSED VALUE data,
125
+ DDTRACE_UNUSED VALUE self,
126
+ DDTRACE_UNUSED ID mid,
127
+ DDTRACE_UNUSED VALUE klass
128
+ ) {
129
+ ddog_ThreadContextHandle *handle = get_current_fiber_handle();
130
+
131
+ if (handle != NULL) {
132
+ ddog_otel_thread_ctx_attach(handle);
133
+ } else {
134
+ ddog_otel_thread_ctx_detach();
135
+ }
136
+ }
137
+ #endif
138
+
139
+ static VALUE native_enable(DDTRACE_UNUSED VALUE _self) {
140
+ #ifdef __linux__
141
+ if (otel_context_enabled) return Qtrue;
142
+ otel_context_enabled = true;
143
+
144
+ #ifdef RUBY_INTERNAL_THREAD_EVENT_EXITED
145
+ rb_internal_thread_add_event_hook(on_thread_exited, RUBY_INTERNAL_THREAD_EVENT_EXITED, NULL);
146
+ #else
147
+ rb_add_event_hook(on_thread_end, RUBY_EVENT_THREAD_END, Qnil);
148
+ #endif
149
+
150
+ // These hooks only matter under the M:N thread scheduler (Ruby 3.3+),
151
+ // where a Ruby thread can migrate between native threads.
152
+ #ifdef HAVE_RUBY_THREAD_STORAGE_API
153
+ rb_internal_thread_add_event_hook(on_thread_suspended, RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, NULL);
154
+ rb_internal_thread_add_event_hook(on_thread_resumed, RUBY_INTERNAL_THREAD_EVENT_RESUMED, NULL);
155
+ #endif
156
+
157
+ rb_add_event_hook(on_fiber_switch, RUBY_EVENT_FIBER_SWITCH, Qnil);
158
+
159
+ return Qtrue;
160
+ #else
161
+ return Qfalse;
162
+ #endif
163
+ }
164
+
165
+ static VALUE native_supported_p(DDTRACE_UNUSED VALUE _self) {
166
+ #ifdef __linux__
167
+ return Qtrue;
168
+ #else
169
+ return Qfalse;
170
+ #endif
171
+ }
172
+
173
+ static VALUE native_set(
174
+ DDTRACE_UNUSED VALUE _self,
175
+ DDTRACE_UNUSED VALUE trace_id,
176
+ DDTRACE_UNUSED VALUE span_id,
177
+ DDTRACE_UNUSED VALUE local_root_span_id
178
+ ) {
179
+ #ifdef __linux__
180
+ if (!otel_context_enabled) return Qfalse;
181
+
182
+ uint8_t trace_id_bytes[16];
183
+ uint8_t span_id_bytes[8];
184
+ uint8_t local_root_span_id_bytes[8];
185
+
186
+ const int BIG_ENDIAN_PACK_FLAGS = INTEGER_PACK_MSWORD_FIRST | INTEGER_PACK_BIG_ENDIAN;
187
+ rb_integer_pack(trace_id, trace_id_bytes, sizeof(trace_id_bytes), 1, 0, BIG_ENDIAN_PACK_FLAGS);
188
+ rb_integer_pack(span_id, span_id_bytes, sizeof(span_id_bytes), 1, 0, BIG_ENDIAN_PACK_FLAGS);
189
+ rb_integer_pack(local_root_span_id, local_root_span_id_bytes, sizeof(local_root_span_id_bytes), 1, 0, BIG_ENDIAN_PACK_FLAGS);
190
+
191
+ ddog_ThreadContextHandle *handle = get_current_fiber_handle();
192
+
193
+ if (handle == NULL) {
194
+ handle = ddog_otel_thread_ctx_new(&trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
195
+ store_current_fiber_handle(handle);
196
+ ddog_otel_thread_ctx_attach(handle);
197
+ } else {
198
+ // FIXME: add a method to libdatadog to update the context record before attaching it
199
+ ddog_otel_thread_ctx_attach(handle);
200
+ ddog_otel_thread_ctx_update(&trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
201
+ }
202
+
203
+ return Qtrue;
204
+ #else
205
+ return Qfalse;
206
+ #endif
207
+ }
208
+
209
+ static VALUE native_clear(DDTRACE_UNUSED VALUE _self) {
210
+ #ifdef __linux__
211
+ if (!otel_context_enabled) return Qfalse;
212
+
213
+ ddog_ThreadContextHandle *detached = ddog_otel_thread_ctx_detach();
214
+ rb_thread_local_aset(rb_thread_current(), fiber_context_slot, Qnil);
215
+
216
+ return detached == NULL ? Qfalse : Qtrue;
217
+ #else
218
+ return Qfalse;
219
+ #endif
220
+ }
221
+
222
+ static VALUE native_read(DDTRACE_UNUSED VALUE _self) {
223
+ #ifdef __linux__
224
+ const uint8_t *raw = otel_thread_ctx_v1;
225
+ if (!raw) return Qnil;
226
+
227
+ uint16_t attrs_data_size = (uint16_t) raw[26] | ((uint16_t) raw[27] << 8);
228
+
229
+ if (attrs_data_size > ddog_MAX_ATTRS_DATA_SIZE) {
230
+ raise_error(
231
+ rb_eRuntimeError,
232
+ "Invalid OTel thread context record: attrs_data_size (%d) exceeds maximum (%d)",
233
+ attrs_data_size, ddog_MAX_ATTRS_DATA_SIZE
234
+ );
235
+ }
236
+
237
+ VALUE result = rb_hash_new();
238
+ rb_hash_aset(result, ID2SYM(rb_intern("trace_id")), rb_str_new((const char *) raw, 16));
239
+ rb_hash_aset(result, ID2SYM(rb_intern("span_id")), rb_str_new((const char *) (raw + 16), 8));
240
+ rb_hash_aset(result, ID2SYM(rb_intern("valid")), rb_str_new((const char *) (raw + 24), 1));
241
+ rb_hash_aset(result, ID2SYM(rb_intern("attrs")), rb_str_new((const char *) (raw + 28), attrs_data_size));
242
+
243
+ return result;
244
+ #else
245
+ return Qnil;
246
+ #endif
247
+ }
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ void otel_thread_context_init(VALUE tracing_module);