datadog 2.0.0.beta1 → 2.0.0.beta2

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 (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