datadog 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
  };