datadog 2.33.0 → 2.35.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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +20 -0
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +2 -15
  5. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  6. data/ext/datadog_profiling_native_extension/stack_recorder.c +6 -11
  7. data/lib/datadog/ai_guard/configuration.rb +1 -0
  8. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +53 -39
  9. data/lib/datadog/ai_guard/evaluation.rb +6 -1
  10. data/lib/datadog/ai_guard/ext.rb +12 -1
  11. data/lib/datadog/appsec/api_security/route_extractor.rb +3 -0
  12. data/lib/datadog/appsec/component.rb +4 -1
  13. data/lib/datadog/appsec/compressed_json.rb +2 -2
  14. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +3 -3
  15. data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
  16. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +9 -40
  17. data/lib/datadog/appsec/default_header_tags.rb +48 -0
  18. data/lib/datadog/core/configuration/components.rb +8 -1
  19. data/lib/datadog/core/configuration/settings.rb +16 -7
  20. data/lib/datadog/core/configuration/supported_configurations.rb +10 -0
  21. data/lib/datadog/core/environment/ext.rb +4 -0
  22. data/lib/datadog/core/environment/identity.rb +15 -1
  23. data/lib/datadog/core/environment/process.rb +50 -27
  24. data/lib/datadog/core/remote/client/capabilities.rb +11 -2
  25. data/lib/datadog/core/remote/transport/http/config.rb +5 -5
  26. data/lib/datadog/core/telemetry/request.rb +0 -2
  27. data/lib/datadog/core/transport/response.rb +1 -1
  28. data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +3 -2
  29. data/lib/datadog/core/utils/{array.rb → enumerable_compat.rb} +2 -2
  30. data/lib/datadog/core/utils/hash.rb +0 -23
  31. data/lib/datadog/core/utils/spawn_monkey_patch.rb +46 -16
  32. data/lib/datadog/data_streams/pathway_context.rb +3 -3
  33. data/lib/datadog/di/code_tracker.rb +43 -22
  34. data/lib/datadog/di/contrib/active_record.rb +6 -2
  35. data/lib/datadog/di/instrumenter.rb +24 -4
  36. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  37. data/lib/datadog/di/remote.rb +4 -4
  38. data/lib/datadog/di/serializer.rb +5 -5
  39. data/lib/datadog/di/utils.rb +42 -14
  40. data/lib/datadog/opentelemetry/configuration/settings.rb +65 -0
  41. data/lib/datadog/opentelemetry/ext.rb +9 -0
  42. data/lib/datadog/opentelemetry/logs.rb +98 -0
  43. data/lib/datadog/opentelemetry/metrics.rb +10 -46
  44. data/lib/datadog/opentelemetry/sdk/configurator.rb +40 -0
  45. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +37 -0
  46. data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
  47. data/lib/datadog/opentelemetry.rb +1 -0
  48. data/lib/datadog/profiling/collectors/thread_context.rb +0 -4
  49. data/lib/datadog/profiling/component.rb +3 -11
  50. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -2
  51. data/lib/datadog/profiling/stack_recorder.rb +0 -4
  52. data/lib/datadog/symbol_database/component.rb +409 -0
  53. data/lib/datadog/symbol_database/configuration.rb +2 -2
  54. data/lib/datadog/symbol_database/extractor.rb +32 -4
  55. data/lib/datadog/symbol_database/remote.rb +175 -0
  56. data/lib/datadog/symbol_database/scope_batcher.rb +8 -0
  57. data/lib/datadog/symbol_database/service_version.rb +11 -2
  58. data/lib/datadog/symbol_database/symbol.rb +6 -3
  59. data/lib/datadog/symbol_database/uploader.rb +62 -8
  60. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -1
  61. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +4 -1
  62. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -1
  63. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +4 -1
  64. data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -1
  65. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +1 -0
  66. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +8 -0
  67. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +4 -1
  68. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +4 -1
  69. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +4 -1
  70. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +4 -1
  71. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +4 -1
  72. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +4 -1
  73. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +4 -1
  74. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +4 -1
  75. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -4
  76. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -4
  77. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +1 -4
  78. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -5
  79. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +1 -5
  80. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +2 -0
  81. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  82. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -5
  83. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +2 -2
  84. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +1 -5
  85. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +1 -8
  86. data/lib/datadog/tracing/contrib/excon/middleware.rb +1 -5
  87. data/lib/datadog/tracing/contrib/ext.rb +3 -1
  88. data/lib/datadog/tracing/contrib/faraday/middleware.rb +1 -5
  89. data/lib/datadog/tracing/contrib/grape/endpoint.rb +3 -0
  90. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +1 -0
  91. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -5
  92. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -5
  93. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +1 -0
  94. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +1 -0
  95. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +1 -0
  96. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  97. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  98. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  99. data/lib/datadog/tracing/contrib/kafka/event.rb +1 -0
  100. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +5 -5
  101. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -5
  102. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +1 -5
  103. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -5
  104. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +2 -2
  105. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +1 -5
  106. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -5
  107. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +3 -0
  108. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +2 -2
  109. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -0
  110. data/lib/datadog/tracing/contrib/racecar/event.rb +1 -5
  111. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +23 -0
  112. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -0
  113. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +2 -0
  114. data/lib/datadog/tracing/contrib/rails/runner.rb +2 -0
  115. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +4 -2
  116. data/lib/datadog/tracing/contrib/redis/tags.rb +0 -5
  117. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +2 -0
  118. data/lib/datadog/tracing/contrib/resque/resque_job.rb +1 -0
  119. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +1 -5
  120. data/lib/datadog/tracing/contrib/roda/ext.rb +1 -0
  121. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +4 -1
  122. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -0
  123. data/lib/datadog/tracing/contrib/sequel/dataset.rb +1 -0
  124. data/lib/datadog/tracing/contrib/sequel/utils.rb +0 -5
  125. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -0
  126. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +1 -0
  127. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  128. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  129. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  130. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  131. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  132. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +3 -2
  133. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +1 -0
  134. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +1 -0
  135. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -0
  136. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +1 -0
  137. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +1 -5
  138. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +1 -1
  139. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -13
  140. data/lib/datadog/tracing/distributed/trace_context.rb +0 -28
  141. data/lib/datadog/tracing/metadata/ext.rb +10 -0
  142. data/lib/datadog/tracing/span_operation.rb +13 -0
  143. data/lib/datadog/tracing/trace_operation.rb +22 -0
  144. data/lib/datadog/tracing/tracer.rb +9 -0
  145. data/lib/datadog/tracing/transport/traces.rb +2 -2
  146. data/lib/datadog/version.rb +1 -1
  147. metadata +16 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff1c01535f382bb6e3de5b529bf8ec30a6deda1d1c4aba3450bb21dbd80407bf
4
- data.tar.gz: 966a01b956c9df2cd8d451df9175b66e0dbae3b7b3da7732ea998c7adca70442
3
+ metadata.gz: 4029cb3d97dee5a685f9f34027d3f46c960d452eb82339f8a167227f597881aa
4
+ data.tar.gz: 3a108d7cb90cb00326d2f9ec563e0370855161ea21c270e31cfe8bbd16b9e154
5
5
  SHA512:
6
- metadata.gz: c2d4111c1b0526122be94729577ba54d1e85fb08f2cd1ae74495d9de5bd805cb883b39c872187a5a10f2d4f67a3153d6bce2dda8192e75f4b0e808c9ab9b6a79
7
- data.tar.gz: 413cb6dc25ca7b8a79e9e85b152bfd4eed649f72ca5275a46203e30c12f893914337cbd8e5136767588b67f81eadefdc839a5a4aafebbdf5cc17e7d089798886
6
+ metadata.gz: c10991420b5026c39d0ca76529be13c276479236ebf01ab8e5050c110f687266620bfa04127f76cdb55c87b54e84c3cee5ffa39f1de46492f2dd90a58f8ed484
7
+ data.tar.gz: f7508958b880c20197ab687ff2eb98c29af51aadbc1835f8ae88a88b8858a520518aefb0d73797ae0728018fe871056c4fa4baccc86aa77b9ec0e1d20a8df298
data/CHANGELOG.md CHANGED
@@ -2,6 +2,73 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.35.0] - 2026-06-03
6
+
7
+ ### Added
8
+
9
+ * Tracing: Add `dynamic_service` SQL comment propagation mode for Database Monitoring ([#5812][])
10
+ * Tracing: Prevent Datadog-generated traffic from interfering with application metrics ([#5811][])
11
+
12
+ ### Changed
13
+
14
+ * AppSec: Improve route extraction performance for Rails applications ([#5836][])
15
+
16
+ ### Fixed
17
+
18
+ * Tracing: Restore `Datadog::Tracing::Contrib::Ext::Metadata::TAG_BASE_SERVICE` constant removed in v2.34.0 ([#5830][])
19
+
20
+ ### Removed
21
+
22
+ * Profiling: Deprecate the `profiling.advanced.timeline_enabled` setting for removal; it no longer does anything. Please remove it from `Datadog.configure` and do not set `DD_PROFILING_TIMELINE_ENABLED` ([#5750][])
23
+
24
+ ## [2.34.0] - 2026-05-27
25
+
26
+ ### Added
27
+
28
+ * Dynamic Instrumentation: Enable opt-in Symbol Database upload so Ruby services populate Live Debugger UI autocomplete when creating probes ([#5717][])
29
+ * Open Telemetry: Add OpenTelemetry logs support with OTLP export. Enable using `DD_LOGS_OTEL_ENABLED=true`; supports standard `OTEL_EXPORTER_OTLP_*` settings ([#5446][])
30
+
31
+ ### Fixed
32
+
33
+ * Core: Fix Remote configuration `TransportError` messages removing wrapper response object memory addresses ([#5762][])
34
+ * Core: Fix `TypeError` from `Process.spawn` when passing an environment Hash ([#5773][], [#5634][])
35
+ * AppSec: Prevent host application crashes when AppSec fails to initialize ([#5768][])
36
+ * Dynamic Instrumentation: Fix off-by-one in `max_capture_depth` so snapshots respect the configured nesting limit exactly ([#5753][])
37
+ * Dynamic Instrumentation: Improve line probes to match `sourceFile` case-insensitively and support Windows-style backslashes for correct installation ([#5754][])
38
+
39
+ ## [2.33.0] - 2026-05-13
40
+
41
+ ### Added
42
+
43
+ * AI Guard: Ensure client IP is always collected when AI Guard is enabled ([#5677][])
44
+ * AppSec: Add support for AWS Lambda ([#5663][])
45
+ * Tracing: Add inferred proxy spans for services behind AWS Gateway ([#5681][])
46
+ * Open Telemetry: Add support for `DD_HOSTNAME` to set trace hostname and OTel `host.name` when `DD_TRACE_REPORT_HOSTNAME` is enabled ([#5705][])
47
+
48
+ ### Changed
49
+
50
+ * Core: Collect all threads in crash reports to provide full thread context during crashes ([#5724][])
51
+ * Core: Update `libdatadog` dependency to version 33.0.0 ([#5723][])
52
+
53
+ ## [2.32.0] - 2026-05-08
54
+
55
+ ### Added
56
+
57
+ * Open Feature: Add flag evaluation metrics (`feature_flag.evaluations`) via OpenTelemetry for OpenFeature provider. ([#5599][])
58
+ * Profiling: Add metric for total time spent waiting for the GVL. ([#5569][])
59
+ * Dynamic Instrumentation: Live Debugger line probes can now target third-party and Ruby standard library code loaded before datadog gem is loaded. ([#5501][])
60
+
61
+ ### Changed
62
+
63
+ * Profiling: Print failure info when native extension setup fails ([#5657][])
64
+ * Tracing: Add parsing limits to `tracestate` and `traceparent` propagation headers and remove whitespace around list members. ([#5674][])
65
+ * Tracing: Limit extracted [baggage](https://www.w3.org/TR/2024/CR-baggage-20240530/) header parsing to 64 items and 8192 bytes. ([#5672][])
66
+
67
+ ### Fixed
68
+
69
+ * Tracing: Enforce `x-datadog-tags` propagation header size limits by byte size. ([#5687][])
70
+ * Tracing: Return empty baggage on invalid UTF-8 baggage extraction ([#5689][])
71
+
5
72
  ## [2.31.0] - 2026-04-20
6
73
 
7
74
  ### Added
@@ -3567,7 +3634,11 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3567
3634
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3568
3635
 
3569
3636
 
3570
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.31.0...master
3637
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.35.0...master
3638
+ [2.35.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.34.0...v2.35.0
3639
+ [2.34.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.33.0...v2.34.0
3640
+ [2.33.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.32.0...v2.33.0
3641
+ [2.32.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.31.0...v2.32.0
3571
3642
  [2.31.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.30.0...v2.31.0
3572
3643
  [2.30.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.29.0...v2.30.0
3573
3644
  [2.29.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.28.0...v2.29.0
@@ -5278,6 +5349,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5278
5349
  [#5434]: https://github.com/DataDog/dd-trace-rb/issues/5434
5279
5350
  [#5435]: https://github.com/DataDog/dd-trace-rb/issues/5435
5280
5351
  [#5436]: https://github.com/DataDog/dd-trace-rb/issues/5436
5352
+ [#5446]: https://github.com/DataDog/dd-trace-rb/issues/5446
5281
5353
  [#5448]: https://github.com/DataDog/dd-trace-rb/issues/5448
5282
5354
  [#5449]: https://github.com/DataDog/dd-trace-rb/issues/5449
5283
5355
  [#5461]: https://github.com/DataDog/dd-trace-rb/issues/5461
@@ -5286,15 +5358,41 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5286
5358
  [#5483]: https://github.com/DataDog/dd-trace-rb/issues/5483
5287
5359
  [#5484]: https://github.com/DataDog/dd-trace-rb/issues/5484
5288
5360
  [#5499]: https://github.com/DataDog/dd-trace-rb/issues/5499
5361
+ [#5501]: https://github.com/DataDog/dd-trace-rb/issues/5501
5289
5362
  [#5509]: https://github.com/DataDog/dd-trace-rb/issues/5509
5290
5363
  [#5531]: https://github.com/DataDog/dd-trace-rb/issues/5531
5291
5364
  [#5564]: https://github.com/DataDog/dd-trace-rb/issues/5564
5365
+ [#5569]: https://github.com/DataDog/dd-trace-rb/issues/5569
5292
5366
  [#5573]: https://github.com/DataDog/dd-trace-rb/issues/5573
5293
5367
  [#5574]: https://github.com/DataDog/dd-trace-rb/issues/5574
5294
5368
  [#5579]: https://github.com/DataDog/dd-trace-rb/issues/5579
5295
5369
  [#5580]: https://github.com/DataDog/dd-trace-rb/issues/5580
5296
5370
  [#5587]: https://github.com/DataDog/dd-trace-rb/issues/5587
5297
5371
  [#5594]: https://github.com/DataDog/dd-trace-rb/issues/5594
5372
+ [#5599]: https://github.com/DataDog/dd-trace-rb/issues/5599
5373
+ [#5634]: https://github.com/DataDog/dd-trace-rb/issues/5634
5374
+ [#5657]: https://github.com/DataDog/dd-trace-rb/issues/5657
5375
+ [#5663]: https://github.com/DataDog/dd-trace-rb/issues/5663
5376
+ [#5672]: https://github.com/DataDog/dd-trace-rb/issues/5672
5377
+ [#5674]: https://github.com/DataDog/dd-trace-rb/issues/5674
5378
+ [#5677]: https://github.com/DataDog/dd-trace-rb/issues/5677
5379
+ [#5681]: https://github.com/DataDog/dd-trace-rb/issues/5681
5380
+ [#5687]: https://github.com/DataDog/dd-trace-rb/issues/5687
5381
+ [#5689]: https://github.com/DataDog/dd-trace-rb/issues/5689
5382
+ [#5705]: https://github.com/DataDog/dd-trace-rb/issues/5705
5383
+ [#5717]: https://github.com/DataDog/dd-trace-rb/issues/5717
5384
+ [#5723]: https://github.com/DataDog/dd-trace-rb/issues/5723
5385
+ [#5724]: https://github.com/DataDog/dd-trace-rb/issues/5724
5386
+ [#5750]: https://github.com/DataDog/dd-trace-rb/issues/5750
5387
+ [#5753]: https://github.com/DataDog/dd-trace-rb/issues/5753
5388
+ [#5754]: https://github.com/DataDog/dd-trace-rb/issues/5754
5389
+ [#5762]: https://github.com/DataDog/dd-trace-rb/issues/5762
5390
+ [#5768]: https://github.com/DataDog/dd-trace-rb/issues/5768
5391
+ [#5773]: https://github.com/DataDog/dd-trace-rb/issues/5773
5392
+ [#5811]: https://github.com/DataDog/dd-trace-rb/issues/5811
5393
+ [#5812]: https://github.com/DataDog/dd-trace-rb/issues/5812
5394
+ [#5830]: https://github.com/DataDog/dd-trace-rb/issues/5830
5395
+ [#5836]: https://github.com/DataDog/dd-trace-rb/issues/5836
5298
5396
  [@AdrianLC]: https://github.com/AdrianLC
5299
5397
  [@Azure7111]: https://github.com/Azure7111
5300
5398
  [@BabyGroot]: https://github.com/BabyGroot
@@ -17,6 +17,10 @@
17
17
  #include "setup_signal_handler.h"
18
18
  #include "time_helpers.h"
19
19
 
20
+ #ifdef __APPLE__
21
+ #include "macos_sampler_thread.h"
22
+ #endif
23
+
20
24
  // Used to trigger the execution of Collectors::ThreadContext, which implements all of the sampling logic
21
25
  // itself; this class only implements the "when to do it" part.
22
26
  //
@@ -535,6 +539,14 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
535
539
 
536
540
  block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
537
541
 
542
+ #ifdef __APPLE__
543
+ // Promote the native thread that will run the sampling loop to a realtime scheduling policy so
544
+ // its periodic wake-ups are not subject to the default ~1-2ms timeshare wake latency. The matching
545
+ // demote happens below in this same function, alongside the SIGPROF unblock dance, so both per-thread
546
+ // policy changes are reverted before Ruby reuses this native thread for an unrelated Ruby thread.
547
+ promote_sampler_thread_to_realtime(MILLIS_AS_NS(state->cpu_sampling_interval_ms));
548
+ #endif
549
+
538
550
  // Release GVL, get to the actual work!
539
551
  int exception_state;
540
552
  rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
@@ -556,6 +568,14 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
556
568
  // had SIGPROF delivery blocked. :hide_the_pain_harold:
557
569
  unblock_sigprof_signal_handler_from_running_in_current_thread();
558
570
 
571
+ #ifdef __APPLE__
572
+ // Pairs with promote_sampler_thread_to_realtime above. Same reasoning as the SIGPROF unblock:
573
+ // Ruby may reuse this native thread for an unrelated Ruby thread that would otherwise inherit
574
+ // our scheduler policy. Doing it here also covers the exception path, since grab_gvl_and_sample
575
+ // can raise and unwind out of the sampling loop.
576
+ demote_sampler_thread_from_realtime();
577
+ #endif
578
+
559
579
  // Why replace and not use remove the signal handler? We do this because when a process receives a SIGPROF without
560
580
  // having an explicit signal handler set up, the process will instantly terminate with a confusing
561
581
  // "Profiling timer expired" message left behind. (This message doesn't come from us -- it's the default message for
@@ -142,8 +142,6 @@ typedef struct {
142
142
  VALUE thread_list_buffer;
143
143
  // Used to omit endpoint names (retrieved from tracer) from collected data
144
144
  bool endpoint_collection_enabled;
145
- // Used to omit timestamps / timeline events from collected data
146
- bool timeline_enabled;
147
145
  // Used to control context collection
148
146
  otel_context_enabled otel_context_enabled;
149
147
  // Used to remember where otel context is being stored after we observe it the first time
@@ -458,7 +456,6 @@ static VALUE _native_new(VALUE klass) {
458
456
  VALUE thread_list_buffer = rb_ary_new();
459
457
  state->thread_list_buffer = thread_list_buffer;
460
458
  state->endpoint_collection_enabled = true;
461
- state->timeline_enabled = true;
462
459
  state->native_filenames_enabled = false;
463
460
  state->native_filenames_cache = st_init_numtable();
464
461
  state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
@@ -492,14 +489,12 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
492
489
  VALUE max_frames = rb_hash_fetch(options, ID2SYM(rb_intern("max_frames")));
493
490
  VALUE tracer_context_key = rb_hash_fetch(options, ID2SYM(rb_intern("tracer_context_key")));
494
491
  VALUE endpoint_collection_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("endpoint_collection_enabled")));
495
- VALUE timeline_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("timeline_enabled")));
496
492
  VALUE waiting_for_gvl_threshold_ns = rb_hash_fetch(options, ID2SYM(rb_intern("waiting_for_gvl_threshold_ns")));
497
493
  VALUE otel_context_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("otel_context_enabled")));
498
494
  VALUE native_filenames_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("native_filenames_enabled")));
499
495
 
500
496
  ENFORCE_TYPE(max_frames, T_FIXNUM);
501
497
  ENFORCE_BOOLEAN(endpoint_collection_enabled);
502
- ENFORCE_BOOLEAN(timeline_enabled);
503
498
  ENFORCE_TYPE(waiting_for_gvl_threshold_ns, T_FIXNUM);
504
499
  ENFORCE_BOOLEAN(native_filenames_enabled);
505
500
 
@@ -512,7 +507,6 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
512
507
  // hash_map_per_thread_context is already initialized, nothing to do here
513
508
  state->recorder_instance = enforce_recorder_instance(recorder_instance);
514
509
  state->endpoint_collection_enabled = (endpoint_collection_enabled == Qtrue);
515
- state->timeline_enabled = (timeline_enabled == Qtrue);
516
510
  state->native_filenames_enabled = (native_filenames_enabled == Qtrue);
517
511
  if (otel_context_enabled == Qfalse || otel_context_enabled == Qnil) {
518
512
  state->otel_context_enabled = OTEL_CONTEXT_ENABLED_FALSE;
@@ -844,11 +838,7 @@ VALUE thread_context_collector_sample_after_gc(VALUE self_instance) {
844
838
  ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = label_pos};
845
839
 
846
840
  // The end_timestamp_ns is treated specially by libdatadog and that's why it's not added as a ddog_prof_Label
847
- int64_t end_timestamp_ns = 0;
848
-
849
- if (state->timeline_enabled) {
850
- end_timestamp_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, state->gc_tracking.wall_time_at_previous_gc_ns);
851
- }
841
+ int64_t end_timestamp_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, state->gc_tracking.wall_time_at_previous_gc_ns);
852
842
 
853
843
  record_placeholder_stack(
854
844
  state->recorder_instance,
@@ -1008,7 +998,7 @@ static void trigger_sample_for_thread(
1008
998
 
1009
999
  // The end_timestamp_ns is treated specially by libdatadog and that's why it's not added as a ddog_prof_Label
1010
1000
  int64_t end_timestamp_ns = 0;
1011
- if (state->timeline_enabled && current_monotonic_wall_time_ns != INVALID_TIME) {
1001
+ if (current_monotonic_wall_time_ns != INVALID_TIME) {
1012
1002
  end_timestamp_ns = monotonic_to_system_epoch_ns(&state->time_converter_state, current_monotonic_wall_time_ns);
1013
1003
  }
1014
1004
 
@@ -1166,7 +1156,6 @@ static VALUE _native_inspect(DDTRACE_UNUSED VALUE _self, VALUE collector_instanc
1166
1156
  rb_str_concat(result, rb_sprintf(" sample_count=%u", state->sample_count));
1167
1157
  rb_str_concat(result, rb_sprintf(" stats=%"PRIsVALUE, stats_as_ruby_hash(state)));
1168
1158
  rb_str_concat(result, rb_sprintf(" endpoint_collection_enabled=%"PRIsVALUE, state->endpoint_collection_enabled ? Qtrue : Qfalse));
1169
- rb_str_concat(result, rb_sprintf(" timeline_enabled=%"PRIsVALUE, state->timeline_enabled ? Qtrue : Qfalse));
1170
1159
  rb_str_concat(result, rb_sprintf(" native_filenames_enabled=%"PRIsVALUE, state->native_filenames_enabled ? Qtrue : Qfalse));
1171
1160
  // Note: `st_table_size()` is available from Ruby 3.2+ but not before
1172
1161
  rb_str_concat(result, rb_sprintf(" native_filenames_cache_size=%zu", state->native_filenames_cache->num_entries));
@@ -1994,8 +1983,6 @@ static uint64_t otel_span_id_to_uint(VALUE otel_span_id) {
1994
1983
  thread_context_collector_state *state;
1995
1984
  TypedData_Get_Struct(self_instance, thread_context_collector_state, &thread_context_collector_typed_data, state);
1996
1985
 
1997
- if (!state->timeline_enabled) raise_error(rb_eRuntimeError, "GVL profiling requires timeline to be enabled");
1998
-
1999
1986
  intptr_t gvl_waiting_at = gvl_profiling_state_thread_object_get(current_thread);
2000
1987
 
2001
1988
  if (gvl_waiting_at >= 0) {
@@ -0,0 +1,55 @@
1
+ #pragma once
2
+
3
+ #include <mach/mach.h>
4
+ #include <mach/mach_time.h>
5
+ #include <mach/thread_policy.h>
6
+ #include <pthread.h>
7
+ #include <stdio.h>
8
+
9
+ #include "time_helpers.h"
10
+
11
+ // On macOS the default scheduler wake latency for a timeshare thread is ~1-2ms,
12
+ // so nanosleep regularly overshoots a 10ms request by ~2ms. Marking the worker
13
+ // thread with THREAD_TIME_CONSTRAINT_POLICY tells the scheduler this thread has
14
+ // a periodic deadline; the kernel then wakes it close to the requested time.
15
+ //
16
+ // This only affects the sampler worker thread. We pair it with a demote call
17
+ // before the thread can be reused by Ruby for unrelated Ruby threads (see the
18
+ // SIGPROF unblock dance in _native_sampling_loop).
19
+ static inline void promote_sampler_thread_to_realtime(uint64_t period_ns) {
20
+ mach_timebase_info_data_t timebase = (mach_timebase_info_data_t) {};
21
+ mach_timebase_info(&timebase);
22
+
23
+ // ns -> mach ticks: each mach tick is (numer/denom) ns, so divide by that.
24
+ #define NS_TO_MACH_TICKS(ns) ((uint32_t) (((uint64_t)(ns) * (uint64_t) timebase.denom) / (uint64_t) timebase.numer))
25
+
26
+ struct thread_time_constraint_policy policy = {
27
+ .period = NS_TO_MACH_TICKS(period_ns),
28
+ .computation = NS_TO_MACH_TICKS(MICROS_AS_NS(200)), // 200us upper bound on the work we do per period
29
+ .constraint = NS_TO_MACH_TICKS(MILLIS_AS_NS(1)), // wake us within 1ms of the deadline
30
+ .preemptible = TRUE,
31
+ };
32
+
33
+ #undef NS_TO_MACH_TICKS
34
+
35
+ kern_return_t kr = thread_policy_set(
36
+ pthread_mach_thread_np(pthread_self()),
37
+ THREAD_TIME_CONSTRAINT_POLICY,
38
+ (thread_policy_t) &policy,
39
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT
40
+ );
41
+ if (kr != KERN_SUCCESS) {
42
+ // Non-fatal: we'll fall back to the default scheduler behavior (overshoot ~2ms).
43
+ fprintf(stderr, "[ddtrace] Failed to set real-time policy on profiler sampler thread (kr=%d); sample cadence may be imprecise\n", kr);
44
+ }
45
+ }
46
+
47
+ static inline void demote_sampler_thread_from_realtime(void) {
48
+ struct thread_standard_policy policy = {.no_data = 0};
49
+ thread_policy_set(
50
+ pthread_mach_thread_np(pthread_self()),
51
+ THREAD_STANDARD_POLICY,
52
+ (thread_policy_t) &policy,
53
+ THREAD_STANDARD_POLICY_COUNT
54
+ );
55
+ }
@@ -420,14 +420,12 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
420
420
  VALUE heap_samples_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_samples_enabled")));
421
421
  VALUE heap_size_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_size_enabled")));
422
422
  VALUE heap_sample_every = rb_hash_fetch(options, ID2SYM(rb_intern("heap_sample_every")));
423
- VALUE timeline_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("timeline_enabled")));
424
423
  VALUE heap_clean_after_gc_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_clean_after_gc_enabled")));
425
424
 
426
425
  ENFORCE_BOOLEAN(alloc_samples_enabled);
427
426
  ENFORCE_BOOLEAN(heap_samples_enabled);
428
427
  ENFORCE_BOOLEAN(heap_size_enabled);
429
428
  ENFORCE_TYPE(heap_sample_every, T_FIXNUM);
430
- ENFORCE_BOOLEAN(timeline_enabled);
431
429
  ENFORCE_BOOLEAN(heap_clean_after_gc_enabled);
432
430
 
433
431
  stack_recorder_state *state;
@@ -440,8 +438,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
440
438
  uint8_t requested_values_count = ALL_VALUE_TYPES_COUNT -
441
439
  (alloc_samples_enabled == Qtrue? 0 : 2) -
442
440
  (heap_samples_enabled == Qtrue ? 0 : 1) -
443
- (heap_size_enabled == Qtrue ? 0 : 1) -
444
- (timeline_enabled == Qtrue ? 0 : 1);
441
+ (heap_size_enabled == Qtrue ? 0 : 1);
445
442
 
446
443
  if (requested_values_count == ALL_VALUE_TYPES_COUNT) return Qtrue; // Nothing to do, this is the default
447
444
 
@@ -467,6 +464,10 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
467
464
  enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_TIME;
468
465
  state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
469
466
 
467
+ // TIMELINE is always enabled
468
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_TIMELINE;
469
+ state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
470
+
470
471
  if (alloc_samples_enabled == Qtrue) {
471
472
  enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES;
472
473
  state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
@@ -500,13 +501,6 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
500
501
  state->heap_recorder = NULL;
501
502
  }
502
503
 
503
- if (timeline_enabled == Qtrue) {
504
- enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_TIMELINE;
505
- state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
506
- } else {
507
- state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
508
- }
509
-
510
504
  ddog_prof_Profile_drop(&state->profile_slot_one.profile);
511
505
  ddog_prof_Profile_drop(&state->profile_slot_two.profile);
512
506
 
@@ -639,6 +633,7 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
639
633
  .values = (ddog_Slice_I64) {.ptr = metric_values, .len = state->enabled_values_count},
640
634
  .labels = labels.labels
641
635
  },
636
+ /* To disable end_timestamp_ns to get aggregated profiles in pprof, replace the below with `0` */
642
637
  labels.end_timestamp_ns
643
638
  );
644
639
 
@@ -71,6 +71,7 @@ module Datadog
71
71
  option :app_key do |o|
72
72
  o.type :string, nilable: true
73
73
  o.env Ext::ENV_APP_KEY
74
+ o.skip_telemetry true
74
75
  end
75
76
 
76
77
  # Request timeout in milliseconds.
@@ -11,71 +11,85 @@ module Datadog
11
11
  module Rack
12
12
  # AI Guard Rack middleware.
13
13
  #
14
- # Inserted into the middleware stack right after
15
- # Datadog::Tracing::Contrib::Rack::TraceMiddleware (i.e. nested inside
16
- # it). This ordering matters: on the way out of the request, AI Guard's
17
- # `ensure` block unwinds *before* Tracing's ensure, while Tracing's
18
- # request span is still live. We need that, because Tracing's ensure
19
- # calls `request_span.finish`, which builds a frozen `Span` snapshot of
20
- # the meta hash — any `set_tag` call after that point mutates the
21
- # `SpanOperation` but never reaches the exported `Span`.
14
+ # At request entry the middleware stores some request attributes for
15
+ # on the active trace under the `_dd.ai_guard.` prefix.
22
16
  #
23
- # So while the span is still active, we tag `http.client_ip` and
24
- # `network.client.ip` on it — but only when an AI Guard span was
25
- # actually recorded during the request.
17
+ # Later when AI Guard evaluation is performed, those attributes are
18
+ # mirrored on AI Guard span.
26
19
  class RequestMiddleware
27
- NETWORK_CLIENT_IP_TAG = "network.client.ip"
28
-
29
20
  def initialize(app, opt = {})
30
21
  @app = app
31
22
  end
32
23
 
33
24
  def call(env)
25
+ trace = Datadog::Tracing.active_trace
26
+ return @app.call(env) unless trace
27
+
28
+ store_anomaly_detection_tags!(trace, env)
29
+
34
30
  @app.call(env)
35
31
  ensure
36
- tag_client_ip(env) if consume_ai_guard_executed_flag
32
+ # @type var trace: Datadog::Tracing::TraceSegment?
33
+ # Steep: https://github.com/soutaro/steep/issues/919
34
+ if trace
35
+ tag_client_ip_on_request_span!(trace) if ai_guard_executed?(trace)
36
+
37
+ clean_up_ai_guard_temp_tags!(trace)
38
+ end
37
39
  end
38
40
 
39
41
  private
40
42
 
41
- # AI Guard's evaluation flow sets `ai_guard.executed` on the trace
42
- # whenever an AI Guard span is created during the request. We read
43
- # it here to know whether to tag client IP, then clear it so the
44
- # internal flag does not propagate to the exported trace.
45
- #
46
- # `Tracing.active_trace` is publicly typed as `TraceSegment?` but at
47
- # runtime returns a `TraceOperation`, which exposes `get_tag` and
48
- # `clear_tag`. Pre-existing sig mismatch — hence the steep:ignore.
49
43
  # steep:ignore:start
50
- def consume_ai_guard_executed_flag
51
- trace = Datadog::Tracing.active_trace
52
- return false unless trace
53
- return false unless trace.get_tag(Datadog::AIGuard::Ext::SERVICE_ENTRY_EXECUTED_TAG) == "1"
44
+ def store_anomaly_detection_tags!(trace, env)
45
+ remote_ip = env["REMOTE_ADDR"]
46
+ trace.set_tag(Datadog::AIGuard::Ext::TRACE_NETWORK_CLIENT_IP_TAG, remote_ip) if remote_ip
47
+
48
+ headers = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
49
+ resolved_client_ip = Datadog::Tracing::ClientIp.extract_client_ip(headers, remote_ip)
50
+ trace.set_tag(Datadog::AIGuard::Ext::TRACE_HTTP_CLIENT_IP_TAG, resolved_client_ip) if resolved_client_ip
51
+
52
+ user_agent = env["HTTP_USER_AGENT"]
53
+ trace.set_tag(Datadog::AIGuard::Ext::TRACE_HTTP_USERAGENT_TAG, user_agent) if user_agent
54
+ rescue => e
55
+ Datadog::AIGuard.telemetry&.report(e, description: "AI Guard: failed to get request attributes")
56
+ end
57
+ # steep:ignore:end
58
+
59
+ # steep:ignore:start
60
+ def clean_up_ai_guard_temp_tags!(trace)
61
+ Ext::TRACE_ANOMALY_DETECTION_TAGS.each do |tag|
62
+ trace.clear_tag(tag)
63
+ end
54
64
 
55
- trace.clear_tag(Datadog::AIGuard::Ext::SERVICE_ENTRY_EXECUTED_TAG)
56
- true
65
+ trace.clear_tag(Datadog::AIGuard::Ext::TRACE_EXECUTED_TAG)
57
66
  end
58
67
  # steep:ignore:end
59
68
 
60
- def tag_client_ip(env)
69
+ # AI Guard's evaluation flow sets `_dd.ai_guard.executed` on the
70
+ # trace whenever an AI Guard span is created during the request.
71
+ # steep:ignore:start
72
+ def ai_guard_executed?(trace)
73
+ trace.get_tag(Datadog::AIGuard::Ext::TRACE_EXECUTED_TAG) == "1"
74
+ end
75
+ # steep:ignore:end
76
+
77
+ # steep:ignore:start
78
+ def tag_client_ip_on_request_span!(trace)
61
79
  span = Datadog::Tracing.active_span
62
80
  return unless span
63
81
 
64
- if span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
65
- headers = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
66
- Datadog::Tracing::ClientIp.set_client_ip_tag!(
67
- span,
68
- headers: headers,
69
- remote_ip: env["REMOTE_ADDR"]
70
- )
82
+ client_ip = trace.get_tag(Datadog::AIGuard::Ext::TRACE_HTTP_CLIENT_IP_TAG)
83
+ if client_ip && span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
84
+ span.set_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP, client_ip)
71
85
  end
72
86
 
73
- if env["REMOTE_ADDR"] && span.get_tag(NETWORK_CLIENT_IP_TAG).nil?
74
- span.set_tag(NETWORK_CLIENT_IP_TAG, env["REMOTE_ADDR"])
75
- end
87
+ network_client_ip = trace.get_tag(Datadog::AIGuard::Ext::TRACE_NETWORK_CLIENT_IP_TAG)
88
+ span["network.client.ip"] = network_client_ip if network_client_ip
76
89
  rescue => e
77
90
  Datadog::AIGuard.telemetry&.report(e, description: "AI Guard: failed to tag client IP on root span")
78
91
  end
92
+ # steep:ignore:end
79
93
  end
80
94
  end
81
95
  end
@@ -16,7 +16,12 @@ module Datadog
16
16
  Tracing::Sampling::Ext::Decision::AI_GUARD
17
17
  )
18
18
  trace.set_tag(Ext::EVENT_TAG, true)
19
- trace.set_tag(Ext::SERVICE_ENTRY_EXECUTED_TAG, "1")
19
+ trace.set_tag(Ext::TRACE_EXECUTED_TAG, "1")
20
+
21
+ Ext::TRACE_ANOMALY_DETECTION_TAGS.each do |tag|
22
+ value = trace.get_tag(tag)
23
+ span.set_tag(tag, value) if value
24
+ end
20
25
 
21
26
  if (last_message = messages.last)
22
27
  if last_message.tool_call
@@ -11,8 +11,19 @@ module Datadog
11
11
  REASON_TAG = "ai_guard.reason"
12
12
  BLOCKED_TAG = "ai_guard.blocked"
13
13
  EVENT_TAG = "ai_guard.event"
14
- SERVICE_ENTRY_EXECUTED_TAG = "_dd.ai_guard.executed"
14
+
15
15
  METASTRUCT_TAG = "ai_guard"
16
+
17
+ TRACE_EXECUTED_TAG = "_dd.ai_guard.executed"
18
+ TRACE_HTTP_USERAGENT_TAG = "_dd.ai_guard.http.useragent"
19
+ TRACE_HTTP_CLIENT_IP_TAG = "_dd.ai_guard.http.client_ip"
20
+ TRACE_NETWORK_CLIENT_IP_TAG = "_dd.ai_guard.network.client.ip"
21
+
22
+ TRACE_ANOMALY_DETECTION_TAGS = [
23
+ TRACE_HTTP_USERAGENT_TAG,
24
+ TRACE_HTTP_CLIENT_IP_TAG,
25
+ TRACE_NETWORK_CLIENT_IP_TAG
26
+ ].freeze
16
27
  end
17
28
  end
18
29
  end
@@ -15,6 +15,7 @@ module Datadog
15
15
  RAILS_ROUTES_KEY = 'action_dispatch.routes'
16
16
  RAILS_PATH_PARAMS_KEY = 'action_dispatch.request.path_parameters'
17
17
  RAILS_FORMAT_SUFFIX = '(.:format)'
18
+ DATADOG_RAILS_ROUTE_KEY = 'datadog.action_dispatch.route'
18
19
 
19
20
  # HACK: We rely on the fact that each contrib will modify `request.env`
20
21
  # and store information sufficient to compute the canonical
@@ -55,6 +56,8 @@ module Datadog
55
56
  elsif request.env.key?(SINATRA_ROUTE_KEY)
56
57
  pattern = request.env[SINATRA_ROUTE_KEY].split(SINATRA_ROUTE_SEPARATOR, 2)[1]
57
58
  "#{request.script_name}#{pattern}"
59
+ elsif request.env.key?(DATADOG_RAILS_ROUTE_KEY)
60
+ request.env[DATADOG_RAILS_ROUTE_KEY].path.spec.to_s.delete_suffix(RAILS_FORMAT_SUFFIX)
58
61
  elsif request.env.key?(RAILS_ROUTE_KEY)
59
62
  request.env[RAILS_ROUTE_KEY].path.spec.to_s.delete_suffix(RAILS_FORMAT_SUFFIX)
60
63
  elsif request.env.key?(RAILS_ROUTE_URI_PATTERN_KEY)
@@ -46,7 +46,10 @@ module Datadog
46
46
 
47
47
  security_engine = SecurityEngine::Engine.new(appsec_settings: settings.appsec, telemetry: telemetry)
48
48
  new(security_engine: security_engine)
49
- rescue => e
49
+ # NOTE: At this point we should capture all possible exceptions and
50
+ # gracefully fail component initialization, preventing propagation
51
+ # into the host application code.
52
+ rescue Exception => e # standard:disable Lint/RescueException
50
53
  Datadog.logger.warn("AppSec is disabled: #{e.class}: #{e.message}; there may be additional logged errors above")
51
54
 
52
55
  # Not reporting to telemetry here because some of the rescued exceptions
@@ -4,7 +4,7 @@ require 'json'
4
4
  require 'zlib'
5
5
  require 'stringio'
6
6
 
7
- require_relative '../core/utils/base64'
7
+ require_relative '../core/utils/base64_codec'
8
8
 
9
9
  module Datadog
10
10
  module AppSec
@@ -27,7 +27,7 @@ module Datadog
27
27
  end
28
28
 
29
29
  private_class_method def self.compress_and_encode(payload)
30
- Core::Utils::Base64.strict_encode64(
30
+ Core::Utils::Base64Codec.strict_encode64(
31
31
  Zlib.gzip(payload, level: Zlib::BEST_SPEED, strategy: Zlib::DEFAULT_STRATEGY)
32
32
  )
33
33
  rescue Zlib::Error, TypeError => e
@@ -4,7 +4,7 @@ require 'uri'
4
4
 
5
5
  require_relative '../../utils/http/media_type'
6
6
  require_relative '../../utils/http/body'
7
- require_relative '../../../core/utils/base64'
7
+ require_relative '../../../core/utils/base64_codec'
8
8
  require_relative '../../../core/header_collection'
9
9
  require_relative '../../../tracing/client_ip'
10
10
 
@@ -42,7 +42,7 @@ module Datadog
42
42
 
43
43
  headers = parse_headers(payload)
44
44
  data = {
45
- 'server.response.status' => payload['statusCode']&.to_s,
45
+ 'server.response.status' => payload['status_code']&.to_s,
46
46
  'server.response.headers' => headers,
47
47
  'server.response.headers.no_cookies' => headers.dup.tap { |h| h.delete('set-cookie') }
48
48
  }
@@ -94,7 +94,7 @@ module Datadog
94
94
  body = payload['body']
95
95
  return unless body
96
96
 
97
- body = Core::Utils::Base64.strict_decode64(body) if payload['base64_encoded']
97
+ body = Core::Utils::Base64Codec.strict_decode64(body) if payload['base64_encoded']
98
98
 
99
99
  content_type = headers['content-type']
100
100
  return unless content_type
@@ -13,7 +13,7 @@ module Datadog
13
13
  'cloudfront-viewer-ja3-fingerprint',
14
14
  'content-type',
15
15
  'user-agent',
16
- 'x-amzn-trace-Id',
16
+ 'x-amzn-trace-id',
17
17
  'x-appgw-trace-id',
18
18
  'x-cloud-trace-context',
19
19
  'x-sigsci-requestid',