datadog 2.3.0 → 2.4.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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -1
  3. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
  4. data/ext/datadog_profiling_loader/extconf.rb +10 -22
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +148 -30
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -2
  7. data/ext/datadog_profiling_native_extension/collectors_stack.c +89 -46
  8. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +580 -29
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +9 -1
  10. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +0 -27
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -4
  12. data/ext/datadog_profiling_native_extension/extconf.rb +38 -21
  13. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
  14. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
  15. data/ext/datadog_profiling_native_extension/heap_recorder.c +20 -6
  16. data/ext/datadog_profiling_native_extension/http_transport.c +38 -6
  17. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +52 -1
  18. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -0
  19. data/ext/datadog_profiling_native_extension/profiling.c +1 -1
  20. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
  21. data/ext/libdatadog_api/crashtracker.c +20 -18
  22. data/ext/libdatadog_api/datadog_ruby_common.c +0 -27
  23. data/ext/libdatadog_api/datadog_ruby_common.h +0 -4
  24. data/ext/libdatadog_extconf_helpers.rb +1 -1
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
  26. data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
  27. data/lib/datadog/appsec/component.rb +29 -8
  28. data/lib/datadog/appsec/configuration/settings.rb +2 -2
  29. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
  30. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
  31. data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
  32. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +0 -14
  33. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +67 -31
  34. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +18 -15
  35. data/lib/datadog/appsec/contrib/graphql/integration.rb +14 -1
  36. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +2 -5
  37. data/lib/datadog/appsec/event.rb +1 -1
  38. data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
  39. data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
  40. data/lib/datadog/appsec/processor.rb +36 -37
  41. data/lib/datadog/appsec/rate_limiter.rb +25 -40
  42. data/lib/datadog/appsec/remote.rb +7 -3
  43. data/lib/datadog/appsec.rb +2 -2
  44. data/lib/datadog/core/configuration/components.rb +4 -3
  45. data/lib/datadog/core/configuration/settings.rb +84 -5
  46. data/lib/datadog/core/crashtracking/component.rb +1 -1
  47. data/lib/datadog/core/environment/execution.rb +5 -5
  48. data/lib/datadog/core/metrics/client.rb +7 -0
  49. data/lib/datadog/core/rate_limiter.rb +183 -0
  50. data/lib/datadog/core/remote/client/capabilities.rb +4 -3
  51. data/lib/datadog/core/remote/component.rb +4 -2
  52. data/lib/datadog/core/remote/negotiation.rb +4 -4
  53. data/lib/datadog/core/remote/tie.rb +2 -0
  54. data/lib/datadog/core/runtime/metrics.rb +1 -1
  55. data/lib/datadog/core/telemetry/component.rb +2 -0
  56. data/lib/datadog/core/telemetry/event.rb +12 -7
  57. data/lib/datadog/core/telemetry/logger.rb +51 -0
  58. data/lib/datadog/core/telemetry/logging.rb +50 -14
  59. data/lib/datadog/core/telemetry/request.rb +13 -1
  60. data/lib/datadog/core/utils/time.rb +12 -0
  61. data/lib/datadog/di/code_tracker.rb +168 -0
  62. data/lib/datadog/di/configuration/settings.rb +163 -0
  63. data/lib/datadog/di/configuration.rb +11 -0
  64. data/lib/datadog/di/error.rb +31 -0
  65. data/lib/datadog/di/extensions.rb +16 -0
  66. data/lib/datadog/di/probe.rb +133 -0
  67. data/lib/datadog/di/probe_builder.rb +41 -0
  68. data/lib/datadog/di/redactor.rb +188 -0
  69. data/lib/datadog/di/serializer.rb +193 -0
  70. data/lib/datadog/di.rb +14 -0
  71. data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
  72. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +12 -10
  73. data/lib/datadog/profiling/collectors/info.rb +12 -3
  74. data/lib/datadog/profiling/collectors/thread_context.rb +26 -0
  75. data/lib/datadog/profiling/component.rb +20 -4
  76. data/lib/datadog/profiling/http_transport.rb +6 -1
  77. data/lib/datadog/profiling/scheduler.rb +2 -0
  78. data/lib/datadog/profiling/stack_recorder.rb +3 -0
  79. data/lib/datadog/single_step_instrument.rb +12 -0
  80. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
  81. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
  82. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
  83. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
  84. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
  85. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
  86. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
  87. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +3 -1
  88. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
  89. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
  90. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  91. data/lib/datadog/tracing/contrib/faraday/middleware.rb +9 -0
  92. data/lib/datadog/tracing/contrib/grape/endpoint.rb +19 -0
  93. data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
  94. data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
  95. data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
  96. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +13 -9
  97. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +6 -3
  98. data/lib/datadog/tracing/contrib/http/instrumentation.rb +18 -15
  99. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -5
  100. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
  101. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +5 -0
  102. data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
  103. data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -2
  104. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  105. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
  106. data/lib/datadog/tracing/contrib/patcher.rb +2 -1
  107. data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
  108. data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
  109. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
  110. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
  111. data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
  112. data/lib/datadog/tracing/distributed/propagation.rb +7 -0
  113. data/lib/datadog/tracing/metadata/ext.rb +2 -0
  114. data/lib/datadog/tracing/remote.rb +5 -2
  115. data/lib/datadog/tracing/sampling/matcher.rb +6 -1
  116. data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
  117. data/lib/datadog/tracing/sampling/rule.rb +2 -0
  118. data/lib/datadog/tracing/sampling/rule_sampler.rb +9 -5
  119. data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
  120. data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
  121. data/lib/datadog/tracing/trace_operation.rb +26 -2
  122. data/lib/datadog/tracing/tracer.rb +14 -12
  123. data/lib/datadog/tracing/transport/http/client.rb +1 -0
  124. data/lib/datadog/tracing/transport/io/client.rb +1 -0
  125. data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
  126. data/lib/datadog/tracing/workers.rb +1 -1
  127. data/lib/datadog/version.rb +1 -1
  128. metadata +25 -8
  129. data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -20,16 +20,9 @@ struct sampling_buffer {
20
20
  frame_info *stack_buffer;
21
21
  }; // Note: typedef'd in the header to sampling_buffer
22
22
 
23
- static VALUE _native_sample(
24
- VALUE self,
25
- VALUE thread,
26
- VALUE recorder_instance,
27
- VALUE metric_values_hash,
28
- VALUE labels_array,
29
- VALUE numeric_labels_array,
30
- VALUE max_frames,
31
- VALUE in_gc
32
- );
23
+ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
24
+ static VALUE native_sample_do(VALUE args);
25
+ static VALUE native_sample_ensure(VALUE args);
33
26
  static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size);
34
27
  static void record_placeholder_stack_in_native_code(VALUE recorder_instance, sample_values values, sample_labels labels);
35
28
  static void maybe_trim_template_random_ids(ddog_CharSlice *name_slice, ddog_CharSlice *filename_slice);
@@ -45,24 +38,42 @@ void collectors_stack_init(VALUE profiling_module) {
45
38
  // Hosts methods used for testing the native code using RSpec
46
39
  VALUE testing_module = rb_define_module_under(collectors_stack_class, "Testing");
47
40
 
48
- rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 7);
41
+ rb_define_singleton_method(testing_module, "_native_sample", _native_sample, -1);
49
42
 
50
43
  missing_string = rb_str_new2("");
51
44
  rb_global_variable(&missing_string);
52
45
  }
53
46
 
47
+ struct native_sample_args {
48
+ VALUE in_gc;
49
+ VALUE recorder_instance;
50
+ sample_values values;
51
+ sample_labels labels;
52
+ VALUE thread;
53
+ ddog_prof_Location *locations;
54
+ sampling_buffer *buffer;
55
+ };
56
+
54
57
  // This method exists only to enable testing Datadog::Profiling::Collectors::Stack behavior using RSpec.
55
58
  // It SHOULD NOT be used for other purposes.
56
- static VALUE _native_sample(
57
- DDTRACE_UNUSED VALUE _self,
58
- VALUE thread,
59
- VALUE recorder_instance,
60
- VALUE metric_values_hash,
61
- VALUE labels_array,
62
- VALUE numeric_labels_array,
63
- VALUE max_frames,
64
- VALUE in_gc
65
- ) {
59
+ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
60
+ // Positional args
61
+ VALUE thread;
62
+ VALUE recorder_instance;
63
+ VALUE metric_values_hash;
64
+ VALUE labels_array;
65
+ VALUE numeric_labels_array;
66
+ VALUE options;
67
+
68
+ rb_scan_args(argc, argv, "5:", &thread, &recorder_instance, &metric_values_hash, &labels_array, &numeric_labels_array, &options);
69
+
70
+ if (options == Qnil) options = rb_hash_new();
71
+
72
+ // Optional keyword args
73
+ VALUE max_frames = rb_hash_lookup2(options, ID2SYM(rb_intern("max_frames")), INT2NUM(400));
74
+ VALUE in_gc = rb_hash_lookup2(options, ID2SYM(rb_intern("in_gc")), Qfalse);
75
+ VALUE is_gvl_waiting_state = rb_hash_lookup2(options, ID2SYM(rb_intern("is_gvl_waiting_state")), Qfalse);
76
+
66
77
  ENFORCE_TYPE(metric_values_hash, T_HASH);
67
78
  ENFORCE_TYPE(labels_array, T_ARRAY);
68
79
  ENFORCE_TYPE(numeric_labels_array, T_ARRAY);
@@ -105,33 +116,54 @@ static VALUE _native_sample(
105
116
  };
106
117
  }
107
118
 
108
- int max_frames_requested = NUM2INT(max_frames);
109
- if (max_frames_requested < 0) rb_raise(rb_eArgError, "Invalid max_frames: value must not be negative");
119
+ int max_frames_requested = sampling_buffer_check_max_frames(NUM2INT(max_frames));
110
120
 
111
121
  ddog_prof_Location *locations = ruby_xcalloc(max_frames_requested, sizeof(ddog_prof_Location));
112
122
  sampling_buffer *buffer = sampling_buffer_new(max_frames_requested, locations);
113
123
 
114
124
  ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = labels_count};
115
125
 
116
- if (in_gc == Qtrue) {
126
+ struct native_sample_args args_struct = {
127
+ .in_gc = in_gc,
128
+ .recorder_instance = recorder_instance,
129
+ .values = values,
130
+ .labels = (sample_labels) {.labels = slice_labels, .state_label = state_label, .is_gvl_waiting_state = is_gvl_waiting_state == Qtrue},
131
+ .thread = thread,
132
+ .locations = locations,
133
+ .buffer = buffer,
134
+ };
135
+
136
+ return rb_ensure(native_sample_do, (VALUE) &args_struct, native_sample_ensure, (VALUE) &args_struct);
137
+ }
138
+
139
+ static VALUE native_sample_do(VALUE args) {
140
+ struct native_sample_args *args_struct = (struct native_sample_args *) args;
141
+
142
+ if (args_struct->in_gc == Qtrue) {
117
143
  record_placeholder_stack(
118
- recorder_instance,
119
- values,
120
- (sample_labels) {.labels = slice_labels, .state_label = state_label},
144
+ args_struct->recorder_instance,
145
+ args_struct->values,
146
+ args_struct->labels,
121
147
  DDOG_CHARSLICE_C("Garbage Collection")
122
148
  );
123
149
  } else {
124
150
  sample_thread(
125
- thread,
126
- buffer,
127
- recorder_instance,
128
- values,
129
- (sample_labels) {.labels = slice_labels, .state_label = state_label}
151
+ args_struct->thread,
152
+ args_struct->buffer,
153
+ args_struct->recorder_instance,
154
+ args_struct->values,
155
+ args_struct->labels
130
156
  );
131
157
  }
132
158
 
133
- ruby_xfree(locations);
134
- sampling_buffer_free(buffer);
159
+ return Qtrue;
160
+ }
161
+
162
+ static VALUE native_sample_ensure(VALUE args) {
163
+ struct native_sample_args *args_struct = (struct native_sample_args *) args;
164
+
165
+ ruby_xfree(args_struct->locations);
166
+ sampling_buffer_free(args_struct->buffer);
135
167
 
136
168
  return Qtrue;
137
169
  }
@@ -185,11 +217,17 @@ void sample_thread(
185
217
  ddog_prof_Label *state_label = labels.state_label;
186
218
  bool cpu_or_wall_sample = values.cpu_or_wall_samples > 0;
187
219
  bool has_cpu_time = cpu_or_wall_sample && values.cpu_time_ns > 0;
188
- bool only_wall_time = cpu_or_wall_sample && values.cpu_time_ns == 0 && values.wall_time_ns > 0;
220
+ // Note: In theory, a cpu_or_wall_sample should always have some wall-time. In practice, the first sample for a thread
221
+ // will be zero, as well as if the system clock does something weird. Thus, at some point we had values.wall_time_ns > 0
222
+ // here, but >= 0 makes this easier to understand/debug.
223
+ bool only_wall_time = cpu_or_wall_sample && values.cpu_time_ns == 0 && values.wall_time_ns >= 0;
189
224
 
190
225
  if (cpu_or_wall_sample && state_label == NULL) rb_raise(rb_eRuntimeError, "BUG: Unexpected missing state_label");
191
226
 
192
- if (has_cpu_time) state_label->str = DDOG_CHARSLICE_C("had cpu");
227
+ if (has_cpu_time) {
228
+ state_label->str = DDOG_CHARSLICE_C("had cpu");
229
+ if (labels.is_gvl_waiting_state) rb_raise(rb_eRuntimeError, "BUG: Unexpected combination of cpu-time with is_gvl_waiting");
230
+ }
193
231
 
194
232
  for (int i = captured_frames - 1; i >= 0; i--) {
195
233
  VALUE name, filename;
@@ -219,12 +257,15 @@ void sample_thread(
219
257
  bool top_of_the_stack = i == 0;
220
258
 
221
259
  // When there's only wall-time in a sample, this means that the thread was not active in the sampled period.
222
- //
223
- // We try to categorize what it was doing based on what we observe at the top of the stack. This is a very rough
224
- // approximation, and in the future we hope to replace this with a more accurate approach (such as using the
225
- // GVL instrumentation API.)
226
260
  if (top_of_the_stack && only_wall_time) {
227
- if (!buffer->stack_buffer[i].is_ruby_frame) {
261
+ // Did the caller already provide the state?
262
+ if (labels.is_gvl_waiting_state) {
263
+ state_label->str = DDOG_CHARSLICE_C("waiting for gvl");
264
+
265
+ // Otherwise, we try to categorize what the thread was doing based on what we observe at the top of the stack. This is a very rough
266
+ // approximation, and in the future we hope to replace this with a more accurate approach (such as using the
267
+ // GVL instrumentation API.)
268
+ } else if (!buffer->stack_buffer[i].is_ruby_frame) {
228
269
  // We know that known versions of Ruby implement these using native code; thus if we find a method with the
229
270
  // same name that is not native code, we ignore it, as it's probably a user method that coincidentally
230
271
  // has the same name. Thus, even though "matching just by method name" is kinda weak,
@@ -259,10 +300,8 @@ void sample_thread(
259
300
  }
260
301
 
261
302
  buffer->locations[i] = (ddog_prof_Location) {
262
- .function = (ddog_prof_Function) {
263
- .name = name_slice,
264
- .filename = filename_slice,
265
- },
303
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
304
+ .function = (ddog_prof_Function) {.name = name_slice, .filename = filename_slice},
266
305
  .line = line,
267
306
  };
268
307
  }
@@ -300,7 +339,9 @@ static void maybe_trim_template_random_ids(ddog_CharSlice *name_slice, ddog_Char
300
339
  // Check filename doesn't end with ".rb"; templates are usually along the lines of .html.erb/.html.haml/...
301
340
  if (filename_slice->len < 3 || memcmp(filename_slice->ptr + filename_slice->len - 3, ".rb", 3) == 0) return;
302
341
 
303
- int pos = name_slice->len - 1;
342
+ if (name_slice->len > 1024) return;
343
+
344
+ int pos = ((int) name_slice->len) - 1;
304
345
 
305
346
  // Let's match on something__number_number:
306
347
  // Find start of id suffix from the end...
@@ -338,6 +379,7 @@ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer*
338
379
  ddog_CharSlice function_name = DDOG_CHARSLICE_C("");
339
380
  ddog_CharSlice function_filename = {.ptr = frames_omitted_message, .len = strlen(frames_omitted_message)};
340
381
  buffer->locations[buffer->max_frames - 1] = (ddog_prof_Location) {
382
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
341
383
  .function = (ddog_prof_Function) {.name = function_name, .filename = function_filename},
342
384
  .line = 0,
343
385
  };
@@ -384,6 +426,7 @@ void record_placeholder_stack(
384
426
  ddog_CharSlice placeholder_stack
385
427
  ) {
386
428
  ddog_prof_Location placeholder_location = {
429
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
387
430
  .function = {.name = DDOG_CHARSLICE_C(""), .filename = placeholder_stack},
388
431
  .line = 0,
389
432
  };