datadog 2.0.0.beta1 → 2.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +125 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +32 -12
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +5 -2
  5. data/ext/datadog_profiling_native_extension/heap_recorder.c +45 -3
  6. data/ext/datadog_profiling_native_extension/heap_recorder.h +7 -1
  7. data/ext/datadog_profiling_native_extension/http_transport.c +5 -5
  8. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +1 -1
  9. data/ext/datadog_profiling_native_extension/stack_recorder.c +7 -9
  10. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -13
  11. data/lib/datadog/appsec/event.rb +2 -2
  12. data/lib/datadog/core/configuration/components.rb +2 -1
  13. data/lib/datadog/core/configuration/option.rb +7 -5
  14. data/lib/datadog/core/configuration/settings.rb +38 -14
  15. data/lib/datadog/core/configuration.rb +20 -4
  16. data/lib/datadog/core/environment/platform.rb +7 -1
  17. data/lib/datadog/core/remote/client/capabilities.rb +2 -1
  18. data/lib/datadog/core/remote/transport/http/config.rb +5 -5
  19. data/lib/datadog/core/telemetry/client.rb +18 -10
  20. data/lib/datadog/core/telemetry/emitter.rb +9 -13
  21. data/lib/datadog/core/telemetry/event.rb +247 -57
  22. data/lib/datadog/core/telemetry/ext.rb +1 -0
  23. data/lib/datadog/core/telemetry/heartbeat.rb +1 -3
  24. data/lib/datadog/core/telemetry/http/ext.rb +4 -1
  25. data/lib/datadog/core/telemetry/http/transport.rb +9 -4
  26. data/lib/datadog/core/telemetry/request.rb +59 -0
  27. data/lib/datadog/core/utils/base64.rb +22 -0
  28. data/lib/datadog/opentelemetry/sdk/span_processor.rb +1 -1
  29. data/lib/datadog/opentelemetry/sdk/trace/span.rb +3 -17
  30. data/lib/datadog/profiling/collectors/code_provenance.rb +10 -4
  31. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +25 -0
  32. data/lib/datadog/profiling/component.rb +23 -15
  33. data/lib/datadog/profiling/load_native_extension.rb +14 -1
  34. data/lib/datadog/profiling.rb +11 -0
  35. data/lib/datadog/tracing/contrib/action_pack/integration.rb +1 -1
  36. data/lib/datadog/tracing/contrib/action_view/integration.rb +1 -1
  37. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  38. data/lib/datadog/tracing/contrib/active_support/integration.rb +1 -1
  39. data/lib/datadog/tracing/contrib/grape/endpoint.rb +43 -5
  40. data/lib/datadog/tracing/correlation.rb +3 -4
  41. data/lib/datadog/tracing/sampling/matcher.rb +23 -3
  42. data/lib/datadog/tracing/sampling/rule.rb +18 -2
  43. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  44. data/lib/datadog/tracing/span.rb +7 -2
  45. data/lib/datadog/tracing/span_link.rb +86 -0
  46. data/lib/datadog/tracing/trace_operation.rb +12 -0
  47. data/lib/datadog/tracing/tracer.rb +4 -3
  48. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -1
  49. data/lib/datadog/tracing/utils.rb +16 -0
  50. data/lib/datadog/version.rb +1 -1
  51. metadata +7 -30
  52. data/lib/datadog/core/telemetry/collector.rb +0 -248
  53. data/lib/datadog/core/telemetry/v1/app_event.rb +0 -59
  54. data/lib/datadog/core/telemetry/v1/application.rb +0 -94
  55. data/lib/datadog/core/telemetry/v1/configuration.rb +0 -27
  56. data/lib/datadog/core/telemetry/v1/dependency.rb +0 -45
  57. data/lib/datadog/core/telemetry/v1/host.rb +0 -59
  58. data/lib/datadog/core/telemetry/v1/install_signature.rb +0 -38
  59. data/lib/datadog/core/telemetry/v1/integration.rb +0 -66
  60. data/lib/datadog/core/telemetry/v1/product.rb +0 -36
  61. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +0 -108
  62. data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +0 -41
  63. data/lib/datadog/core/telemetry/v2/request.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b20af2904b022a99ddd6b86a2b0f7fc0dc6aaff6be5e6ce33562e1f33a1f720
4
- data.tar.gz: 5c4881d78dbfc4c07a830c1328609f62fa2595dad2e5a6565432c67ed693a9b9
3
+ metadata.gz: c98feb8dee5da784f25da37c6989ed32929eeac8189590c0aa6763303ac5076d
4
+ data.tar.gz: 9324b595c888213affe2a342c4be4dcb49643328cdf3ab0aab9616c41a9b5dd6
5
5
  SHA512:
6
- metadata.gz: 40aa8b141fcc9c7faf85d92bef1493e87b5f4ffbee1c9f4c86c32329dd2a243e4fc1f63f668a074e4214bbc77df336853927bb8c57e3728bc4a216987c128ed7
7
- data.tar.gz: 02be99a9ca062989e97c56daaf85c6558f04c4dadc72ff6ff79da3d75a0965113f02a7f6fabef30fa618924e4c62099fc7bcdbcd83fd7719aeae21bcbbfc4175
6
+ metadata.gz: f4ee11c65fe76ee70b5c85d67de21a5feadc6938976a0869ae230a6d3a28c38d5ed2c8516633d2046f7fb311ed19d62de9a46317e70a1ade2d4147c139693a44
7
+ data.tar.gz: 05b8bb6ec82ddb7cd7bce5e461c5e48416df745a23cfcc724d7b2cc0de86e047a4b0e8b7d26dbf9f0b62a12f94dc0492937da3676adb97e458fb41a501a005f3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,72 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.0.0.beta2] - 2024-04-18
6
+
7
+ ### Added
8
+
9
+ * Add Agent configuration option: `timeout_seconds`, `uds_path`, and `use_ssl` ([#3350][])
10
+ * Tracing: Add lightweight log correlation generation ([#3486][])
11
+ * Tracing: Add span links ([#3546][])
12
+ * Tracing: Add `span_remote` field to `TraceDigest` ([#3516][])
13
+ * Tracing: Add `_dd.parent_id` to `tracestate` ([#3488][])
14
+ * Tracing: Allow `RateSampler` with zero sampling rate ([#3295][])
15
+ * Grape: Add `on_error` settings ([#3370][])
16
+
17
+ ### Changed
18
+
19
+ * Rename gem from `ddtrace` to `datadog` ([#3490][])
20
+ * Require Ruby `>= 2.5` ([#3291][])
21
+ * Frozen string literals ([#3392][])
22
+ * Startup logs emit when reconfigures ([#3441][])
23
+ * Enhance validation for configuration ([#3332][], [#3326][])
24
+ * Tracing: Propagation style configuration becomes case-insensitive ([#3299][])
25
+ * Tracing: Return string for `#trace_id` and `#span_id` from `Correlation::Identifier` ([#3322][])
26
+ * `Elasticsearch`: Replace instance configuration from `client` to `transport` instance ([#3399][])
27
+ * `Grape`: Change `error_statuses` settings to `error_status_codes` ([#3370][])
28
+ * `GraphQL`: Instrument with `GraphQL::Tracing::DataDogTrace` and more ([#3409][], [#3417][], [#3388][])
29
+ * `Rack`: Change http proxy span pattern ([#3369][])
30
+ * `Sidekiq`: Remove `tag_args` option and worker specific configuration ([#3396][], [#3402][])
31
+ * Integrations: Rename `error_handler` settings to `on_error` ([#3341][])
32
+ *
33
+ ### Fixed
34
+
35
+ * Tracing: Fix `error_status_codes` options ([#3344][])
36
+
37
+ ### Removed
38
+
39
+ * Profiling: Remove `bin/ddtracerb` ([#3506][])
40
+ * Ci-app: Remove `datadog-ci` gem dependency ([#3288][])
41
+ * Tracing: Remove `SpanOperation` aliases ([#3330][])
42
+ * Tracing: Remove `b3` style from default propagation ([#3293][])
43
+ * Tracing: Minimize sampling API ([#3423][])
44
+ * Tracing: Remove `client_ip` disabled env ([#3404][])
45
+ * Tracing: Remove `use` alias for `instrument` ([#3403][])
46
+ * Tracing: `OpenTracing`, `qless` removed ([#3398][], [#3443][])
47
+ * `Net/Http`: Remove `Datadog::Tracing::Contrib::HTTP::Instrumentation.after_request` ([#3367][])
48
+ * `Rails`: Drop support for Rails 3 ([#3324][])
49
+ * `Rails`: Remove `exception_controller` option ([#3243][])
50
+ * Remove constants, methods and more ([#3401][], [#3336][], [#3454][], [#3338][], [#3335][], [#3298][], [#3297][], [#3309][], [#3294][], [#3325][], [#3300][])
51
+
52
+ ## [1.22.0] - 2024-04-16
53
+
54
+ ### Added
55
+
56
+ * Tracing: Add sampling rules by trace resouce and tags ([#3587][], [#3585][])
57
+ * Appsec: Add WAF vendor header support ([#3528][])
58
+
59
+ ### Changed
60
+
61
+ * Upgrade `Telemetry` to V2 ([#3551][])
62
+ * Upgrade to libdatadog 7 ([#3536][])
63
+ * Profiling: Enable Garbage Collection profiling by default ([#3558][])
64
+ * Profiling: Skip heap samples with age 0 ([#3573][])
65
+ * Profiling: Support falling back into extension directory when loading profiler ([#3582][])
66
+
67
+ ### Fixed
68
+
69
+ * Appsec: Fix MIME-style newlines with strict base64 encoding ([#3565][])
70
+
5
71
  ## [2.0.0.beta1] - 2024-03-22
6
72
 
7
73
  Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v2.0.0.beta1
@@ -2784,7 +2850,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
2784
2850
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
2785
2851
 
2786
2852
 
2787
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.21.1...master
2853
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.22.0...master
2854
+ [2.0.0.beta2]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.beta1...v2.0.0.beta2
2855
+ [1.22.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.21.1...v1.22.0
2788
2856
  [2.0.0.beta1]: https://github.com/DataDog/dd-trace-rb/compare/v1.21.1...v2.0.0.beta1
2789
2857
  [1.21.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.21.0...v1.21.1
2790
2858
  [1.21.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.20.0...v1.21.0
@@ -4007,6 +4075,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4007
4075
  [#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
4008
4076
  [#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
4009
4077
  [#3242]: https://github.com/DataDog/dd-trace-rb/issues/3242
4078
+ [#3243]: https://github.com/DataDog/dd-trace-rb/issues/3243
4010
4079
  [#3248]: https://github.com/DataDog/dd-trace-rb/issues/3248
4011
4080
  [#3252]: https://github.com/DataDog/dd-trace-rb/issues/3252
4012
4081
  [#3255]: https://github.com/DataDog/dd-trace-rb/issues/3255
@@ -4025,21 +4094,43 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4025
4094
  [#3284]: https://github.com/DataDog/dd-trace-rb/issues/3284
4026
4095
  [#3286]: https://github.com/DataDog/dd-trace-rb/issues/3286
4027
4096
  [#3287]: https://github.com/DataDog/dd-trace-rb/issues/3287
4097
+ [#3288]: https://github.com/DataDog/dd-trace-rb/issues/3288
4028
4098
  [#3289]: https://github.com/DataDog/dd-trace-rb/issues/3289
4099
+ [#3291]: https://github.com/DataDog/dd-trace-rb/issues/3291
4100
+ [#3293]: https://github.com/DataDog/dd-trace-rb/issues/3293
4101
+ [#3294]: https://github.com/DataDog/dd-trace-rb/issues/3294
4102
+ [#3295]: https://github.com/DataDog/dd-trace-rb/issues/3295
4103
+ [#3297]: https://github.com/DataDog/dd-trace-rb/issues/3297
4104
+ [#3298]: https://github.com/DataDog/dd-trace-rb/issues/3298
4105
+ [#3299]: https://github.com/DataDog/dd-trace-rb/issues/3299
4106
+ [#3300]: https://github.com/DataDog/dd-trace-rb/issues/3300
4029
4107
  [#3303]: https://github.com/DataDog/dd-trace-rb/issues/3303
4030
4108
  [#3307]: https://github.com/DataDog/dd-trace-rb/issues/3307
4031
4109
  [#3308]: https://github.com/DataDog/dd-trace-rb/issues/3308
4110
+ [#3309]: https://github.com/DataDog/dd-trace-rb/issues/3309
4032
4111
  [#3310]: https://github.com/DataDog/dd-trace-rb/issues/3310
4033
4112
  [#3313]: https://github.com/DataDog/dd-trace-rb/issues/3313
4034
4113
  [#3315]: https://github.com/DataDog/dd-trace-rb/issues/3315
4035
4114
  [#3316]: https://github.com/DataDog/dd-trace-rb/issues/3316
4036
4115
  [#3317]: https://github.com/DataDog/dd-trace-rb/issues/3317
4037
4116
  [#3320]: https://github.com/DataDog/dd-trace-rb/issues/3320
4117
+ [#3322]: https://github.com/DataDog/dd-trace-rb/issues/3322
4118
+ [#3324]: https://github.com/DataDog/dd-trace-rb/issues/3324
4119
+ [#3325]: https://github.com/DataDog/dd-trace-rb/issues/3325
4120
+ [#3326]: https://github.com/DataDog/dd-trace-rb/issues/3326
4038
4121
  [#3328]: https://github.com/DataDog/dd-trace-rb/issues/3328
4039
4122
  [#3329]: https://github.com/DataDog/dd-trace-rb/issues/3329
4123
+ [#3330]: https://github.com/DataDog/dd-trace-rb/issues/3330
4124
+ [#3332]: https://github.com/DataDog/dd-trace-rb/issues/3332
4040
4125
  [#3333]: https://github.com/DataDog/dd-trace-rb/issues/3333
4126
+ [#3335]: https://github.com/DataDog/dd-trace-rb/issues/3335
4127
+ [#3336]: https://github.com/DataDog/dd-trace-rb/issues/3336
4128
+ [#3338]: https://github.com/DataDog/dd-trace-rb/issues/3338
4129
+ [#3341]: https://github.com/DataDog/dd-trace-rb/issues/3341
4130
+ [#3344]: https://github.com/DataDog/dd-trace-rb/issues/3344
4041
4131
  [#3345]: https://github.com/DataDog/dd-trace-rb/issues/3345
4042
4132
  [#3349]: https://github.com/DataDog/dd-trace-rb/issues/3349
4133
+ [#3350]: https://github.com/DataDog/dd-trace-rb/issues/3350
4043
4134
  [#3352]: https://github.com/DataDog/dd-trace-rb/issues/3352
4044
4135
  [#3354]: https://github.com/DataDog/dd-trace-rb/issues/3354
4045
4136
  [#3356]: https://github.com/DataDog/dd-trace-rb/issues/3356
@@ -4049,13 +4140,28 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4049
4140
  [#3362]: https://github.com/DataDog/dd-trace-rb/issues/3362
4050
4141
  [#3365]: https://github.com/DataDog/dd-trace-rb/issues/3365
4051
4142
  [#3366]: https://github.com/DataDog/dd-trace-rb/issues/3366
4143
+ [#3367]: https://github.com/DataDog/dd-trace-rb/issues/3367
4144
+ [#3369]: https://github.com/DataDog/dd-trace-rb/issues/3369
4145
+ [#3370]: https://github.com/DataDog/dd-trace-rb/issues/3370
4052
4146
  [#3373]: https://github.com/DataDog/dd-trace-rb/issues/3373
4053
4147
  [#3374]: https://github.com/DataDog/dd-trace-rb/issues/3374
4054
4148
  [#3386]: https://github.com/DataDog/dd-trace-rb/issues/3386
4149
+ [#3388]: https://github.com/DataDog/dd-trace-rb/issues/3388
4150
+ [#3392]: https://github.com/DataDog/dd-trace-rb/issues/3392
4055
4151
  [#3395]: https://github.com/DataDog/dd-trace-rb/issues/3395
4152
+ [#3396]: https://github.com/DataDog/dd-trace-rb/issues/3396
4153
+ [#3398]: https://github.com/DataDog/dd-trace-rb/issues/3398
4154
+ [#3399]: https://github.com/DataDog/dd-trace-rb/issues/3399
4056
4155
  [#3400]: https://github.com/DataDog/dd-trace-rb/issues/3400
4156
+ [#3401]: https://github.com/DataDog/dd-trace-rb/issues/3401
4157
+ [#3402]: https://github.com/DataDog/dd-trace-rb/issues/3402
4158
+ [#3403]: https://github.com/DataDog/dd-trace-rb/issues/3403
4159
+ [#3404]: https://github.com/DataDog/dd-trace-rb/issues/3404
4057
4160
  [#3408]: https://github.com/DataDog/dd-trace-rb/issues/3408
4161
+ [#3409]: https://github.com/DataDog/dd-trace-rb/issues/3409
4162
+ [#3417]: https://github.com/DataDog/dd-trace-rb/issues/3417
4058
4163
  [#3420]: https://github.com/DataDog/dd-trace-rb/issues/3420
4164
+ [#3423]: https://github.com/DataDog/dd-trace-rb/issues/3423
4059
4165
  [#3426]: https://github.com/DataDog/dd-trace-rb/issues/3426
4060
4166
  [#3427]: https://github.com/DataDog/dd-trace-rb/issues/3427
4061
4167
  [#3428]: https://github.com/DataDog/dd-trace-rb/issues/3428
@@ -4064,24 +4170,42 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4064
4170
  [#3438]: https://github.com/DataDog/dd-trace-rb/issues/3438
4065
4171
  [#3439]: https://github.com/DataDog/dd-trace-rb/issues/3439
4066
4172
  [#3440]: https://github.com/DataDog/dd-trace-rb/issues/3440
4173
+ [#3441]: https://github.com/DataDog/dd-trace-rb/issues/3441
4174
+ [#3443]: https://github.com/DataDog/dd-trace-rb/issues/3443
4175
+ [#3454]: https://github.com/DataDog/dd-trace-rb/issues/3454
4067
4176
  [#3455]: https://github.com/DataDog/dd-trace-rb/issues/3455
4068
4177
  [#3463]: https://github.com/DataDog/dd-trace-rb/issues/3463
4069
4178
  [#3466]: https://github.com/DataDog/dd-trace-rb/issues/3466
4070
4179
  [#3468]: https://github.com/DataDog/dd-trace-rb/issues/3468
4071
4180
  [#3473]: https://github.com/DataDog/dd-trace-rb/issues/3473
4181
+ [#3486]: https://github.com/DataDog/dd-trace-rb/issues/3486
4182
+ [#3488]: https://github.com/DataDog/dd-trace-rb/issues/3488
4183
+ [#3490]: https://github.com/DataDog/dd-trace-rb/issues/3490
4072
4184
  [#3491]: https://github.com/DataDog/dd-trace-rb/issues/3491
4073
4185
  [#3495]: https://github.com/DataDog/dd-trace-rb/issues/3495
4074
4186
  [#3501]: https://github.com/DataDog/dd-trace-rb/issues/3501
4075
4187
  [#3502]: https://github.com/DataDog/dd-trace-rb/issues/3502
4076
4188
  [#3503]: https://github.com/DataDog/dd-trace-rb/issues/3503
4189
+ [#3506]: https://github.com/DataDog/dd-trace-rb/issues/3506
4077
4190
  [#3511]: https://github.com/DataDog/dd-trace-rb/issues/3511
4191
+ [#3516]: https://github.com/DataDog/dd-trace-rb/issues/3516
4078
4192
  [#3518]: https://github.com/DataDog/dd-trace-rb/issues/3518
4079
4193
  [#3519]: https://github.com/DataDog/dd-trace-rb/issues/3519
4080
4194
  [#3520]: https://github.com/DataDog/dd-trace-rb/issues/3520
4081
4195
  [#3523]: https://github.com/DataDog/dd-trace-rb/issues/3523
4196
+ [#3528]: https://github.com/DataDog/dd-trace-rb/issues/3528
4082
4197
  [#3531]: https://github.com/DataDog/dd-trace-rb/issues/3531
4083
4198
  [#3535]: https://github.com/DataDog/dd-trace-rb/issues/3535
4199
+ [#3536]: https://github.com/DataDog/dd-trace-rb/issues/3536
4084
4200
  [#3539]: https://github.com/DataDog/dd-trace-rb/issues/3539
4201
+ [#3546]: https://github.com/DataDog/dd-trace-rb/issues/3546
4202
+ [#3551]: https://github.com/DataDog/dd-trace-rb/issues/3551
4203
+ [#3558]: https://github.com/DataDog/dd-trace-rb/issues/3558
4204
+ [#3565]: https://github.com/DataDog/dd-trace-rb/issues/3565
4205
+ [#3573]: https://github.com/DataDog/dd-trace-rb/issues/3573
4206
+ [#3582]: https://github.com/DataDog/dd-trace-rb/issues/3582
4207
+ [#3585]: https://github.com/DataDog/dd-trace-rb/issues/3585
4208
+ [#3587]: https://github.com/DataDog/dd-trace-rb/issues/3587
4085
4209
  [@AdrianLC]: https://github.com/AdrianLC
4086
4210
  [@Azure7111]: https://github.com/Azure7111
4087
4211
  [@BabyGroot]: https://github.com/BabyGroot
@@ -96,6 +96,7 @@ struct cpu_and_wall_time_worker_state {
96
96
  bool no_signals_workaround_enabled;
97
97
  bool dynamic_sampling_rate_enabled;
98
98
  bool allocation_profiling_enabled;
99
+ bool skip_idle_samples_for_testing;
99
100
  VALUE self_instance;
100
101
  VALUE thread_context_collector_instance;
101
102
  VALUE idle_sampling_helper_instance;
@@ -132,6 +133,8 @@ struct cpu_and_wall_time_worker_state {
132
133
  unsigned int signal_handler_enqueued_sample;
133
134
  // How many times the signal handler was called from the wrong thread
134
135
  unsigned int signal_handler_wrong_thread;
136
+ // How many times we actually tried to interrupt a thread for sampling
137
+ unsigned int interrupt_thread_attempts;
135
138
 
136
139
  // # Stats for the results of calling rb_postponed_job_register_one
137
140
  // The same function was already waiting to be executed
@@ -177,7 +180,8 @@ static VALUE _native_initialize(
177
180
  VALUE no_signals_workaround_enabled,
178
181
  VALUE dynamic_sampling_rate_enabled,
179
182
  VALUE dynamic_sampling_rate_overhead_target_percentage,
180
- VALUE allocation_profiling_enabled
183
+ VALUE allocation_profiling_enabled,
184
+ VALUE skip_idle_samples_for_testing
181
185
  );
182
186
  static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
183
187
  static VALUE _native_sampling_loop(VALUE self, VALUE instance);
@@ -272,14 +276,16 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
272
276
  // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
273
277
  rb_define_alloc_func(collectors_cpu_and_wall_time_worker_class, _native_new);
274
278
 
275
- rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, 8);
279
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, 9);
276
280
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_sampling_loop", _native_sampling_loop, 1);
277
281
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop, 2);
278
282
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
279
283
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stats", _native_stats, 1);
280
284
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stats_reset_not_thread_safe", _native_stats_reset_not_thread_safe, 1);
281
285
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_allocation_count", _native_allocation_count, 0);
286
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_is_running?", _native_is_running, 1);
282
287
  rb_define_singleton_method(testing_module, "_native_current_sigprof_signal_handler", _native_current_sigprof_signal_handler, 0);
288
+ // TODO: Remove `_native_is_running` from `testing_module` once `prof-correctness` has been updated to not need it
283
289
  rb_define_singleton_method(testing_module, "_native_is_running?", _native_is_running, 1);
284
290
  rb_define_singleton_method(testing_module, "_native_install_testing_signal_handler", _native_install_testing_signal_handler, 0);
285
291
  rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
@@ -315,6 +321,7 @@ static VALUE _native_new(VALUE klass) {
315
321
  state->no_signals_workaround_enabled = false;
316
322
  state->dynamic_sampling_rate_enabled = true;
317
323
  state->allocation_profiling_enabled = false;
324
+ state->skip_idle_samples_for_testing = false;
318
325
  state->thread_context_collector_instance = Qnil;
319
326
  state->idle_sampling_helper_instance = Qnil;
320
327
  state->owner_thread = Qnil;
@@ -350,13 +357,15 @@ static VALUE _native_initialize(
350
357
  VALUE no_signals_workaround_enabled,
351
358
  VALUE dynamic_sampling_rate_enabled,
352
359
  VALUE dynamic_sampling_rate_overhead_target_percentage,
353
- VALUE allocation_profiling_enabled
360
+ VALUE allocation_profiling_enabled,
361
+ VALUE skip_idle_samples_for_testing
354
362
  ) {
355
363
  ENFORCE_BOOLEAN(gc_profiling_enabled);
356
364
  ENFORCE_BOOLEAN(no_signals_workaround_enabled);
357
365
  ENFORCE_BOOLEAN(dynamic_sampling_rate_enabled);
358
366
  ENFORCE_TYPE(dynamic_sampling_rate_overhead_target_percentage, T_FLOAT);
359
367
  ENFORCE_BOOLEAN(allocation_profiling_enabled);
368
+ ENFORCE_BOOLEAN(skip_idle_samples_for_testing)
360
369
 
361
370
  struct cpu_and_wall_time_worker_state *state;
362
371
  TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
@@ -365,6 +374,7 @@ static VALUE _native_initialize(
365
374
  state->no_signals_workaround_enabled = (no_signals_workaround_enabled == Qtrue);
366
375
  state->dynamic_sampling_rate_enabled = (dynamic_sampling_rate_enabled == Qtrue);
367
376
  state->allocation_profiling_enabled = (allocation_profiling_enabled == Qtrue);
377
+ state->skip_idle_samples_for_testing = (skip_idle_samples_for_testing == Qtrue);
368
378
 
369
379
  double total_overhead_target_percentage = NUM2DBL(dynamic_sampling_rate_overhead_target_percentage);
370
380
  if (!state->allocation_profiling_enabled) {
@@ -616,17 +626,23 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
616
626
  // Note that reading the GVL owner and sending them a signal is a race -- the Ruby VM keeps on executing while
617
627
  // we're doing this, so we may still not signal the correct thread from time to time, but our signal handler
618
628
  // includes a check to see if it got called in the right thread
629
+ state->stats.interrupt_thread_attempts++;
619
630
  pthread_kill(owner.owner, SIGPROF);
620
631
  } else {
621
- // If no thread owns the Global VM Lock, the application is probably idle at the moment. We still want to sample
622
- // so we "ask a friend" (the IdleSamplingHelper component) to grab the GVL and simulate getting a SIGPROF.
623
- //
624
- // In a previous version of the code, we called `grab_gvl_and_sample` directly BUT this was problematic because
625
- // Ruby may concurrently get busy and so the CpuAndWallTimeWorker would be blocked in line to acquire the GVL
626
- // for an uncontrolled amount of time. (This can still happen to the IdleSamplingHelper, but the
627
- // CpuAndWallTimeWorker will still be free to interrupt the Ruby VM and keep sampling for the entire blocking period).
628
- state->stats.trigger_simulated_signal_delivery_attempts++;
629
- idle_sampling_helper_request_action(state->idle_sampling_helper_instance, grab_gvl_and_sample);
632
+ if (state->skip_idle_samples_for_testing) {
633
+ // This was added to make sure our tests don't accidentally pass due to idle samples. Specifically, if we
634
+ // comment out the thread interruption code inside `if (owner.valid)` above, our tests should not pass!
635
+ } else {
636
+ // If no thread owns the Global VM Lock, the application is probably idle at the moment. We still want to sample
637
+ // so we "ask a friend" (the IdleSamplingHelper component) to grab the GVL and simulate getting a SIGPROF.
638
+ //
639
+ // In a previous version of the code, we called `grab_gvl_and_sample` directly BUT this was problematic because
640
+ // Ruby may concurrently get busy and so the CpuAndWallTimeWorker would be blocked in line to acquire the GVL
641
+ // for an uncontrolled amount of time. (This can still happen to the IdleSamplingHelper, but the
642
+ // CpuAndWallTimeWorker will still be free to interrupt the Ruby VM and keep sampling for the entire blocking period).
643
+ state->stats.trigger_simulated_signal_delivery_attempts++;
644
+ idle_sampling_helper_request_action(state->idle_sampling_helper_instance, grab_gvl_and_sample);
645
+ }
630
646
  }
631
647
  }
632
648
 
@@ -737,6 +753,9 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
737
753
  if (state->gc_profiling_enabled) rb_tracepoint_enable(state->gc_tracepoint);
738
754
  if (state->allocation_profiling_enabled) rb_tracepoint_enable(state->object_allocation_tracepoint);
739
755
 
756
+ // Flag the profiler as running before we release the GVL, in case anyone's waiting to know about it
757
+ rb_funcall(instance, rb_intern("signal_running"), 0);
758
+
740
759
  rb_thread_call_without_gvl(run_sampling_trigger_loop, state, interrupt_sampling_trigger_loop, state);
741
760
 
742
761
  // If we stopped sampling due to an exception, re-raise it (now in the worker thread)
@@ -943,6 +962,7 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
943
962
  ID2SYM(rb_intern("postponed_job_success")), /* => */ UINT2NUM(state->stats.postponed_job_success),
944
963
  ID2SYM(rb_intern("postponed_job_full")), /* => */ UINT2NUM(state->stats.postponed_job_full),
945
964
  ID2SYM(rb_intern("postponed_job_unknown_result")), /* => */ UINT2NUM(state->stats.postponed_job_unknown_result),
965
+ ID2SYM(rb_intern("interrupt_thread_attempts")), /* => */ UINT2NUM(state->stats.interrupt_thread_attempts),
946
966
 
947
967
  // CPU Stats
948
968
  ID2SYM(rb_intern("cpu_sampled")), /* => */ UINT2NUM(state->stats.cpu_sampled),
@@ -621,11 +621,14 @@ bool thread_context_collector_on_gc_finish(VALUE self_instance) {
621
621
  // Let the caller know if it should schedule a flush or not. Returning true every time would cause a lot of overhead
622
622
  // on the application (see GC tracking introduction at the top of the file), so instead we try to accumulate a few
623
623
  // samples first.
624
- bool finished_major_gc = gc_profiling_has_major_gc_finished();
625
624
  bool over_flush_time_treshold =
626
625
  (wall_time_at_finish_ns - state->gc_tracking.wall_time_at_last_flushed_gc_event_ns) >= TIME_BETWEEN_GC_EVENTS_NS;
627
626
 
628
- return finished_major_gc || over_flush_time_treshold;
627
+ if (over_flush_time_treshold) {
628
+ return true;
629
+ } else {
630
+ return gc_profiling_has_major_gc_finished();
631
+ }
629
632
  }
630
633
 
631
634
  // This function gets called after one or more GC work steps (calls to on_gc_start/on_gc_finish).
@@ -10,6 +10,13 @@
10
10
  #define CAN_APPLY_GC_FORCE_RECYCLE_BUG_WORKAROUND
11
11
  #endif
12
12
 
13
+ // Minimum age (in GC generations) of heap objects we want to include in heap
14
+ // recorder iterations. Object with age 0 represent objects that have yet to undergo
15
+ // a GC and, thus, may just be noise/trash at instant of iteration and are usually not
16
+ // relevant for heap profiles as the great majority should be trivially reclaimed
17
+ // during the next GC.
18
+ #define ITERATION_MIN_AGE 1
19
+
13
20
  // A compact representation of a stacktrace frame for a heap allocation.
14
21
  typedef struct {
15
22
  char *name;
@@ -137,6 +144,11 @@ struct heap_recorder {
137
144
  // mutation of the data so iteration can occur without acquiring a lock.
138
145
  // NOTE: Contrary to object_records, this table has no ownership of its data.
139
146
  st_table *object_records_snapshot;
147
+ // The GC gen/epoch/count in which we prepared the current iteration.
148
+ //
149
+ // This enables us to calculate the age of iterated objects in the above snapshot by
150
+ // comparing it against an object's alloc_gen.
151
+ size_t iteration_gen;
140
152
 
141
153
  // Data for a heap recording that was started but not yet ended
142
154
  recording active_recording;
@@ -353,6 +365,8 @@ void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
353
365
  return;
354
366
  }
355
367
 
368
+ heap_recorder->iteration_gen = rb_gc_count();
369
+
356
370
  if (heap_recorder->object_records_snapshot != NULL) {
357
371
  // we could trivially handle this but we raise to highlight and catch unexpected usages.
358
372
  rb_raise(rb_eRuntimeError, "New heap recorder iteration prepared without the previous one having been finished.");
@@ -459,6 +473,13 @@ static int st_object_record_entry_free(DDTRACE_UNUSED st_data_t key, st_data_t v
459
473
  return ST_DELETE;
460
474
  }
461
475
 
476
+ // Check to see if an object should not be included in a heap recorder iteration.
477
+ // This centralizes the checking logic to ensure it's equally applied between
478
+ // preparation and iteration codepaths.
479
+ static inline bool should_exclude_from_iteration(object_record *obj_record) {
480
+ return obj_record->object_data.gen_age < ITERATION_MIN_AGE;
481
+ }
482
+
462
483
  static int st_object_record_update(st_data_t key, st_data_t value, st_data_t extra_arg) {
463
484
  long obj_id = (long) key;
464
485
  object_record *record = (object_record*) value;
@@ -466,6 +487,19 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
466
487
 
467
488
  VALUE ref;
468
489
 
490
+ size_t iteration_gen = recorder->iteration_gen;
491
+ size_t alloc_gen = record->object_data.alloc_gen;
492
+ // Guard against potential overflows given unsigned types here.
493
+ record->object_data.gen_age = alloc_gen < iteration_gen ? iteration_gen - alloc_gen : 0;
494
+
495
+ if (should_exclude_from_iteration(record)) {
496
+ // If an object won't be included in the current iteration, there's
497
+ // no point checking for liveness or updating its size, so exit early.
498
+ // NOTE: This means that there should be an equivalent check during actual
499
+ // iteration otherwise we'd iterate/expose stale object data.
500
+ return ST_CONTINUE;
501
+ }
502
+
469
503
  if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) {
470
504
  // Id no longer associated with a valid ref. Need to delete this object record!
471
505
  on_committed_object_record_cleanup(recorder, record);
@@ -525,8 +559,16 @@ static int st_object_records_iterate(DDTRACE_UNUSED st_data_t key, st_data_t val
525
559
  const heap_stack *stack = record->heap_record->stack;
526
560
  iteration_context *context = (iteration_context*) extra;
527
561
 
528
- ddog_prof_Location *locations = context->heap_recorder->reusable_locations;
562
+ const heap_recorder *recorder = context->heap_recorder;
563
+
564
+ if (should_exclude_from_iteration(record)) {
565
+ // Skip objects that should not be included in iteration
566
+ // NOTE: This matches the short-circuiting condition in st_object_record_update
567
+ // and prevents iteration over stale objects.
568
+ return ST_CONTINUE;
569
+ }
529
570
 
571
+ ddog_prof_Location *locations = recorder->reusable_locations;
530
572
  for (uint16_t i = 0; i < stack->frames_len; i++) {
531
573
  const heap_frame *frame = &stack->frames[i];
532
574
  ddog_prof_Location *location = &locations[i];
@@ -725,9 +767,9 @@ void object_record_free(object_record *record) {
725
767
 
726
768
  VALUE object_record_inspect(object_record *record) {
727
769
  heap_frame top_frame = record->heap_record->stack->frames[0];
728
- VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%s:%d alloc_gen=%zu ",
770
+ VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%s:%d alloc_gen=%zu gen_age=%zu ",
729
771
  record->obj_id, record->object_data.weight, record->object_data.size, top_frame.filename,
730
- (int) top_frame.line, record->object_data.alloc_gen);
772
+ (int) top_frame.line, record->object_data.alloc_gen, record->object_data.gen_age);
731
773
 
732
774
  const char *class = record->object_data.class;
733
775
  if (class != NULL) {
@@ -27,7 +27,9 @@ typedef struct live_object_data {
27
27
  // could be seen as being representative of 50 objects.
28
28
  unsigned int weight;
29
29
 
30
- // Size of this object on last flush/update.
30
+ // Size of this object in memory.
31
+ // NOTE: This only gets updated during heap_recorder_prepare_iteration and only
32
+ // for those objects that meet the minimum iteration age requirements.
31
33
  size_t size;
32
34
 
33
35
  // The class of the object that we're tracking.
@@ -39,6 +41,10 @@ typedef struct live_object_data {
39
41
  // This enables us to calculate the age of this object in terms of GC executions.
40
42
  size_t alloc_gen;
41
43
 
44
+ // The age of this object in terms of GC generations.
45
+ // NOTE: This only gets updated during heap_recorder_prepare_iteration
46
+ size_t gen_age;
47
+
42
48
  // Whether this object was previously seen as being frozen. If this is the case,
43
49
  // we'll skip any further size updates since frozen objects are supposed to be
44
50
  // immutable.
@@ -30,7 +30,7 @@ inline static ddog_ByteSlice byte_slice_from_ruby_string(VALUE string);
30
30
  static VALUE _native_validate_exporter(VALUE self, VALUE exporter_configuration);
31
31
  static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration, VALUE tags_as_array);
32
32
  static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_result);
33
- static ddog_Endpoint endpoint_from(VALUE exporter_configuration);
33
+ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration);
34
34
  static ddog_Vec_Tag convert_tags(VALUE tags_as_array);
35
35
  static void safely_log_failure_to_process_tag(ddog_Vec_Tag tags, VALUE err_details);
36
36
  static VALUE _native_do_export(
@@ -94,7 +94,7 @@ static ddog_prof_Exporter_NewResult create_exporter(VALUE exporter_configuration
94
94
 
95
95
  // This needs to be called BEFORE convert_tags since it can raise an exception and thus cause the ddog_Vec_Tag
96
96
  // to be leaked.
97
- ddog_Endpoint endpoint = endpoint_from(exporter_configuration);
97
+ ddog_prof_Endpoint endpoint = endpoint_from(exporter_configuration);
98
98
 
99
99
  ddog_Vec_Tag tags = convert_tags(tags_as_array);
100
100
 
@@ -116,7 +116,7 @@ static VALUE handle_exporter_failure(ddog_prof_Exporter_NewResult exporter_resul
116
116
  rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&exporter_result.err));
117
117
  }
118
118
 
119
- static ddog_Endpoint endpoint_from(VALUE exporter_configuration) {
119
+ static ddog_prof_Endpoint endpoint_from(VALUE exporter_configuration) {
120
120
  ENFORCE_TYPE(exporter_configuration, T_ARRAY);
121
121
 
122
122
  ID working_mode = SYM2ID(rb_ary_entry(exporter_configuration, 0)); // SYM2ID verifies its input so we can do this safely
@@ -131,12 +131,12 @@ static ddog_Endpoint endpoint_from(VALUE exporter_configuration) {
131
131
  ENFORCE_TYPE(site, T_STRING);
132
132
  ENFORCE_TYPE(api_key, T_STRING);
133
133
 
134
- return ddog_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
134
+ return ddog_prof_Endpoint_agentless(char_slice_from_ruby_string(site), char_slice_from_ruby_string(api_key));
135
135
  } else { // agent_id
136
136
  VALUE base_url = rb_ary_entry(exporter_configuration, 1);
137
137
  ENFORCE_TYPE(base_url, T_STRING);
138
138
 
139
- return ddog_Endpoint_agent(char_slice_from_ruby_string(base_url));
139
+ return ddog_prof_Endpoint_agent(char_slice_from_ruby_string(base_url));
140
140
  }
141
141
  }
142
142
 
@@ -15,7 +15,7 @@ module Datadog
15
15
  # The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on debase-ruby_core_source
16
16
  CAN_USE_MJIT_HEADER = RUBY_VERSION.start_with?('2.6', '2.7', '3.0.', '3.1.', '3.2.')
17
17
 
18
- LIBDATADOG_VERSION = '~> 6.0.0.2.0'
18
+ LIBDATADOG_VERSION = '~> 7.0.0.1.0'
19
19
 
20
20
  def self.fail_install_if_missing_extension?
21
21
  ENV[ENV_FAIL_INSTALL_IF_MISSING_EXTENSION].to_s.strip.downcase == 'true'
@@ -196,7 +196,6 @@ struct call_serialize_without_gvl_arguments {
196
196
  // Set by caller
197
197
  struct stack_recorder_state *state;
198
198
  ddog_Timespec finish_timestamp;
199
- size_t gc_count_before_serialize;
200
199
 
201
200
  // Set by callee
202
201
  ddog_prof_Profile *profile;
@@ -489,7 +488,6 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
489
488
  struct call_serialize_without_gvl_arguments args = {
490
489
  .state = state,
491
490
  .finish_timestamp = finish_timestamp,
492
- .gc_count_before_serialize = rb_gc_count(),
493
491
  .serialize_ran = false
494
492
  };
495
493
 
@@ -613,8 +611,6 @@ typedef struct heap_recorder_iteration_context {
613
611
 
614
612
  bool error;
615
613
  char error_msg[MAX_LEN_HEAP_ITERATION_ERROR_MSG];
616
-
617
- size_t profile_gen;
618
614
  } heap_recorder_iteration_context;
619
615
 
620
616
  static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteration_data iteration_data, void *extra_arg) {
@@ -643,7 +639,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
643
639
  }
644
640
  labels[label_offset++] = (ddog_prof_Label) {
645
641
  .key = DDOG_CHARSLICE_C("gc gen age"),
646
- .num = context->profile_gen - object_data->alloc_gen,
642
+ .num = object_data->gen_age,
647
643
  };
648
644
 
649
645
  ddog_prof_Profile_Result result = ddog_prof_Profile_add(
@@ -670,13 +666,12 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
670
666
  return true;
671
667
  }
672
668
 
673
- static void build_heap_profile_without_gvl(struct stack_recorder_state *state, ddog_prof_Profile *profile, size_t gc_count_before_serialize) {
669
+ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, ddog_prof_Profile *profile) {
674
670
  heap_recorder_iteration_context iteration_context = {
675
671
  .state = state,
676
672
  .profile = profile,
677
673
  .error = false,
678
674
  .error_msg = {0},
679
- .profile_gen = gc_count_before_serialize,
680
675
  };
681
676
  bool iterated = heap_recorder_for_each_live_object(state->heap_recorder, add_heap_sample_to_active_profile_without_gvl, (void*) &iteration_context);
682
677
  // We wait until we're out of the iteration to grab the gvl and raise. This is important because during
@@ -698,7 +693,7 @@ static void *call_serialize_without_gvl(void *call_args) {
698
693
 
699
694
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
700
695
  // without needing to race with the active sampler
701
- build_heap_profile_without_gvl(args->state, args->profile, args->gc_count_before_serialize);
696
+ build_heap_profile_without_gvl(args->state, args->profile);
702
697
 
703
698
  // Note: The profile gets reset by the serialize call
704
699
  args->result = ddog_prof_Profile_serialize(args->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
@@ -918,10 +913,13 @@ static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recor
918
913
  #pragma GCC diagnostic push
919
914
  // rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
920
915
  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
916
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
921
917
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
922
918
  // It SHOULD NOT be used for other purposes.
923
919
  static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
924
- rb_gc_force_recycle(obj);
920
+ #ifdef HAVE_WORKING_RB_GC_FORCE_RECYCLE
921
+ rb_gc_force_recycle(obj);
922
+ #endif
925
923
  return Qnil;
926
924
  }
927
925
  #pragma GCC diagnostic pop