datadog 2.33.0 → 2.34.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +20 -0
  4. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  5. data/lib/datadog/appsec/component.rb +4 -1
  6. data/lib/datadog/appsec/compressed_json.rb +2 -2
  7. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +3 -3
  8. data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
  9. data/lib/datadog/core/configuration/components.rb +8 -1
  10. data/lib/datadog/core/configuration/settings.rb +6 -1
  11. data/lib/datadog/core/configuration/supported_configurations.rb +10 -0
  12. data/lib/datadog/core/environment/ext.rb +4 -0
  13. data/lib/datadog/core/environment/identity.rb +15 -1
  14. data/lib/datadog/core/environment/process.rb +48 -27
  15. data/lib/datadog/core/remote/client/capabilities.rb +11 -2
  16. data/lib/datadog/core/remote/transport/http/config.rb +5 -5
  17. data/lib/datadog/core/telemetry/request.rb +0 -2
  18. data/lib/datadog/core/transport/response.rb +1 -1
  19. data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +3 -2
  20. data/lib/datadog/core/utils/hash.rb +0 -23
  21. data/lib/datadog/core/utils/spawn_monkey_patch.rb +46 -16
  22. data/lib/datadog/data_streams/pathway_context.rb +3 -3
  23. data/lib/datadog/di/code_tracker.rb +43 -22
  24. data/lib/datadog/di/contrib/active_record.rb +6 -2
  25. data/lib/datadog/di/instrumenter.rb +24 -4
  26. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  27. data/lib/datadog/di/remote.rb +4 -4
  28. data/lib/datadog/di/serializer.rb +5 -5
  29. data/lib/datadog/di/utils.rb +42 -14
  30. data/lib/datadog/opentelemetry/configuration/settings.rb +65 -0
  31. data/lib/datadog/opentelemetry/ext.rb +9 -0
  32. data/lib/datadog/opentelemetry/logs.rb +98 -0
  33. data/lib/datadog/opentelemetry/metrics.rb +10 -46
  34. data/lib/datadog/opentelemetry/sdk/configurator.rb +40 -0
  35. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +37 -0
  36. data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
  37. data/lib/datadog/opentelemetry.rb +1 -0
  38. data/lib/datadog/symbol_database/component.rb +409 -0
  39. data/lib/datadog/symbol_database/configuration.rb +2 -2
  40. data/lib/datadog/symbol_database/extractor.rb +29 -1
  41. data/lib/datadog/symbol_database/remote.rb +175 -0
  42. data/lib/datadog/symbol_database/scope_batcher.rb +8 -0
  43. data/lib/datadog/symbol_database/service_version.rb +11 -2
  44. data/lib/datadog/symbol_database/symbol.rb +6 -3
  45. data/lib/datadog/symbol_database/uploader.rb +62 -8
  46. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +8 -0
  47. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +0 -4
  48. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +0 -4
  49. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +0 -4
  50. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +0 -5
  51. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +0 -5
  52. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +0 -5
  53. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +0 -5
  54. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +0 -8
  55. data/lib/datadog/tracing/contrib/excon/middleware.rb +0 -5
  56. data/lib/datadog/tracing/contrib/ext.rb +2 -3
  57. data/lib/datadog/tracing/contrib/faraday/middleware.rb +0 -5
  58. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +0 -5
  59. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +0 -5
  60. data/lib/datadog/tracing/contrib/http/instrumentation.rb +0 -5
  61. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +0 -5
  62. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +0 -5
  63. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +0 -5
  64. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +0 -5
  65. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +0 -5
  66. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +0 -5
  67. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +0 -5
  68. data/lib/datadog/tracing/contrib/racecar/event.rb +0 -5
  69. data/lib/datadog/tracing/contrib/redis/tags.rb +0 -5
  70. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +0 -5
  71. data/lib/datadog/tracing/contrib/sequel/utils.rb +0 -5
  72. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +0 -5
  73. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -13
  74. data/lib/datadog/tracing/distributed/trace_context.rb +0 -28
  75. data/lib/datadog/tracing/metadata/ext.rb +3 -0
  76. data/lib/datadog/tracing/span_operation.rb +13 -0
  77. data/lib/datadog/tracing/trace_operation.rb +22 -0
  78. data/lib/datadog/tracing/tracer.rb +6 -0
  79. data/lib/datadog/version.rb +1 -1
  80. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff1c01535f382bb6e3de5b529bf8ec30a6deda1d1c4aba3450bb21dbd80407bf
4
- data.tar.gz: 966a01b956c9df2cd8d451df9175b66e0dbae3b7b3da7732ea998c7adca70442
3
+ metadata.gz: aa3ddf8f18dda4b503c654911332fb5cdc50356d4fa8223d43a993be204618ac
4
+ data.tar.gz: d917e203823268d36fc01c086969052160a6afdfb2c3cfdc29a081d8ce23a384
5
5
  SHA512:
6
- metadata.gz: c2d4111c1b0526122be94729577ba54d1e85fb08f2cd1ae74495d9de5bd805cb883b39c872187a5a10f2d4f67a3153d6bce2dda8192e75f4b0e808c9ab9b6a79
7
- data.tar.gz: 413cb6dc25ca7b8a79e9e85b152bfd4eed649f72ca5275a46203e30c12f893914337cbd8e5136767588b67f81eadefdc839a5a4aafebbdf5cc17e7d089798886
6
+ metadata.gz: 4fda14c3e26b82d5b93e3581acfa939d9ac3be695c2ad26ca720b4873127f05e949dc78f0cb1b8922ed87cd114881e9191fa36463cd86f3dcbf5d969da0da932
7
+ data.tar.gz: ca53286a2a5ad436e460ede12148faed98b9904d0823715954f602cdf292cb03966cde1f96dd2c227581b1ccd814c30fdd0236dfaa1903f59a87ae2873f40dd0
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.34.0] - 2026-05-27
6
+
7
+ ### Added
8
+
9
+ * Dynamic Instrumentation: Enable Symbol Database upload so Ruby services populate Live Debugger UI autocomplete when creating probes ([#5717][])
10
+ * Open Telemetry: Add OpenTelemetry logs support with OTLP export. Enable using `DD_LOGS_OTEL_ENABLED=true`; supports standard `OTEL_EXPORTER_OTLP_*` settings ([#5446][])
11
+
12
+ ### Changed
13
+
14
+ * Dynamic Instrumentation: Improve request latency under load by throttling symbol database extraction CPU usage during background processing ([#5776][])
15
+
16
+ ### Fixed
17
+
18
+ * Core: Fix Remote configuration `TransportError` messages removing wrapper response object memory addresses ([#5762][])
19
+ * Core: Fix `TypeError` from `Process.spawn` when passing an environment Hash ([#5773][], [#5634][])
20
+ * AppSec: Prevent host application crashes when AppSec fails to initialize ([#5768][])
21
+ * Dynamic Instrumentation: Fix off-by-one in `max_capture_depth` so snapshots respect the configured nesting limit exactly ([#5753][])
22
+ * Dynamic Instrumentation: Improve line probes to match `sourceFile` case-insensitively and support Windows-style backslashes for correct installation ([#5754][])
23
+
5
24
  ## [2.31.0] - 2026-04-20
6
25
 
7
26
  ### Added
@@ -3567,7 +3586,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
3567
3586
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
3568
3587
 
3569
3588
 
3570
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.31.0...master
3589
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.34.0...master
3590
+ [2.34.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.33.0...v2.34.0
3571
3591
  [2.31.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.30.0...v2.31.0
3572
3592
  [2.30.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.29.0...v2.30.0
3573
3593
  [2.29.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.28.0...v2.29.0
@@ -5278,6 +5298,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5278
5298
  [#5434]: https://github.com/DataDog/dd-trace-rb/issues/5434
5279
5299
  [#5435]: https://github.com/DataDog/dd-trace-rb/issues/5435
5280
5300
  [#5436]: https://github.com/DataDog/dd-trace-rb/issues/5436
5301
+ [#5446]: https://github.com/DataDog/dd-trace-rb/issues/5446
5281
5302
  [#5448]: https://github.com/DataDog/dd-trace-rb/issues/5448
5282
5303
  [#5449]: https://github.com/DataDog/dd-trace-rb/issues/5449
5283
5304
  [#5461]: https://github.com/DataDog/dd-trace-rb/issues/5461
@@ -5295,6 +5316,14 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
5295
5316
  [#5580]: https://github.com/DataDog/dd-trace-rb/issues/5580
5296
5317
  [#5587]: https://github.com/DataDog/dd-trace-rb/issues/5587
5297
5318
  [#5594]: https://github.com/DataDog/dd-trace-rb/issues/5594
5319
+ [#5634]: https://github.com/DataDog/dd-trace-rb/issues/5634
5320
+ [#5717]: https://github.com/DataDog/dd-trace-rb/issues/5717
5321
+ [#5753]: https://github.com/DataDog/dd-trace-rb/issues/5753
5322
+ [#5754]: https://github.com/DataDog/dd-trace-rb/issues/5754
5323
+ [#5762]: https://github.com/DataDog/dd-trace-rb/issues/5762
5324
+ [#5768]: https://github.com/DataDog/dd-trace-rb/issues/5768
5325
+ [#5773]: https://github.com/DataDog/dd-trace-rb/issues/5773
5326
+ [#5776]: https://github.com/DataDog/dd-trace-rb/issues/5776
5298
5327
  [@AdrianLC]: https://github.com/AdrianLC
5299
5328
  [@Azure7111]: https://github.com/Azure7111
5300
5329
  [@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
@@ -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
+ }
@@ -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',
@@ -19,6 +19,8 @@ require_relative '../../profiling/component'
19
19
  require_relative '../../appsec/component'
20
20
  require_relative '../../ai_guard/component'
21
21
  require_relative '../../di/component'
22
+ require_relative '../../symbol_database'
23
+ require_relative '../../symbol_database/component'
22
24
  require_relative '../../open_feature/component'
23
25
  require_relative '../../error_tracking/component'
24
26
  require_relative '../crashtracking/component'
@@ -120,6 +122,7 @@ module Datadog
120
122
  :ai_guard,
121
123
  :agent_info,
122
124
  :data_streams,
125
+ :symbol_database,
123
126
  :open_feature
124
127
 
125
128
  def initialize(settings)
@@ -133,7 +136,7 @@ module Datadog
133
136
  self.class::PATCH_ONLY_ONCE.run do
134
137
  Utils::AtForkMonkeyPatch.apply!
135
138
  Utils::SpawnMonkeyPatch.apply!(
136
- lineage_envs_provider: Core::Environment::Identity.method(:runtime_propagation_envs),
139
+ env_provider: Core::Environment::Identity.method(:runtime_propagation_envs),
137
140
  )
138
141
 
139
142
  # Register callback that calls Components.after_fork
@@ -171,6 +174,7 @@ module Datadog
171
174
  @ai_guard = Datadog::AIGuard::Component.build(settings, logger: @logger, telemetry: telemetry)
172
175
  @open_feature = OpenFeature::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry)
173
176
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
177
+ @symbol_database = Datadog::SymbolDatabase::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
174
178
  @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
175
179
  @data_streams = self.class.build_data_streams(settings, agent_settings, @logger, @agent_info)
176
180
  @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
@@ -241,6 +245,9 @@ module Datadog
241
245
  # Shutdown DI after remote, since remote config triggers DI operations.
242
246
  dynamic_instrumentation&.shutdown!
243
247
 
248
+ # Shutdown Symbol Database
249
+ symbol_database&.shutdown!
250
+
244
251
  # Shutdown OpenFeature component
245
252
  open_feature&.shutdown!
246
253
 
@@ -6,6 +6,7 @@ require_relative 'base'
6
6
  require_relative 'ext'
7
7
  require_relative '../environment/execution'
8
8
  require_relative '../environment/ext'
9
+ require_relative '../environment/process'
9
10
  require_relative '../runtime/ext'
10
11
  require_relative '../telemetry/ext'
11
12
  require_relative '../remote/ext'
@@ -692,12 +693,16 @@ module Datadog
692
693
  o.env Core::Environment::Ext::ENV_SERVICE
693
694
  o.default Core::Environment::Ext::FALLBACK_SERVICE_NAME
694
695
 
696
+ o.after_set do |service_name|
697
+ Core::Environment::Process.set_service(service_name, user_configured: !using_default?(:service))
698
+ end
699
+
695
700
  # There's a few cases where we don't want to use the fallback service name, so this helper allows us to get a
696
701
  # nil instead so that one can do
697
702
  # nice_service_name = Datadog.configuration.service_without_fallback || nice_service_name_default
698
703
  o.helper(:service_without_fallback) do
699
704
  service_name = service
700
- service_name unless service_name.equal?(Core::Environment::Ext::FALLBACK_SERVICE_NAME)
705
+ service_name unless using_default?(:service)
701
706
  end
702
707
  end
703
708
 
@@ -70,6 +70,7 @@ module Datadog
70
70
  "DD_INSTRUMENTATION_TELEMETRY_ENABLED",
71
71
  "DD_INTERNAL_FORCE_SYMBOL_DATABASE_UPLOAD",
72
72
  "DD_LOGS_INJECTION",
73
+ "DD_LOGS_OTEL_ENABLED",
73
74
  "DD_METRICS_OTEL_ENABLED",
74
75
  "DD_METRIC_AGENT_PORT",
75
76
  "DD_PROFILING_ALLOCATION_ENABLED",
@@ -350,8 +351,16 @@ module Datadog
350
351
  "DD_TRACE_WATERDROP_ENABLED",
351
352
  "DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH",
352
353
  "DD_VERSION",
354
+ "OTEL_BLRP_EXPORT_TIMEOUT",
355
+ "OTEL_BLRP_MAX_EXPORT_BATCH_SIZE",
356
+ "OTEL_BLRP_MAX_QUEUE_SIZE",
357
+ "OTEL_BLRP_SCHEDULE_DELAY",
353
358
  "OTEL_EXPORTER_OTLP_ENDPOINT",
354
359
  "OTEL_EXPORTER_OTLP_HEADERS",
360
+ "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT",
361
+ "OTEL_EXPORTER_OTLP_LOGS_HEADERS",
362
+ "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL",
363
+ "OTEL_EXPORTER_OTLP_LOGS_TIMEOUT",
355
364
  "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
356
365
  "OTEL_EXPORTER_OTLP_METRICS_HEADERS",
357
366
  "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL",
@@ -359,6 +368,7 @@ module Datadog
359
368
  "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT",
360
369
  "OTEL_EXPORTER_OTLP_PROTOCOL",
361
370
  "OTEL_EXPORTER_OTLP_TIMEOUT",
371
+ "OTEL_LOGS_EXPORTER",
362
372
  "OTEL_LOG_LEVEL",
363
373
  "OTEL_METRICS_EXPORTER",
364
374
  "OTEL_METRIC_EXPORT_INTERVAL",
@@ -45,6 +45,10 @@ module Datadog
45
45
  TAG_RAILS_APPLICATION = "rails.application"
46
46
  TAG_PROCESS_TAGS = "_dd.tags.process"
47
47
  TAG_SERVICE = 'service'
48
+ # Service name was automatically populated by this library
49
+ TAG_SVC_AUTO = 'svc.auto'
50
+ # Service name was explicitly configured by the library user
51
+ TAG_SVC_USER = 'svc.user'
48
52
  TAG_VERSION = 'version'
49
53
 
50
54
  GEM_DATADOG_VERSION = Datadog::VERSION::STRING
@@ -76,7 +76,21 @@ module Datadog
76
76
  Core::Environment::Ext::GEM_DATADOG_VERSION
77
77
  end
78
78
 
79
- # Returns tracer version, comforming to https://semver.org/spec/v2.0.0.html
79
+ # Returns the tracer version in SemVer-2 form (https://semver.org/spec/v2.0.0.html).
80
+ #
81
+ # Converts the RubyGems-style version returned by {.gem_datadog_version}
82
+ # (dot-separated prerelease/build segments, e.g. "2.34.0.dev") into the
83
+ # SemVer-2 form expected by cross-language Datadog consumers (hyphen-separated
84
+ # prerelease, "+" build metadata, e.g. "2.34.0-dev").
85
+ #
86
+ # Called by reporters that emit a tracer version on the wire and must match
87
+ # the format used by other-language tracers:
88
+ # - process discovery memfd (`Core::ProcessDiscovery.get_metadata` → `tracer_version`)
89
+ # - telemetry payloads (`Core::Telemetry::Request#application`)
90
+ # - remote configuration client identification (`Core::Remote::Client#tracer_version`)
91
+ #
92
+ # Use {.gem_datadog_version} (not this method) when a RubyGems-style string is
93
+ # required (e.g. gem-internal contexts, gemspec interop).
80
94
  def gem_datadog_version_semver2
81
95
  major, minor, patch, rest = gem_datadog_version.split('.', 4)
82
96
 
@@ -10,18 +10,17 @@ module Datadog
10
10
  #
11
11
  # @api private
12
12
  module Process
13
- # This method returns a key/value part of serialized tags in the format of k1:v1,k2:v2,k3:v3
14
- # @return [String] comma-separated normalized key:value pairs
13
+ # Returns a comma-separated string of normalized key:value pairs.
14
+ # Includes svc.user or svc.auto based on whether the service was explicitly configured.
15
+ # @return [String]
15
16
  def self.serialized
16
- return @serialized if defined?(@serialized)
17
-
18
- @serialized = tags.join(',').freeze
17
+ tags.join(',').freeze
19
18
  end
20
19
 
21
- # This method returns an array in the format ["k1:v1","k2:v2","k3:v3"]
22
- # @return [Array<String>] array of normalized key:value pairs
20
+ # Returns an array of normalized key:value pair strings.
21
+ # Includes svc.user or svc.auto based on whether the service was explicitly configured.
22
+ # @return [Array<String>]
23
23
  def self.tags
24
- return @tags if defined?(@tags)
25
24
  tags = []
26
25
 
27
26
  workdir = TagNormalizer.normalize_process_value(entrypoint_workdir.to_s)
@@ -35,17 +34,44 @@ module Datadog
35
34
 
36
35
  tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"
37
36
 
38
- rails_application_name = TagNormalizer.normalize_process_value(@rails_application_name.to_s)
39
- tags << "#{Environment::Ext::TAG_RAILS_APPLICATION}:#{rails_application_name}" unless rails_application_name.empty?
37
+ rails_name = TagNormalizer.normalize_process_value(@rails_application_name.to_s)
38
+ tags << "#{Environment::Ext::TAG_RAILS_APPLICATION}:#{rails_name}" unless rails_name.empty?
39
+
40
+ if defined?(@service_user_configured)
41
+ if @service_user_configured
42
+ tags << "#{Environment::Ext::TAG_SVC_USER}:true"
43
+ else
44
+ svc = TagNormalizer.normalize_process_value(@service_name.to_s)
45
+ tags << "#{Environment::Ext::TAG_SVC_AUTO}:#{svc}" unless svc.empty?
46
+ end
47
+ end
48
+
49
+ tags.freeze
50
+ end
51
+
52
+ # Called via after_set on option :service in settings.rb whenever the service value changes.
53
+ # @param name [String] the service name
54
+ # @param user_configured [Boolean] whether the service was explicitly set by the user
55
+ # @return [void]
56
+ def self.set_service(name, user_configured:)
57
+ @service_name = name
58
+ @service_user_configured = user_configured
59
+ end
40
60
 
41
- @tags = tags.freeze
61
+ # Sets the rails application name from other places in code
62
+ # @param name [String] the rails application name
63
+ # @return [void]
64
+ def self.rails_application_name=(name)
65
+ @rails_application_name = name
42
66
  end
43
67
 
44
68
  # Returns the last segment of the working directory of the process
45
69
  # Example: /app/myapp -> myapp
46
70
  # @return [String] the last segment of the working directory
47
71
  def self.entrypoint_workdir
48
- File.basename(Dir.pwd)
72
+ return @entrypoint_workdir if defined?(@entrypoint_workdir)
73
+
74
+ @entrypoint_workdir = File.basename(Dir.pwd)
49
75
  end
50
76
 
51
77
  # Returns the entrypoint type of the process
@@ -55,10 +81,10 @@ module Datadog
55
81
  Environment::Ext::PROCESS_TYPE
56
82
  end
57
83
 
58
- # Returns the last segment of the base directory of the process
84
+ # Returns the basename of the script being run
59
85
  # Example 1: /bin/mybin -> mybin
60
- # Example 2: ruby /test/myapp.rb -> myapp
61
- # @return [String] the last segment of base directory of the script
86
+ # Example 2: ruby /test/myapp.rb -> myapp.rb
87
+ # @return [String] the basename of the script
62
88
  #
63
89
  # @note Determining true entrypoint name is rather complicated. This method
64
90
  # is the initial implementation but it does not produce optimal output in all cases.
@@ -66,12 +92,14 @@ module Datadog
66
92
  # as their entrypoint name.
67
93
  # We might improve the behavior in the future if there is customer demand for it.
68
94
  def self.entrypoint_name
69
- File.basename($0)
95
+ return @entrypoint_name if defined?(@entrypoint_name)
96
+
97
+ @entrypoint_name = File.basename($0)
70
98
  end
71
99
 
72
- # Returns the last segment of the base directory of the process
100
+ # Returns the last segment of the directory containing the script
73
101
  # Example 1: /bin/mybin -> bin
74
- # Example 2: ruby /test/myapp.js -> test
102
+ # Example 2: ruby /test/myapp.rb -> test
75
103
  # @return [String] the last segment of the base directory of the script
76
104
  #
77
105
  # @note As with entrypoint name, determining true entrypoint directory is complicated.
@@ -80,16 +108,9 @@ module Datadog
80
108
  # the entrypoint basedir is `bin` which is not very helpful.
81
109
  # We might improve this in the future if there is customer demand.
82
110
  def self.entrypoint_basedir
83
- File.basename(File.expand_path(File.dirname($0)))
84
- end
111
+ return @entrypoint_basedir if defined?(@entrypoint_basedir)
85
112
 
86
- # Sets the rails application name from other places in code
87
- # @param name [String] the rails application name
88
- # @return [void]
89
- def self.rails_application_name=(name)
90
- @rails_application_name = name
91
- remove_instance_variable(:@tags) if instance_variable_defined?(:@tags)
92
- remove_instance_variable(:@serialized) if instance_variable_defined?(:@serialized)
113
+ @entrypoint_basedir = File.basename(File.expand_path(File.dirname($0)))
93
114
  end
94
115
 
95
116
  private_class_method :entrypoint_workdir, :entrypoint_type, :entrypoint_name, :entrypoint_basedir
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../utils/base64'
3
+ require_relative '../../utils/base64_codec'
4
4
  require_relative '../../../appsec/remote'
5
5
  require_relative '../../../tracing/remote'
6
+ require_relative '../../../di/remote'
7
+ require_relative '../../../symbol_database/remote'
6
8
  require_relative '../../../open_feature/remote'
7
9
 
8
10
  module Datadog
@@ -37,6 +39,13 @@ module Datadog
37
39
  register_capabilities(Datadog::DI::Remote.capabilities)
38
40
  register_products(Datadog::DI::Remote.products)
39
41
  register_receivers(Datadog::DI::Remote.receivers(@telemetry))
42
+
43
+ # Symbol Database
44
+ if settings.respond_to?(:symbol_database) && settings.symbol_database.enabled
45
+ register_capabilities(Datadog::SymbolDatabase::Remote.capabilities)
46
+ register_products(Datadog::SymbolDatabase::Remote.products)
47
+ register_receivers(Datadog::SymbolDatabase::Remote.receivers(@telemetry))
48
+ end
40
49
  end
41
50
 
42
51
  if settings.respond_to?(:open_feature) && settings.open_feature.enabled
@@ -68,7 +77,7 @@ module Datadog
68
77
  cap_to_hexs = capabilities.reduce(:|).to_s(16).tap { |s| s.size.odd? && s.prepend('0') }.scan(/\h\h/)
69
78
  binary = cap_to_hexs.each_with_object([]) { |hex, acc| acc << hex }.map { |e| e.to_i(16) }.pack('C*')
70
79
 
71
- Datadog::Core::Utils::Base64.strict_encode64(binary)
80
+ Datadog::Core::Utils::Base64Codec.strict_encode64(binary)
72
81
  end
73
82
  end
74
83
  end
@@ -4,7 +4,7 @@ require 'json'
4
4
 
5
5
  require_relative '../../../transport/http/api/endpoint'
6
6
  require_relative '../../../transport/http/response'
7
- require_relative '../../../utils/base64'
7
+ require_relative '../../../utils/base64_codec'
8
8
  require_relative '../../../utils/truncation'
9
9
 
10
10
  module Datadog
@@ -35,7 +35,7 @@ module Datadog
35
35
 
36
36
  # TODO: these fallbacks should be improved
37
37
  roots = payload[:roots] || []
38
- targets = payload[:targets] || Datadog::Core::Utils::Base64.strict_encode64('{}')
38
+ targets = payload[:targets] || Datadog::Core::Utils::Base64Codec.strict_encode64('{}')
39
39
  target_files = payload[:target_files] || []
40
40
  client_configs = payload[:client_configs] || []
41
41
 
@@ -45,7 +45,7 @@ module Datadog
45
45
  raise TypeError.new(String, root) unless root.is_a?(String)
46
46
 
47
47
  decoded = begin
48
- Datadog::Core::Utils::Base64.strict_decode64(root) # TODO: unprocessed, don't symbolize_names
48
+ Datadog::Core::Utils::Base64Codec.strict_decode64(root) # TODO: unprocessed, don't symbolize_names
49
49
  rescue ArgumentError
50
50
  raise DecodeError.new(:roots, root)
51
51
  end
@@ -65,7 +65,7 @@ module Datadog
65
65
 
66
66
  @targets = begin
67
67
  decoded = begin
68
- Datadog::Core::Utils::Base64.strict_decode64(targets)
68
+ Datadog::Core::Utils::Base64Codec.strict_decode64(targets)
69
69
  rescue ArgumentError
70
70
  raise DecodeError.new(:targets, targets)
71
71
  end
@@ -93,7 +93,7 @@ module Datadog
93
93
  raise TypeError.new(String, raw) unless raw.is_a?(String)
94
94
 
95
95
  content = begin
96
- Datadog::Core::Utils::Base64.strict_decode64(raw)
96
+ Datadog::Core::Utils::Base64Codec.strict_decode64(raw)
97
97
  rescue ArgumentError
98
98
  raise DecodeError.new(:target_files, raw)
99
99
  end
@@ -10,8 +10,6 @@ module Datadog
10
10
  # Module defining methods for collecting metadata for telemetry
11
11
  module Request
12
12
  class << self
13
- using Core::Utils::Hash::Refinement
14
-
15
13
  def build_payload(event, seq_id, debug: false)
16
14
  hash = {
17
15
  api_version: 'v2',
@@ -70,7 +70,7 @@ module Datadog
70
70
  end
71
71
 
72
72
  def to_s
73
- "#{super}, error_type:#{error.class} error:#{error}"
73
+ "#{self.class}, error_type:#{error.class} error:#{error}"
74
74
  end
75
75
 
76
76
  def inspect
@@ -3,8 +3,9 @@
3
3
  module Datadog
4
4
  module Core
5
5
  module Utils
6
- # Helper methods for encoding and decoding base64
7
- module Base64
6
+ # Base64 encoding/decoding without using the `base64` gem,
7
+ # which is no longer a default gem since Ruby 3.4.
8
+ module Base64Codec
8
9
  def self.encode64(bin)
9
10
  [bin].pack('m')
10
11
  end
@@ -3,30 +3,7 @@
3
3
  module Datadog
4
4
  module Core
5
5
  module Utils
6
- # Refinements for {Hash}.
7
6
  module Hash
8
- # This refinement ensures modern rubies are allowed to use newer,
9
- # simpler, and more performant APIs.
10
- module Refinement
11
- # Introduced in Ruby 2.4
12
- unless ::Hash.method_defined?(:compact)
13
- refine ::Hash do
14
- def compact
15
- reject { |_k, v| v.nil? }
16
- end
17
- end
18
- end
19
-
20
- # Introduced in Ruby 2.4
21
- unless ::Hash.method_defined?(:compact!)
22
- refine ::Hash do
23
- def compact!
24
- reject! { |_k, v| v.nil? }
25
- end
26
- end
27
- end
28
- end
29
-
30
7
  # A minimal {Hash} wrapper that provides case-insensitive access
31
8
  # to hash keys, without the overhead of copying the original hash.
32
9
  #