datadog 2.28.0 → 2.30.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +82 -12
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +32 -11
  5. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -1
  6. data/ext/datadog_profiling_native_extension/extconf.rb +9 -24
  7. data/ext/datadog_profiling_native_extension/heap_recorder.c +186 -55
  8. data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
  9. data/ext/datadog_profiling_native_extension/http_transport.c +51 -64
  10. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
  11. data/ext/datadog_profiling_native_extension/profiling.c +3 -1
  12. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +24 -8
  13. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -3
  14. data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -48
  15. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -1
  16. data/ext/libdatadog_api/crashtracker.c +5 -0
  17. data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
  18. data/ext/libdatadog_api/extconf.rb +4 -21
  19. data/ext/libdatadog_extconf_helpers.rb +49 -11
  20. data/lib/datadog/ai_guard/configuration/settings.rb +3 -0
  21. data/lib/datadog/appsec/assets/blocked.html +2 -1
  22. data/lib/datadog/appsec/configuration/settings.rb +14 -0
  23. data/lib/datadog/appsec/context.rb +44 -9
  24. data/lib/datadog/appsec/contrib/active_record/patcher.rb +3 -0
  25. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  26. data/lib/datadog/appsec/contrib/excon/patcher.rb +2 -0
  27. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +55 -6
  28. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  29. data/lib/datadog/appsec/contrib/faraday/patcher.rb +1 -1
  30. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +60 -7
  31. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +11 -6
  32. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
  33. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  34. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -10
  35. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +4 -4
  36. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +26 -5
  38. data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
  39. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
  40. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  41. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -0
  42. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +2 -0
  43. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +72 -7
  44. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -3
  45. data/lib/datadog/appsec/counter_sampler.rb +25 -0
  46. data/lib/datadog/appsec/event.rb +1 -17
  47. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
  48. data/lib/datadog/appsec/instrumentation/gateway.rb +2 -2
  49. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +18 -0
  50. data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -2
  51. data/lib/datadog/appsec/security_engine/engine.rb +23 -2
  52. data/lib/datadog/appsec/utils/http/body.rb +38 -0
  53. data/lib/datadog/appsec/utils/http/media_range.rb +2 -1
  54. data/lib/datadog/appsec/utils/http/media_type.rb +28 -35
  55. data/lib/datadog/appsec/utils/http/url_encoded.rb +52 -0
  56. data/lib/datadog/core/configuration/components.rb +29 -4
  57. data/lib/datadog/core/configuration/option.rb +2 -1
  58. data/lib/datadog/core/configuration/options.rb +1 -1
  59. data/lib/datadog/core/configuration/settings.rb +27 -3
  60. data/lib/datadog/core/configuration/supported_configurations.rb +19 -0
  61. data/lib/datadog/core/configuration.rb +2 -2
  62. data/lib/datadog/core/crashtracking/component.rb +71 -19
  63. data/lib/datadog/core/environment/agent_info.rb +65 -1
  64. data/lib/datadog/core/logger.rb +1 -1
  65. data/lib/datadog/core/metrics/logging.rb +1 -1
  66. data/lib/datadog/core/process_discovery.rb +20 -19
  67. data/lib/datadog/core/rate_limiter.rb +2 -0
  68. data/lib/datadog/core/remote/component.rb +16 -5
  69. data/lib/datadog/core/remote/transport/config.rb +5 -11
  70. data/lib/datadog/core/runtime/metrics.rb +1 -2
  71. data/lib/datadog/core/telemetry/component.rb +0 -13
  72. data/lib/datadog/core/telemetry/transport/telemetry.rb +5 -6
  73. data/lib/datadog/core/transport/ext.rb +1 -0
  74. data/lib/datadog/core/transport/http/response.rb +4 -0
  75. data/lib/datadog/core/transport/parcel.rb +61 -9
  76. data/lib/datadog/core/utils/base64.rb +1 -1
  77. data/lib/datadog/core/utils/fnv.rb +26 -0
  78. data/lib/datadog/core/workers/interval_loop.rb +13 -6
  79. data/lib/datadog/core/workers/queue.rb +0 -4
  80. data/lib/datadog/core/workers/runtime_metrics.rb +9 -1
  81. data/lib/datadog/core.rb +6 -1
  82. data/lib/datadog/data_streams/processor.rb +35 -33
  83. data/lib/datadog/data_streams/transport/http/stats.rb +6 -0
  84. data/lib/datadog/data_streams/transport/http.rb +0 -4
  85. data/lib/datadog/data_streams/transport/stats.rb +5 -12
  86. data/lib/datadog/di/boot.rb +1 -0
  87. data/lib/datadog/di/component.rb +17 -5
  88. data/lib/datadog/di/configuration/settings.rb +9 -0
  89. data/lib/datadog/di/context.rb +6 -0
  90. data/lib/datadog/di/instrumenter.rb +183 -134
  91. data/lib/datadog/di/probe.rb +10 -1
  92. data/lib/datadog/di/probe_file_loader.rb +2 -2
  93. data/lib/datadog/di/probe_manager.rb +86 -64
  94. data/lib/datadog/di/probe_notification_builder.rb +46 -18
  95. data/lib/datadog/di/probe_notifier_worker.rb +65 -9
  96. data/lib/datadog/di/probe_repository.rb +198 -0
  97. data/lib/datadog/di/proc_responder.rb +4 -0
  98. data/lib/datadog/di/remote.rb +6 -7
  99. data/lib/datadog/di/serializer.rb +127 -9
  100. data/lib/datadog/di/transport/diagnostics.rb +5 -7
  101. data/lib/datadog/di/transport/http/diagnostics.rb +3 -1
  102. data/lib/datadog/di/transport/http/input.rb +1 -1
  103. data/lib/datadog/di/transport/http.rb +12 -3
  104. data/lib/datadog/di/transport/input.rb +51 -14
  105. data/lib/datadog/kit/tracing/method_tracer.rb +132 -0
  106. data/lib/datadog/open_feature/configuration.rb +2 -0
  107. data/lib/datadog/open_feature/transport.rb +8 -11
  108. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +13 -0
  109. data/lib/datadog/profiling/component.rb +20 -6
  110. data/lib/datadog/profiling/http_transport.rb +5 -6
  111. data/lib/datadog/profiling/profiler.rb +15 -8
  112. data/lib/datadog/tracing/contrib/dalli/integration.rb +4 -1
  113. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +5 -1
  114. data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
  115. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -2
  116. data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
  117. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +5 -2
  118. data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
  119. data/lib/datadog/tracing/contrib/grape/endpoint.rb +2 -2
  120. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +13 -8
  121. data/lib/datadog/tracing/contrib/grape/patcher.rb +6 -1
  122. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +5 -2
  123. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  124. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +5 -2
  125. data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
  126. data/lib/datadog/tracing/contrib/http/integration.rb +0 -2
  127. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +5 -2
  128. data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
  129. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +5 -2
  130. data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
  131. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +5 -1
  132. data/lib/datadog/tracing/contrib/karafka/ext.rb +1 -0
  133. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -0
  134. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
  135. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -0
  136. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +2 -1
  137. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +10 -0
  138. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  139. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +24 -0
  140. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +5 -2
  141. data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
  142. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +5 -1
  143. data/lib/datadog/tracing/contrib/rack/ext.rb +1 -0
  144. data/lib/datadog/tracing/contrib/rack/route_inference.rb +18 -6
  145. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +5 -2
  146. data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
  147. data/lib/datadog/tracing/contrib/registerable.rb +11 -0
  148. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +5 -2
  149. data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
  150. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +5 -1
  151. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  152. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +5 -1
  153. data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
  154. data/lib/datadog/tracing/contrib/sneakers/integration.rb +15 -4
  155. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +6 -0
  156. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +3 -1
  157. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +5 -1
  158. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +1 -0
  159. data/lib/datadog/tracing/metadata/ext.rb +4 -0
  160. data/lib/datadog/tracing/sync_writer.rb +0 -1
  161. data/lib/datadog/tracing/transport/io/client.rb +5 -8
  162. data/lib/datadog/tracing/transport/io/traces.rb +28 -34
  163. data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
  164. data/lib/datadog/tracing/transport/traces.rb +4 -10
  165. data/lib/datadog/tracing/writer.rb +0 -1
  166. data/lib/datadog/version.rb +1 -1
  167. metadata +14 -8
  168. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
  169. data/lib/datadog/tracing/workers/trace_writer.rb +0 -204
@@ -8,6 +8,7 @@ module Datadog
8
8
  module Ext
9
9
  module HTTP
10
10
  HEADER_CONTAINER_ID = 'Datadog-Container-ID'
11
+ HEADER_CONTAINER_TAGS_HASH = 'Datadog-Container-Tags-Hash'
11
12
  HEADER_ENTITY_ID = 'Datadog-Entity-ID'
12
13
  HEADER_EXTERNAL_ENV = 'Datadog-External-Env'
13
14
  HEADER_DD_API_KEY = 'DD-API-KEY'
@@ -53,6 +53,10 @@ module Datadog
53
53
  def code
54
54
  @http_response.respond_to?(:code) ? @http_response.code : nil
55
55
  end
56
+
57
+ def headers
58
+ @http_response.respond_to?(:headers) ? @http_response.headers : {}
59
+ end
56
60
  end
57
61
  end
58
62
  end
@@ -3,19 +3,71 @@
3
3
  module Datadog
4
4
  module Core
5
5
  module Transport
6
- # Data transfer object for generic data
7
- # @abstract
8
- module Parcel
9
- attr_reader \
10
- :data
11
-
12
- def initialize(data)
6
+ # Data transfer object for transporting already-encoded data.
7
+ #
8
+ # A Parcel is a container that holds pre-encoded data along with metadata
9
+ # about its encoding. The key design principle is that encoding happens
10
+ # BEFORE the Parcel is created, not inside it.
11
+ #
12
+ # @example Creating a Parcel with JSON data
13
+ # encoder = Core::Encoding::JSONEncoder
14
+ # parcel = Parcel.new(
15
+ # encoder.encode(payload),
16
+ # content_type: encoder.content_type,
17
+ # )
18
+ #
19
+ # @example Creating a Parcel with compressed MessagePack data
20
+ # msgpack_data = MessagePack.pack(payload)
21
+ # compressed_data = Zlib.gzip(msgpack_data)
22
+ # parcel = Parcel.new(
23
+ # compressed_data,
24
+ # content_type: 'application/msgpack',
25
+ # content_encoding: 'gzip',
26
+ # )
27
+ #
28
+ # @example Accessing Parcel data in HTTP transport
29
+ # # In HTTP adapters, Parcel metadata maps to HTTP headers:
30
+ # env.headers['Content-Type'] = request.parcel.content_type
31
+ # env.headers['Content-Encoding'] = request.parcel.content_encoding
32
+ # env.body = request.parcel.data
33
+ #
34
+ # The content_type and content_encoding fields are optional but recommended:
35
+ # - Set them when creating the Parcel for automatic header management
36
+ # - Leave them nil for IO transports or when headers are managed elsewhere
37
+ # - HTTP transports use these to set appropriate request headers
38
+ #
39
+ # @see Core::Encoding::JSONEncoder for JSON encoding utilities
40
+ # @see Core::Transport::Request which wraps Parcels for transmission
41
+ class Parcel
42
+ # Creates a new Parcel with pre-encoded data.
43
+ #
44
+ # @param data [String] The already-encoded data (e.g., JSON string, MessagePack bytes)
45
+ # @param content_type [String, nil] MIME type of the data (e.g., 'application/json')
46
+ # @param content_encoding [String, nil] Encoding applied to data (e.g., 'gzip')
47
+ def initialize(data, content_type: nil, content_encoding: nil)
13
48
  @data = data
49
+ @content_type = content_type
50
+ @content_encoding = content_encoding
14
51
  end
15
52
 
16
- def encode_with(encoder)
17
- raise NotImplementedError
53
+ # @!attribute [r] data
54
+ # @return [String] The encoded data payload
55
+ attr_reader :data
56
+
57
+ # Returns the length of the encoded data.
58
+ #
59
+ # @return [Integer] Number of bytes in the data
60
+ def length
61
+ data.length
18
62
  end
63
+
64
+ # @!attribute [r] content_type
65
+ # @return [String, nil] MIME type of the data (e.g., 'application/json')
66
+ attr_reader :content_type
67
+
68
+ # @!attribute [r] content_encoding
69
+ # @return [String, nil] Encoding applied to data (e.g., 'gzip')
70
+ attr_reader :content_encoding
19
71
  end
20
72
  end
21
73
  end
@@ -14,7 +14,7 @@ module Datadog
14
14
  end
15
15
 
16
16
  def self.strict_decode64(str)
17
- str.unpack1('m0')
17
+ str.unpack1('m0') #: String # 'm0' format always returns a String
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Utils
6
+ module FNV
7
+ # FNV-1a 64-bit non-cryptographic hash function.
8
+ # @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash Algorithm
9
+ # @see https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters Prime and Offset Basis
10
+
11
+ FNV_OFFSET_BASIS = 14695981039346656037
12
+ FNV_PRIME = 1099511628211
13
+ FNV_64_BIT_MASK = 0xFFFFFFFFFFFFFFFF
14
+
15
+ def self.fnv1_64(data)
16
+ hash_value = FNV_OFFSET_BASIS
17
+ data.each_byte do |byte|
18
+ hash_value ^= byte
19
+ hash_value = (hash_value * FNV_PRIME) & FNV_64_BIT_MASK
20
+ end
21
+ hash_value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -70,16 +70,23 @@ module Datadog
70
70
  true
71
71
  end
72
72
 
73
- # TODO This overwrites Queue's +work_pending?+ method with an
74
- # implementation that, to me, is at leat questionable semantically:
75
- # the Queue's idea of pending work is if the buffer is not empty,
76
- # but this module says that work is pending if the work processing
77
- # loop is scheduled to run (in other words, as long as the background
78
- # thread is running, there is always pending work).
73
+ # TODO: This method carries two semantics today:
74
+ # 1. Is there work available to process?
75
+ # 2. Should the main loop keep running?
76
+ # Things get messy when `Queue` is mixed in,
77
+ # wanting to override semantic 1 but not 2.
78
+ # This should probably be split into two methods:
79
+ # `work_pending?` (semantic 1) and `continue_loop?` (semantic 2).
80
+ # Today, `run_loop?` performs semantic 2, but should probably be
81
+ # renamed to `continue_loop?`, since that would make it clear that
82
+ # we're just checking if we can "keep going inside the loop",
83
+ # and not checking if we should run the loop right now.
84
+ # Clean up {Workers::Queue} after this.
79
85
  def work_pending?
80
86
  run_loop?
81
87
  end
82
88
 
89
+ # TODO: Probably should be renamed to `continue_loop?`, see `work_pending?` TODO.
83
90
  def run_loop?
84
91
  return false unless instance_variable_defined?(:@run_loop)
85
92
 
@@ -130,10 +130,6 @@ module Datadog
130
130
  # they all override +perform+ and the correct behavior depends on
131
131
  # placing IntervalLoop after Queue.
132
132
  #
133
- # The TraceWriter worker then defines +work_pending?+ to be the
134
- # same as Queue implementation here... Essentially, it demands
135
- # the behavior that perhaps should be applied to all workers.
136
- #
137
133
  # Until this mess is untangled, call +buffer.empty?+ here.
138
134
  buffer.empty? && !in_iteration?
139
135
  end
@@ -21,7 +21,15 @@ module Datadog
21
21
  :metrics
22
22
 
23
23
  def initialize(telemetry:, **options)
24
- @metrics = options.fetch(:metrics) { Core::Runtime::Metrics.new(logger: options[:logger], telemetry: telemetry) }
24
+ @metrics = options.fetch(:metrics) do
25
+ Core::Runtime::Metrics.new(
26
+ logger: options[:logger],
27
+ telemetry: telemetry,
28
+ experimental_propagate_process_tags_enabled: options.fetch(:propagate_process_tags_enabled) do
29
+ options.fetch(:experimental_propagate_process_tags_enabled)
30
+ end
31
+ )
32
+ end
25
33
 
26
34
  # Workers::Async::Thread settings
27
35
  self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
data/lib/datadog/core.rb CHANGED
@@ -29,9 +29,14 @@ module Datadog
29
29
  # Ensures the Datadog components have a chance to gracefully
30
30
  # shut down and cleanup before terminating the process.
31
31
  at_exit do
32
- if Interrupt === $! # rubocop:disable Style/SpecialGlobalVars is process terminating due to a ctrl+c or similar?
32
+ exception = $! # rubocop:disable Style/SpecialGlobalVars
33
+
34
+ if Interrupt === exception # is process terminating due to a ctrl+c or similar?
33
35
  Datadog.send(:handle_interrupt_shutdown!)
34
36
  else
37
+ # Report unhandled exception to crash tracker before shutdown
38
+ Datadog::Core::Crashtracking::Component.report_unhandled_exception(exception)
39
+
35
40
  Datadog.shutdown!
36
41
  end
37
42
  end
@@ -9,6 +9,7 @@ require_relative '../core/workers/polling'
9
9
  require_relative '../core/ddsketch'
10
10
  require_relative '../core/buffer/cruby'
11
11
  require_relative '../core/utils/time'
12
+ require_relative '../core/utils/fnv'
12
13
 
13
14
  module Datadog
14
15
  module DataStreams
@@ -35,14 +36,16 @@ module Datadog
35
36
  # @param logger [Datadog::Core::Logger] Logger instance for debugging
36
37
  # @param settings [Datadog::Core::Configuration::Settings] Global configuration settings
37
38
  # @param agent_settings [Datadog::Core::Configuration::AgentSettings] Agent connection settings
39
+ # @param agent_info [Datadog::Core::Environment::AgentInfo] Agent capability information
38
40
  # @param buffer_size [Integer] Size of the lock-free event buffer for async stat collection
39
41
  # (default: DEFAULT_BUFFER_SIZE). Higher values support more throughput but use more memory.
40
42
  # @raise [UnsupportedError] if DDSketch is not available on this platform
41
- def initialize(interval:, logger:, settings:, agent_settings:, buffer_size: DEFAULT_BUFFER_SIZE)
43
+ def initialize(interval:, logger:, settings:, agent_settings:, agent_info:, buffer_size: DEFAULT_BUFFER_SIZE)
42
44
  raise UnsupportedError, 'DDSketch is not supported' unless Datadog::Core::DDSketch.supported?
43
45
 
44
46
  @settings = settings
45
47
  @agent_settings = agent_settings
48
+ @agent_info = agent_info
46
49
  @logger = logger
47
50
 
48
51
  now = Core::Utils::Time.now
@@ -242,7 +245,7 @@ module Datadog
242
245
  current_context = get_current_context
243
246
  tags = tags.sort
244
247
 
245
- direction = nil #: ::String?
248
+ direction = nil # : ::String?
246
249
  tags.each do |tag|
247
250
  if tag.start_with?('direction:')
248
251
  direction = tag
@@ -300,28 +303,31 @@ module Datadog
300
303
  end
301
304
 
302
305
  def flush_stats
303
- payload = nil # : ::Hash[::String, untyped]?
304
-
305
- @stats_mutex.synchronize do
306
+ stats_buckets = @stats_mutex.synchronize do
306
307
  return if @buckets.empty? && @consumer_stats.empty?
307
308
 
308
- stats_buckets = serialize_buckets
309
-
310
- payload = {
311
- 'Service' => @settings.service,
312
- 'TracerVersion' => Datadog::VERSION::STRING,
313
- 'Lang' => 'ruby',
314
- 'Stats' => stats_buckets,
315
- 'Hostname' => hostname
316
- }
309
+ serialized_buckets = serialize_buckets
317
310
 
318
- # Clear consumer stats even if sending fails to prevent unbounded memory growth
319
- # Must be done inside mutex before we release it
311
+ # Clear consumer stats even if sending fails to prevent unbounded memory growth.
312
+ # Must be done inside mutex before we release it.
320
313
  @consumer_stats.clear
314
+
315
+ serialized_buckets
321
316
  end
322
317
 
323
- # Send to agent outside mutex to avoid blocking customer code if agent is slow/hung
324
- send_stats_to_agent(payload) if payload
318
+ payload = {
319
+ 'Env' => @settings.env || 'none',
320
+ 'Service' => @settings.service,
321
+ 'TracerVersion' => Datadog::VERSION::STRING,
322
+ 'Lang' => 'ruby',
323
+ 'Stats' => stats_buckets,
324
+ 'Hostname' => hostname
325
+ } # : ::Hash[::String, (::String | ::Array[::String])]
326
+
327
+ payload['ProcessTags'] = Core::Environment::Process.tags if @settings.experimental_propagate_process_tags_enabled
328
+
329
+ # Send to agent outside mutex to avoid blocking customer code if agent is slow/hung.
330
+ send_stats_to_agent(payload)
325
331
  rescue => e
326
332
  @logger.debug("Failed to flush DSM stats to agent: #{e.class}: #{e}")
327
333
  end
@@ -359,30 +365,26 @@ module Datadog
359
365
 
360
366
  # Compute new pathway hash using FNV-1a algorithm.
361
367
  # Combines service, env, tags, and parent hash to create unique pathway identifier.
368
+ #
369
+ # The hash only needs to be internally consistent:
370
+ # @see Datadog::Core::Environment::AgentInfo#container_tags_checksum
362
371
  def compute_pathway_hash(current_hash, tags)
363
372
  service = @settings.service || 'ruby-service'
364
373
  env = @settings.env || 'none'
365
374
 
366
375
  bytes = service.bytes + env.bytes
376
+
377
+ if @settings.experimental_propagate_process_tags_enabled
378
+ propagation_checksum = @agent_info.propagation_checksum
379
+ bytes += [propagation_checksum].pack('Q<').bytes if propagation_checksum
380
+ end
381
+
367
382
  tags.each { |tag| bytes += tag.bytes }
368
383
  byte_string = bytes.pack('C*')
369
384
 
370
- node_hash = fnv1_64(byte_string)
385
+ node_hash = Core::Utils::FNV.fnv1_64(byte_string)
371
386
  combined_bytes = [node_hash, current_hash].pack('QQ')
372
- fnv1_64(combined_bytes)
373
- end
374
-
375
- # FNV-1a 64-bit hash function.
376
- def fnv1_64(data)
377
- fnv_offset_basis = 14695981039346656037
378
- fnv_prime = 1099511628211
379
-
380
- hash_value = fnv_offset_basis
381
- data.each_byte do |byte|
382
- hash_value ^= byte
383
- hash_value = (hash_value * fnv_prime) & 0xFFFFFFFFFFFFFFFF
384
- end
385
- hash_value
387
+ Core::Utils::FNV.fnv1_64(combined_bytes)
386
388
  end
387
389
 
388
390
  def record_checkpoint_stats(
@@ -31,6 +31,12 @@ module Datadog
31
31
  env.verb = verb
32
32
  env.path = path
33
33
  env.body = env.request.parcel.data
34
+ if (content_type = env.request.parcel.content_type)
35
+ env.headers['content-type'] = content_type
36
+ end
37
+ if (content_encoding = env.request.parcel.content_encoding)
38
+ env.headers['content-encoding'] = content_encoding
39
+ end
34
40
 
35
41
  # Send request
36
42
  http_response = yield(env)
@@ -23,10 +23,6 @@ module Datadog
23
23
  Core::Transport::HTTP.build(
24
24
  agent_settings: agent_settings,
25
25
  logger: logger,
26
- headers: {
27
- 'Content-Type' => 'application/msgpack',
28
- 'Content-Encoding' => 'gzip'
29
- }
30
26
  ) do |transport|
31
27
  transport.api 'v0.1', V01, default: true
32
28
 
@@ -10,17 +10,6 @@ module Datadog
10
10
  module DataStreams
11
11
  module Transport
12
12
  module Stats
13
- # Parcel for encoded DSM stats payload
14
- class EncodedParcel
15
- include Datadog::Core::Transport::Parcel
16
-
17
- def initialize(data)
18
- @data = data
19
- end
20
-
21
- attr_reader :data
22
- end
23
-
24
13
  # Request for DSM stats
25
14
  class Request < Datadog::Core::Transport::Request
26
15
  end
@@ -33,7 +22,11 @@ module Datadog
33
22
  compressed_data = Zlib.gzip(msgpack_data)
34
23
 
35
24
  # Create parcel and request
36
- parcel = EncodedParcel.new(compressed_data)
25
+ parcel = Core::Transport::Parcel.new(
26
+ compressed_data,
27
+ content_type: 'application/msgpack',
28
+ content_encoding: 'gzip',
29
+ )
37
30
  request = Request.new(parcel)
38
31
 
39
32
  # Send to agent
@@ -12,6 +12,7 @@ require_relative 'probe_builder'
12
12
  require_relative 'probe_manager'
13
13
  require_relative 'probe_notification_builder'
14
14
  require_relative 'probe_notifier_worker'
15
+ require_relative 'probe_repository'
15
16
  require_relative 'redactor'
16
17
  require_relative 'serializer'
17
18
  require_relative 'transport/http'
@@ -63,9 +63,19 @@ module Datadog
63
63
  @redactor = Redactor.new(settings)
64
64
  @serializer = Serializer.new(settings, redactor, telemetry: telemetry)
65
65
  @instrumenter = Instrumenter.new(settings, serializer, logger, code_tracker: code_tracker, telemetry: telemetry)
66
- @probe_notifier_worker = ProbeNotifierWorker.new(settings, logger, agent_settings: agent_settings, telemetry: telemetry)
66
+ @probe_repository = ProbeRepository.new
67
67
  @probe_notification_builder = ProbeNotificationBuilder.new(settings, serializer)
68
- @probe_manager = ProbeManager.new(settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, telemetry: telemetry)
68
+ @probe_notifier_worker = ProbeNotifierWorker.new(
69
+ settings, logger,
70
+ agent_settings: agent_settings,
71
+ probe_repository: probe_repository,
72
+ probe_notification_builder: probe_notification_builder,
73
+ telemetry: telemetry,
74
+ )
75
+ @probe_manager = ProbeManager.new(
76
+ settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, probe_repository,
77
+ telemetry: telemetry,
78
+ )
69
79
  probe_notifier_worker.start
70
80
  end
71
81
 
@@ -75,6 +85,7 @@ module Datadog
75
85
  attr_reader :telemetry
76
86
  attr_reader :code_tracker
77
87
  attr_reader :instrumenter
88
+ attr_reader :probe_repository
78
89
  attr_reader :probe_notifier_worker
79
90
  attr_reader :probe_notification_builder
80
91
  attr_reader :probe_manager
@@ -106,15 +117,16 @@ module Datadog
106
117
  )
107
118
  payload = probe_notification_builder.build_errored(probe, exc)
108
119
  probe_notifier_worker.add_status(payload)
109
- rescue # standard:disable Lint/UselessRescue
110
- # TODO report via instrumentation telemetry?
120
+ rescue => nested_exc
121
+ logger.debug { "di: failed to build error notification: #{nested_exc.class}: #{nested_exc}" }
122
+ telemetry&.report(nested_exc, description: 'Error building probe error notification')
111
123
  raise
112
124
  end
113
125
 
114
126
  raise
115
127
  else
116
128
  payload = probe_notification_builder.build_received(probe)
117
- probe_notifier_worker.add_status(payload)
129
+ probe_notifier_worker.add_status(payload, probe: probe)
118
130
  probe
119
131
  end
120
132
  end
@@ -224,6 +224,15 @@ module Datadog
224
224
  # debugging (since DI uses RC for configuration).
225
225
  o.env 'DD_TRACE_DEBUG'
226
226
  end
227
+
228
+ # If the CPU time consumed by the thread performing instrumentation
229
+ # exceeds this amount, the offending probe will be automatically disabled.
230
+ # Set to nil to disable the circuit breaker.
231
+ # Set to zero to disable every probe after it executes once.
232
+ option :max_processing_time do |o|
233
+ o.type :float
234
+ o.default 0.5
235
+ end
227
236
  end
228
237
  end
229
238
  end
@@ -33,17 +33,23 @@ module Datadog
33
33
  attr_reader :serializer
34
34
  attr_reader :locals
35
35
  attr_reader :target_self
36
+
36
37
  # Actual path of the instrumented file.
37
38
  attr_reader :path
39
+
38
40
  # TODO check how many stack frames we should be keeping/sending,
39
41
  # this should be all frames for enriched probes and no frames for
40
42
  # non-enriched probes?
41
43
  attr_reader :caller_locations
44
+
42
45
  attr_reader :serialized_entry_args
46
+
43
47
  # Return value for the method, for a method probe
44
48
  attr_reader :return_value
49
+
45
50
  # How long the method took to execute, for a method probe
46
51
  attr_reader :duration
52
+
47
53
  # Exception raised by the method, if any, for a method probe
48
54
  attr_reader :exception
49
55