datadog 2.16.0 → 2.17.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  4. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  5. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  6. data/ext/datadog_profiling_native_extension/stack_recorder.c +4 -5
  7. data/ext/libdatadog_api/crashtracker.c +10 -3
  8. data/ext/libdatadog_api/macos_development.md +3 -3
  9. data/ext/libdatadog_extconf_helpers.rb +1 -1
  10. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  11. data/lib/datadog/appsec/api_security.rb +9 -0
  12. data/lib/datadog/core/buffer/random.rb +18 -2
  13. data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -5
  14. data/lib/datadog/core/configuration/components.rb +29 -20
  15. data/lib/datadog/core/configuration/components_state.rb +23 -0
  16. data/lib/datadog/core/configuration/option.rb +18 -18
  17. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  18. data/lib/datadog/core/configuration/options.rb +1 -1
  19. data/lib/datadog/core/configuration/settings.rb +10 -10
  20. data/lib/datadog/core/configuration.rb +16 -16
  21. data/lib/datadog/core/crashtracking/component.rb +2 -1
  22. data/lib/datadog/core/encoding.rb +1 -1
  23. data/lib/datadog/core/environment/cgroup.rb +10 -12
  24. data/lib/datadog/core/environment/container.rb +38 -40
  25. data/lib/datadog/core/environment/ext.rb +6 -6
  26. data/lib/datadog/core/environment/identity.rb +3 -3
  27. data/lib/datadog/core/environment/platform.rb +3 -3
  28. data/lib/datadog/core/error.rb +11 -9
  29. data/lib/datadog/core/logger.rb +2 -2
  30. data/lib/datadog/core/metrics/client.rb +12 -14
  31. data/lib/datadog/core/metrics/logging.rb +5 -5
  32. data/lib/datadog/core/rate_limiter.rb +4 -2
  33. data/lib/datadog/core/remote/client.rb +32 -31
  34. data/lib/datadog/core/remote/component.rb +3 -3
  35. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  36. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  37. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  38. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  39. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  40. data/lib/datadog/core/runtime/metrics.rb +3 -3
  41. data/lib/datadog/core/telemetry/component.rb +39 -24
  42. data/lib/datadog/core/telemetry/emitter.rb +7 -1
  43. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  44. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  45. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  46. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  47. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  48. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  49. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  50. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  51. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  52. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  53. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  54. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  55. data/lib/datadog/core/telemetry/event.rb +17 -475
  56. data/lib/datadog/core/telemetry/logger.rb +1 -1
  57. data/lib/datadog/core/telemetry/metric.rb +3 -3
  58. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -2
  59. data/lib/datadog/core/telemetry/transport/telemetry.rb +0 -1
  60. data/lib/datadog/core/telemetry/worker.rb +48 -27
  61. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  62. data/lib/datadog/core/transport/http/builder.rb +13 -13
  63. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  64. data/lib/datadog/core/utils/duration.rb +32 -32
  65. data/lib/datadog/core/utils/forking.rb +2 -2
  66. data/lib/datadog/core/utils/network.rb +6 -6
  67. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  68. data/lib/datadog/core/utils/time.rb +10 -2
  69. data/lib/datadog/core/utils/truncation.rb +21 -0
  70. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  71. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  72. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  73. data/lib/datadog/core/worker.rb +1 -1
  74. data/lib/datadog/core/workers/async.rb +9 -10
  75. data/lib/datadog/error_tracking/component.rb +2 -2
  76. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  77. data/lib/datadog/profiling/ext.rb +0 -1
  78. data/lib/datadog/profiling/flush.rb +1 -1
  79. data/lib/datadog/profiling/http_transport.rb +1 -6
  80. data/lib/datadog/profiling/scheduler.rb +8 -1
  81. data/lib/datadog/profiling/tag_builder.rb +1 -5
  82. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  83. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  84. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  85. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  86. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  87. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  88. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  89. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  90. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  91. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  92. data/lib/datadog/tracing/contrib/support.rb +28 -0
  93. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  94. data/lib/datadog/version.rb +1 -1
  95. metadata +23 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da587b7c67d38c9ec9730e62603ffecf699d3841978676a06f0fe99506614a3d
4
- data.tar.gz: d17d0f78fe1226187aedd815606ce3b450eb6150139c13116ce24082215452dd
3
+ metadata.gz: 28053ce1bca4cce2032cb068c38e99a56524e6ccecec3068c4d26d1e750f9790
4
+ data.tar.gz: 29b6b57640638184370c5176e4da94e74c9770bae8afd7884d1c2baea782350d
5
5
  SHA512:
6
- metadata.gz: 8d40c4f84ca2396f1011bc27eeb5489a1ded2669c47473a838d5b70191c57b3e34beee38abe8c9737d13212bbf07221ec17a0b428023974ec7001465bbfa7745
7
- data.tar.gz: '0155923613825e859fb952901a98f2a779a5128b1cb02cf4e3c619fb99b1bf9b4a7428b1e56cb8580103d52cc189a354df9a1db697c5b857a8c318d2a383bdba'
6
+ metadata.gz: caf719b7c9a2e5ee3f47ad0c3e02670b90b1f76bfa5de56c10f69169c97b827f4b9e81df822e548d1390f152f15e756c54c200e9f35904138e7c672af99ef30b
7
+ data.tar.gz: eda75252942b8c7d278bab14da78c7752b17b136a3f0bd9ed145512a64b3fb8acb110a8cbbfb280b2bcf7c558409ce83b5d311fce5f019ff34516ceb3883255c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.17.0] - 2025-06-02
6
+
7
+ ### Added
8
+
9
+ * Tracing: Add support for Rails 8.0. ([#4455][])
10
+
11
+ ### Changed
12
+
13
+ * Core: Improve tracer error reporting when agent responds with error responses to remote configuration requests ([#4669][])
14
+ * Core: Profiling: Upgrade libdatadog dependency to version 18.1 ([#4577][])
15
+ * Dynamic Instrumentation: Improve UI reporting of application and host status ([#4678][])
16
+ * Tracing: Mark AWS integration spans as errored when AWS requests fail ([#4672][])
17
+
18
+ ### Fixed
19
+
20
+ * Error Tracking: remove error tracking support on Ruby 2.6 ([#4665][])
21
+ * Profiling: Fix profiling scheduler reporting corner case during shutdown ([#4679][])
22
+ * Tracing: Fix: The `on_error` warning for HTTP instrumentations ([#4673][])
23
+
5
24
  ## [2.16.0] - 2025-05-19
6
25
 
7
26
  ### Added
@@ -3222,7 +3241,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3222
3241
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3223
3242
 
3224
3243
 
3225
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.16.0...master
3244
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.17.0...master
3245
+ [2.17.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.16.0...v2.17.0
3226
3246
  [2.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.15.0...v2.16.0
3227
3247
  [2.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.14.0...v2.15.0
3228
3248
  [2.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.13.0...v2.14.0
@@ -4734,6 +4754,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4734
4754
  [#4426]: https://github.com/DataDog/dd-trace-rb/issues/4426
4735
4755
  [#4433]: https://github.com/DataDog/dd-trace-rb/issues/4433
4736
4756
  [#4437]: https://github.com/DataDog/dd-trace-rb/issues/4437
4757
+ [#4455]: https://github.com/DataDog/dd-trace-rb/issues/4455
4737
4758
  [#4473]: https://github.com/DataDog/dd-trace-rb/issues/4473
4738
4759
  [#4493]: https://github.com/DataDog/dd-trace-rb/issues/4493
4739
4760
  [#4497]: https://github.com/DataDog/dd-trace-rb/issues/4497
@@ -4752,6 +4773,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4752
4773
  [#4568]: https://github.com/DataDog/dd-trace-rb/issues/4568
4753
4774
  [#4573]: https://github.com/DataDog/dd-trace-rb/issues/4573
4754
4775
  [#4575]: https://github.com/DataDog/dd-trace-rb/issues/4575
4776
+ [#4577]: https://github.com/DataDog/dd-trace-rb/issues/4577
4755
4777
  [#4580]: https://github.com/DataDog/dd-trace-rb/issues/4580
4756
4778
  [#4581]: https://github.com/DataDog/dd-trace-rb/issues/4581
4757
4779
  [#4590]: https://github.com/DataDog/dd-trace-rb/issues/4590
@@ -4767,6 +4789,12 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4767
4789
  [#4644]: https://github.com/DataDog/dd-trace-rb/issues/4644
4768
4790
  [#4653]: https://github.com/DataDog/dd-trace-rb/issues/4653
4769
4791
  [#4656]: https://github.com/DataDog/dd-trace-rb/issues/4656
4792
+ [#4665]: https://github.com/DataDog/dd-trace-rb/issues/4665
4793
+ [#4669]: https://github.com/DataDog/dd-trace-rb/issues/4669
4794
+ [#4672]: https://github.com/DataDog/dd-trace-rb/issues/4672
4795
+ [#4673]: https://github.com/DataDog/dd-trace-rb/issues/4673
4796
+ [#4678]: https://github.com/DataDog/dd-trace-rb/issues/4678
4797
+ [#4679]: https://github.com/DataDog/dd-trace-rb/issues/4679
4770
4798
  [@AdrianLC]: https://github.com/AdrianLC
4771
4799
  [@Azure7111]: https://github.com/Azure7111
4772
4800
  [@BabyGroot]: https://github.com/BabyGroot
@@ -38,6 +38,26 @@ VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile) {
38
38
  return TypedData_Wrap_Struct(encoded_profile_class, &encoded_profile_typed_data, state);
39
39
  }
40
40
 
41
+ static ddog_ByteSlice get_bytes(ddog_prof_EncodedProfile *state) {
42
+ ddog_prof_Result_ByteSlice raw_bytes = ddog_prof_EncodedProfile_bytes(state);
43
+ if (raw_bytes.tag == DDOG_PROF_RESULT_BYTE_SLICE_ERR_BYTE_SLICE) {
44
+ rb_raise(rb_eRuntimeError, "Failed to get bytes from profile: %"PRIsVALUE, get_error_details_and_drop(&raw_bytes.err));
45
+ }
46
+ return raw_bytes.ok;
47
+ }
48
+
49
+ static ddog_prof_EncodedProfile *internal_to_ddog_prof_EncodedProfile(VALUE object) {
50
+ ddog_prof_EncodedProfile *state;
51
+ TypedData_Get_Struct(object, ddog_prof_EncodedProfile, &encoded_profile_typed_data, state);
52
+ return state;
53
+ }
54
+
55
+ ddog_prof_EncodedProfile *to_ddog_prof_EncodedProfile(VALUE object) {
56
+ ddog_prof_EncodedProfile *state = internal_to_ddog_prof_EncodedProfile(object);
57
+ get_bytes(state); // Validate profile is still usable -- if it's not, this will raise an exception
58
+ return state;
59
+ }
60
+
41
61
  static void encoded_profile_typed_data_free(void *state_ptr) {
42
62
  ddog_prof_EncodedProfile *state = (ddog_prof_EncodedProfile *) state_ptr;
43
63
 
@@ -49,18 +69,8 @@ static void encoded_profile_typed_data_free(void *state_ptr) {
49
69
  }
50
70
 
51
71
  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);*/
72
+ ddog_ByteSlice bytes = get_bytes(internal_to_ddog_prof_EncodedProfile(self));
73
+ return rb_str_new((const char *) bytes.ptr, bytes.len);
64
74
  }
65
75
 
66
76
  VALUE enforce_encoded_profile_instance(VALUE object) {
@@ -5,3 +5,4 @@
5
5
 
6
6
  VALUE from_ddog_prof_EncodedProfile(ddog_prof_EncodedProfile profile);
7
7
  VALUE enforce_encoded_profile_instance(VALUE object);
8
+ ddog_prof_EncodedProfile *to_ddog_prof_EncodedProfile(VALUE object);
@@ -15,26 +15,22 @@ static VALUE error_symbol = Qnil; // :error in Ruby
15
15
  static VALUE library_version_string = Qnil;
16
16
 
17
17
  typedef struct {
18
- ddog_prof_Exporter *exporter;
19
- ddog_prof_Exporter_Request_BuildResult *build_result;
18
+ ddog_prof_ProfileExporter *exporter;
19
+ ddog_prof_Request_Result *build_result;
20
20
  ddog_CancellationToken *cancel_token;
21
- ddog_prof_Exporter_SendResult result;
21
+ ddog_prof_Result_HttpStatus result;
22
22
  bool send_ran;
23
23
  } call_exporter_without_gvl_arguments;
24
24
 
25
25
  static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
26
26
  static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
27
- static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
28
- static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
27
+ static ddog_prof_ProfileExporter_Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
28
+ static VALUE handle_exporter_failure(ddog_prof_ProfileExporter_Result exporter_result);
29
29
  static VALUE _native_do_export(
30
30
  VALUE self,
31
31
  VALUE exporter_configuration,
32
32
  VALUE upload_timeout_milliseconds,
33
- VALUE flush,
34
- VALUE start_timespec_seconds,
35
- VALUE start_timespec_nanoseconds,
36
- VALUE finish_timespec_seconds,
37
- VALUE finish_timespec_nanoseconds
33
+ VALUE flush
38
34
  );
39
35
  static void *call_exporter_without_gvl(void *call_args);
40
36
  static void interrupt_exporter_call(void *cancel_token);
@@ -43,7 +39,7 @@ void http_transport_init(VALUE profiling_module) {
43
39
  VALUE http_transport_class = rb_define_class_under(profiling_module, "HttpTransport", rb_cObject);
44
40
 
45
41
  rb_define_singleton_method(http_transport_class, "_native_validate_exporter", _native_validate_exporter, 1);
46
- rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 7);
42
+ rb_define_singleton_method(http_transport_class, "_native_do_export", _native_do_export, 3);
47
43
 
48
44
  ok_symbol = ID2SYM(rb_intern_const("ok"));
49
45
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -60,14 +56,14 @@ static inline ddog_ByteSlice byte_slice_from_ruby_string(VALUE string) {
60
56
 
61
57
  static VALUE _native_validate_exporter(DDTRACE_UNUSED VALUE _self, VALUE exporter_configuration) {
62
58
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
63
- ddog_prof_Exporter_NewResult exporter_result = create_exporter(exporter_configuration, rb_ary_new());
59
+ ddog_prof_ProfileExporter_Result exporter_result = create_exporter(exporter_configuration, rb_ary_new());
64
60
 
65
61
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
66
62
  if (!NIL_P(failure_tuple)) return failure_tuple;
67
63
 
68
64
  // We don't actually need the exporter for now -- we just wanted to validate that we could create it with the
69
65
  // settings we were given
70
- ddog_prof_Exporter_drop(exporter_result.ok);
66
+ ddog_prof_Exporter_drop(&exporter_result.ok);
71
67
 
72
68
  return rb_ary_new_from_args(2, ok_symbol, Qnil);
73
69
  }
@@ -93,7 +89,7 @@ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
93
89
  }
94
90
  }
95
91
 
96
- static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
92
+ static ddog_prof_ProfileExporter_Result create_exporter(VALUE exporter_configuration, VALUE tags_as_array) {
97
93
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
98
94
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
99
95
 
@@ -107,7 +103,7 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
107
103
  ddog_CharSlice library_version = char_slice_from_ruby_string(library_version_string);
108
104
  ddog_CharSlice profiling_family = DDOG_CHARSLICE_C("ruby");
109
105
 
110
- ddog_prof_Exporter_NewResult exporter_result =
106
+ ddog_prof_ProfileExporter_Result exporter_result =
111
107
  ddog_prof_Exporter_new(library_name, library_version, profiling_family, &tags, endpoint);
112
108
 
113
109
  ddog_Vec_Tag_drop(tags);
@@ -115,8 +111,12 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
115
111
  return exporter_result;
116
112
  }
117
113
 
118
- static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result) {
119
- return exporter_result.tag == DDOG_PROF_EXPORTER_NEW_RESULT_OK ?
114
+ static void validate_token(ddog_CancellationToken token, const char *file, int line) {
115
+ if (token.inner == NULL) rb_raise(rb_eRuntimeError, "Unexpected: Validation token was empty at %s:%d", file, line);
116
+ }
117
+
118
+ static VALUE handle_exporter_failure(ddog_prof_ProfileExporter_Result exporter_result) {
119
+ return exporter_result.tag == DDOG_PROF_PROFILE_EXPORTER_RESULT_OK_HANDLE_PROFILE_EXPORTER ?
120
120
  Qnil :
121
121
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&exporter_result.err));
122
122
  }
@@ -124,38 +124,37 @@ static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_resul
124
124
  // Note: This function handles a bunch of libdatadog dynamically-allocated objects, so it MUST not use any Ruby APIs
125
125
  // which can raise exceptions, otherwise the objects will be leaked.
126
126
  static VALUE perform_export(
127
- ddog_prof_Exporter *exporter,
128
- ddog_Timespec start,
129
- ddog_Timespec finish,
127
+ ddog_prof_ProfileExporter *exporter,
128
+ ddog_prof_EncodedProfile *profile,
130
129
  ddog_prof_Exporter_Slice_File files_to_compress_and_export,
131
- ddog_prof_Exporter_Slice_File files_to_export_unmodified,
132
130
  ddog_CharSlice internal_metadata,
133
131
  ddog_CharSlice info
134
132
  ) {
135
- ddog_prof_ProfiledEndpointsStats *endpoints_stats = NULL; // Not in use yet
136
- ddog_prof_Exporter_Request_BuildResult build_result = ddog_prof_Exporter_Request_build(
133
+ ddog_prof_Request_Result build_result = ddog_prof_Exporter_Request_build(
137
134
  exporter,
138
- start,
139
- finish,
135
+ profile,
140
136
  files_to_compress_and_export,
141
- files_to_export_unmodified,
137
+ /* files_to_export_unmodified: */ ddog_prof_Exporter_Slice_File_empty(),
142
138
  /* optional_additional_tags: */ NULL,
143
- endpoints_stats,
144
139
  &internal_metadata,
145
140
  &info
146
141
  );
147
142
 
148
- if (build_result.tag == DDOG_PROF_EXPORTER_REQUEST_BUILD_RESULT_ERR) {
143
+ if (build_result.tag == DDOG_PROF_REQUEST_RESULT_ERR_HANDLE_REQUEST) {
149
144
  ddog_prof_Exporter_drop(exporter);
150
145
  return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&build_result.err));
151
146
  }
152
147
 
153
- ddog_CancellationToken *cancel_token = ddog_CancellationToken_new();
148
+ ddog_CancellationToken cancel_token_request = ddog_CancellationToken_new();
149
+ ddog_CancellationToken cancel_token_interrupt = ddog_CancellationToken_clone(&cancel_token_request);
150
+
151
+ validate_token(cancel_token_request, __FILE__, __LINE__);
152
+ validate_token(cancel_token_interrupt, __FILE__, __LINE__);
154
153
 
155
154
  // We'll release the Global VM Lock while we're calling send, so that the Ruby VM can continue to work while this
156
155
  // is pending
157
156
  call_exporter_without_gvl_arguments args =
158
- {.exporter = exporter, .build_result = &build_result, .cancel_token = cancel_token, .send_ran = false};
157
+ {.exporter = exporter, .build_result = &build_result, .cancel_token = &cancel_token_request, .send_ran = false};
159
158
 
160
159
  // We use rb_thread_call_without_gvl2 instead of rb_thread_call_without_gvl as the gvl2 variant never raises any
161
160
  // exceptions.
@@ -172,14 +171,15 @@ static VALUE perform_export(
172
171
  int pending_exception = 0;
173
172
 
174
173
  while (!args.send_ran && !pending_exception) {
175
- rb_thread_call_without_gvl2(call_exporter_without_gvl, &args, interrupt_exporter_call, cancel_token);
174
+ rb_thread_call_without_gvl2(call_exporter_without_gvl, &args, interrupt_exporter_call, &cancel_token_interrupt);
176
175
 
177
176
  // To make sure we don't leak memory, we never check for pending exceptions if send ran
178
177
  if (!args.send_ran) pending_exception = check_if_pending_exception();
179
178
  }
180
179
 
181
180
  // Cleanup exporter and token, no longer needed
182
- ddog_CancellationToken_drop(cancel_token);
181
+ ddog_CancellationToken_drop(&cancel_token_request);
182
+ ddog_CancellationToken_drop(&cancel_token_interrupt);
183
183
  ddog_prof_Exporter_drop(exporter);
184
184
 
185
185
  if (pending_exception) {
@@ -192,10 +192,10 @@ static VALUE perform_export(
192
192
 
193
193
  // The request itself does not need to be freed as libdatadog takes ownership of it as part of sending.
194
194
 
195
- ddog_prof_Exporter_SendResult result = args.result;
195
+ ddog_prof_Result_HttpStatus result = args.result;
196
196
 
197
- return result.tag == DDOG_PROF_EXPORTER_SEND_RESULT_HTTP_RESPONSE ?
198
- rb_ary_new_from_args(2, ok_symbol, UINT2NUM(result.http_response.code)) :
197
+ return result.tag == DDOG_PROF_RESULT_HTTP_STATUS_OK_HTTP_STATUS ?
198
+ rb_ary_new_from_args(2, ok_symbol, UINT2NUM(result.ok.code)) :
199
199
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&result.err));
200
200
  }
201
201
 
@@ -203,11 +203,7 @@ static VALUE _native_do_export(
203
203
  DDTRACE_UNUSED VALUE _self,
204
204
  VALUE exporter_configuration,
205
205
  VALUE upload_timeout_milliseconds,
206
- VALUE flush,
207
- VALUE start_timespec_seconds,
208
- VALUE start_timespec_nanoseconds,
209
- VALUE finish_timespec_seconds,
210
- VALUE finish_timespec_nanoseconds
206
+ VALUE flush
211
207
  ) {
212
208
  VALUE encoded_profile = rb_funcall(flush, rb_intern("encoded_profile"), 0);
213
209
  VALUE code_provenance_file_name = rb_funcall(flush, rb_intern("code_provenance_file_name"), 0);
@@ -217,10 +213,6 @@ static VALUE _native_do_export(
217
213
  VALUE info_json = rb_funcall(flush, rb_intern("info_json"), 0);
218
214
 
219
215
  ENFORCE_TYPE(upload_timeout_milliseconds, T_FIXNUM);
220
- ENFORCE_TYPE(start_timespec_seconds, T_FIXNUM);
221
- ENFORCE_TYPE(start_timespec_nanoseconds, T_FIXNUM);
222
- ENFORCE_TYPE(finish_timespec_seconds, T_FIXNUM);
223
- ENFORCE_TYPE(finish_timespec_nanoseconds, T_FIXNUM);
224
216
  enforce_encoded_profile_instance(encoded_profile);
225
217
  ENFORCE_TYPE(code_provenance_file_name, T_STRING);
226
218
  ENFORCE_TYPE(tags_as_array, T_ARRAY);
@@ -233,28 +225,9 @@ static VALUE _native_do_export(
233
225
 
234
226
  uint64_t timeout_milliseconds = NUM2ULONG(upload_timeout_milliseconds);
235
227
 
236
- ddog_Timespec start =
237
- {.seconds = NUM2LONG(start_timespec_seconds), .nanoseconds = NUM2UINT(start_timespec_nanoseconds)};
238
- ddog_Timespec finish =
239
- {.seconds = NUM2LONG(finish_timespec_seconds), .nanoseconds = NUM2UINT(finish_timespec_nanoseconds)};
240
-
241
228
  int to_compress_length = have_code_provenance ? 1 : 0;
242
229
  ddog_prof_Exporter_File to_compress[to_compress_length];
243
- int already_compressed_length = 1; // pprof
244
- ddog_prof_Exporter_File already_compressed[already_compressed_length];
245
-
246
230
  ddog_prof_Exporter_Slice_File files_to_compress_and_export = {.ptr = to_compress, .len = to_compress_length};
247
- ddog_prof_Exporter_Slice_File files_to_export_unmodified = {.ptr = already_compressed, .len = already_compressed_length};
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
-
254
- already_compressed[0] = (ddog_prof_Exporter_File) {
255
- .name = char_slice_from_ruby_string(pprof_file_name),
256
- .file = byte_slice_from_ruby_string(pprof_data),
257
- };
258
231
 
259
232
  if (have_code_provenance) {
260
233
  to_compress[0] = (ddog_prof_Exporter_File) {
@@ -266,27 +239,25 @@ static VALUE _native_do_export(
266
239
  ddog_CharSlice internal_metadata = char_slice_from_ruby_string(internal_metadata_json);
267
240
  ddog_CharSlice info = char_slice_from_ruby_string(info_json);
268
241
 
269
- ddog_prof_Exporter_NewResult exporter_result = create_exporter(exporter_configuration, tags_as_array);
242
+ ddog_prof_ProfileExporter_Result exporter_result = create_exporter(exporter_configuration, tags_as_array);
270
243
  // Note: Do not add anything that can raise exceptions after this line, as otherwise the exporter memory will leak
271
244
 
272
245
  VALUE failure_tuple = handle_exporter_failure(exporter_result);
273
246
  if (!NIL_P(failure_tuple)) return failure_tuple;
274
247
 
275
- ddog_prof_MaybeError timeout_result = ddog_prof_Exporter_set_timeout(exporter_result.ok, timeout_milliseconds);
276
- if (timeout_result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
248
+ ddog_VoidResult timeout_result = ddog_prof_Exporter_set_timeout(&exporter_result.ok, timeout_milliseconds);
249
+ if (timeout_result.tag == DDOG_VOID_RESULT_ERR) {
277
250
  // NOTE: Seems a bit harsh to fail the upload if we can't set a timeout. OTOH, this is only expected to fail
278
251
  // if the exporter is not well built. Because such a situation should already be caught above I think it's
279
252
  // preferable to leave this here as a virtually unreachable exception rather than ignoring it.
280
- ddog_prof_Exporter_drop(exporter_result.ok);
281
- return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&timeout_result.some));
253
+ ddog_prof_Exporter_drop(&exporter_result.ok);
254
+ return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&timeout_result.err));
282
255
  }
283
256
 
284
257
  return perform_export(
285
- exporter_result.ok,
286
- start,
287
- finish,
258
+ &exporter_result.ok,
259
+ to_ddog_prof_EncodedProfile(encoded_profile),
288
260
  files_to_compress_and_export,
289
- files_to_export_unmodified,
290
261
  internal_metadata,
291
262
  info
292
263
  );
@@ -303,5 +274,7 @@ static void *call_exporter_without_gvl(void *call_args) {
303
274
 
304
275
  // Called by Ruby when it wants to interrupt call_exporter_without_gvl above, e.g. when the app wants to exit cleanly
305
276
  static void interrupt_exporter_call(void *cancel_token) {
277
+ // TODO: False here can mean two things: it was already cancelled OR it failed to cancel.
278
+ // Would be nice to change libdatadog to be able to distinguish between them...
306
279
  ddog_CancellationToken_cancel((ddog_CancellationToken *) cancel_token);
307
280
  }
@@ -363,7 +363,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
363
363
  ddog_Timespec start_timestamp = system_epoch_now_timespec();
364
364
 
365
365
  ddog_prof_Profile_NewResult slot_one_profile_result =
366
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
366
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */);
367
367
 
368
368
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
369
369
  rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
@@ -372,7 +372,7 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
372
372
  state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
373
373
 
374
374
  ddog_prof_Profile_NewResult slot_two_profile_result =
375
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, &start_timestamp);
375
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */);
376
376
 
377
377
  if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
378
378
  // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
@@ -763,7 +763,6 @@ static void *call_serialize_without_gvl(void *call_args) {
763
763
  long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
764
764
 
765
765
  profile_slot *slot_now_inactive = serializer_flip_active_and_inactive_slots(args->state);
766
-
767
766
  args->slot = slot_now_inactive;
768
767
 
769
768
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
@@ -772,7 +771,7 @@ static void *call_serialize_without_gvl(void *call_args) {
772
771
  args->heap_profile_build_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
773
772
 
774
773
  // Note: The profile gets reset by the serialize call
775
- args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
774
+ args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->slot->start_timestamp, &args->finish_timestamp);
776
775
  args->serialize_ran = true;
777
776
  args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
778
777
 
@@ -949,7 +948,7 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
949
948
  }
950
949
 
951
950
  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);
951
+ ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
953
952
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
954
953
  rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
955
954
  }
@@ -6,6 +6,8 @@
6
6
  static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
7
7
  static VALUE _native_stop(DDTRACE_UNUSED VALUE _self);
8
8
 
9
+ static bool first_init = true;
10
+
9
11
  // Used to report Ruby VM crashes.
10
12
  // Once initialized, segfaults will be reported automatically using libdatadog.
11
13
 
@@ -62,7 +64,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
62
64
  // "Process.kill('SEGV', Process.pid)" gets run.
63
65
  //
64
66
  // This actually changed in libdatadog 14, so I could see no issues with `create_alt_stack = true`, but not
65
- // overridding what Ruby set up seems a saner default to keep anyway.
67
+ // overriding what Ruby set up seems a saner default to keep anyway.
66
68
  .create_alt_stack = false,
67
69
  .use_alt_stack = true,
68
70
  .endpoint = endpoint,
@@ -92,9 +94,14 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
92
94
 
93
95
  ddog_VoidResult result =
94
96
  action == start_action ?
95
- ddog_crasht_init(config, receiver_config, metadata) :
97
+ (first_init ?
98
+ ddog_crasht_init(config, receiver_config, metadata) :
99
+ ddog_crasht_reconfigure(config, receiver_config, metadata)
100
+ ) :
96
101
  ddog_crasht_update_on_fork(config, receiver_config, metadata);
97
102
 
103
+ first_init = false;
104
+
98
105
  // Clean up before potentially raising any exceptions
99
106
  ddog_Vec_Tag_drop(tags);
100
107
  ddog_endpoint_drop(endpoint);
@@ -108,7 +115,7 @@ static VALUE _native_start_or_update_on_fork(int argc, VALUE *argv, DDTRACE_UNUS
108
115
  }
109
116
 
110
117
  static VALUE _native_stop(DDTRACE_UNUSED VALUE _self) {
111
- ddog_VoidResult result = ddog_crasht_shutdown();
118
+ ddog_VoidResult result = ddog_crasht_disable();
112
119
 
113
120
  if (result.tag == DDOG_VOID_RESULT_ERR) {
114
121
  rb_raise(rb_eRuntimeError, "Failed to stop the crash tracker: %"PRIsVALUE, get_error_details_and_drop(&result.err));
@@ -17,9 +17,9 @@ export DD_RUBY_PLATFORM=`ruby -e 'puts Gem::Platform.local.to_s'`
17
17
  mkdir -p my-libdatadog-build/$DD_RUBY_PLATFORM
18
18
  ```
19
19
 
20
- 5. Build libdatadog into this folder: `./build-profiling-ffi.sh my-libdatadog-build/$DD_RUBY_PLATFORM`
21
- 6. Tell the Ruby where to find libdatadog: `export LIBDATADOG_VENDOR_OVERRIDE=/full/path/to/my-libdatadog-build/` (Notice no platform here)
22
- 7. Run `bundle exec rake clean compile`
20
+ 5. From inside of the libdatadog repo, build libdatadog into this folder: `./build-profiling-ffi.sh my-libdatadog-build/$DD_RUBY_PLATFORM`
21
+ 6. Tell Ruby where to find libdatadog: `export LIBDATADOG_VENDOR_OVERRIDE=/full/path/to/my-libdatadog-build/` (Notice no platform here)
22
+ 7. From dd-trace-rb, run `bundle exec rake clean compile`
23
23
 
24
24
  If you additionally want to run the profiler test suite, also remember to `export DD_PROFILING_MACOS_TESTING=true` and re-run `rake clean compile`.
25
25
 
@@ -8,7 +8,7 @@ module Datadog
8
8
  module LibdatadogExtconfHelpers
9
9
  # Used to make sure the correct gem version gets loaded, as extconf.rb does not get run with "bundle exec" and thus
10
10
  # may see multiple libdatadog versions. See https://github.com/DataDog/dd-trace-rb/pull/2531 for the horror story.
11
- LIBDATADOG_VERSION = '~> 16.0.1.1.0'
11
+ LIBDATADOG_VERSION = '~> 18.1.0.1.0'
12
12
 
13
13
  # Used as an workaround for a limitation with how dynamic linking works in environments where the datadog gem and
14
14
  # libdatadog are moved after the extension gets compiled.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Datadog
6
+ module AppSec
7
+ module APISecurity
8
+ # An LRU (Least Recently Used) cache implementation that relies on the
9
+ # Ruby 1.9+ `Hash` implementation that guarantees insertion order.
10
+ #
11
+ # WARNING: This implementation is NOT thread-safe and should be used
12
+ # in a single-threaded context.
13
+ class LRUCache
14
+ extend Forwardable
15
+
16
+ def_delegators :@store, :clear, :empty?
17
+
18
+ def initialize(max_size)
19
+ raise ArgumentError, 'max_size must be an Integer' unless max_size.is_a?(Integer)
20
+ raise ArgumentError, 'max_size must be greater than 0' if max_size <= 0
21
+
22
+ @max_size = max_size
23
+ @store = {}
24
+ end
25
+
26
+ # NOTE: Accessing a key moves it to the end of the list.
27
+ def [](key)
28
+ if (entry = @store.delete(key))
29
+ @store[key] = entry
30
+ end
31
+ end
32
+
33
+ # NOTE: If the key exists, it's moved to the end of the list and
34
+ # if does not, the given block will be executed and the result
35
+ # will be stored (which will add it to the end of the list).
36
+ def fetch_or_store(key)
37
+ if (entry = @store.delete(key))
38
+ return @store[key] = entry
39
+ end
40
+
41
+ # NOTE: evict the oldest entry if store reached the maximum allowed size
42
+ @store.shift if @store.size >= @max_size
43
+
44
+ @store[key] ||= yield
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ # A namespace for API Security features.
6
+ module APISecurity
7
+ end
8
+ end
9
+ end
@@ -40,7 +40,23 @@ module Datadog
40
40
  add_all!(underflow) unless underflow.nil?
41
41
 
42
42
  # Iteratively replace items, to ensure pseudo-random replacement.
43
- overflow.each { |item| replace!(item) } unless overflow.nil?
43
+ overflow&.each { |item| replace!(item) }
44
+ end
45
+
46
+ def unshift(*items)
47
+ # TODO The existing concat implementation does not always append
48
+ # to the end of the buffer - if the buffer is full, a random
49
+ # item is deleted and the new item is added in the position of
50
+ # removed item.
51
+ # Therefore, if we want to preserve the item order, concat
52
+ # would also need to be changed to maintain order.
53
+ # With the existing implementation, the idea is to not move
54
+ # existing items around, which is what sets unshift apart from
55
+ # concat to begin with.
56
+ #
57
+ # Since this method currently delegates to +concat+, it does not
58
+ # have a matching definition in the thread-safe worker.
59
+ concat(items)
44
60
  end
45
61
 
46
62
  # Stored items are returned and the local buffer is reset.
@@ -78,7 +94,7 @@ module Datadog
78
94
  underflow = nil
79
95
  overflow = nil
80
96
 
81
- overflow_size = @max_size > 0 ? (@items.length + items.length) - @max_size : 0
97
+ overflow_size = (@max_size > 0) ? (@items.length + items.length) - @max_size : 0
82
98
 
83
99
  if overflow_size > 0
84
100
  # Items will overflow
@@ -37,8 +37,8 @@ module Datadog
37
37
  case adapter
38
38
  when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
39
39
  hostname = self.hostname
40
- hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP
41
- "#{ssl ? 'https' : 'http'}://#{hostname}:#{port}/"
40
+ hostname = "[#{hostname}]" if IPV6_REGEXP.match?(hostname)
41
+ "#{ssl ? "https" : "http"}://#{hostname}:#{port}/"
42
42
  when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
43
43
  "unix://#{uds_path}"
44
44
  else
@@ -158,7 +158,7 @@ module Datadog
158
158
  value: settings.agent.timeout_seconds,
159
159
  ),
160
160
  try_parsing_as_integer(
161
- friendly_name: "#{Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS} "\
161
+ friendly_name: "#{Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS} " \
162
162
  'environment variable',
163
163
  value: ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS],
164
164
  )
@@ -338,13 +338,13 @@ module Datadog
338
338
  log_warning(
339
339
  'Configuration mismatch: values differ between ' \
340
340
  "#{detected_configurations_in_priority_order
341
- .map { |config| "#{config.friendly_name} (#{config.value.inspect})" }.join(' and ')}" \
341
+ .map { |config| "#{config.friendly_name} (#{config.value.inspect})" }.join(" and ")}" \
342
342
  ". Using #{detected_configurations_in_priority_order.first.value.inspect} and ignoring other configuration."
343
343
  )
344
344
  end
345
345
 
346
346
  def log_warning(message)
347
- logger.warn(message) if logger
347
+ logger&.warn(message)
348
348
  end
349
349
 
350
350
  def http_scheme?(uri)