datadog 2.15.0 → 2.17.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 (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -2
  3. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
  5. data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
  6. data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
  7. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  8. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  9. data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
  10. data/ext/datadog_profiling_native_extension/stack_recorder.c +4 -5
  11. data/ext/libdatadog_api/crashtracker.c +11 -12
  12. data/ext/libdatadog_api/crashtracker.h +5 -0
  13. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  14. data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
  15. data/ext/libdatadog_api/init.c +15 -0
  16. data/ext/libdatadog_api/library_config.c +122 -0
  17. data/ext/libdatadog_api/library_config.h +19 -0
  18. data/ext/libdatadog_api/macos_development.md +3 -3
  19. data/ext/libdatadog_api/process_discovery.c +117 -0
  20. data/ext/libdatadog_api/process_discovery.h +5 -0
  21. data/ext/libdatadog_extconf_helpers.rb +1 -1
  22. data/lib/datadog/appsec/actions_handler.rb +3 -2
  23. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  24. data/lib/datadog/appsec/api_security.rb +9 -0
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
  26. data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
  27. data/lib/datadog/appsec/autoload.rb +1 -1
  28. data/lib/datadog/appsec/component.rb +11 -4
  29. data/lib/datadog/appsec/configuration/settings.rb +31 -18
  30. data/lib/datadog/appsec/context.rb +1 -1
  31. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  32. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  33. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  34. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
  35. data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
  36. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
  38. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
  39. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  40. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  41. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  42. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  43. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  44. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  47. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
  48. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  49. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  50. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  51. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  52. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  53. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  54. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  55. data/lib/datadog/appsec/event.rb +85 -95
  56. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
  57. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  58. data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
  59. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  60. data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
  61. data/lib/datadog/appsec/processor.rb +1 -1
  62. data/lib/datadog/appsec/remote.rb +14 -13
  63. data/lib/datadog/appsec/response.rb +6 -6
  64. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  65. data/lib/datadog/appsec/security_event.rb +39 -0
  66. data/lib/datadog/appsec.rb +1 -1
  67. data/lib/datadog/core/buffer/random.rb +18 -2
  68. data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -5
  69. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  70. data/lib/datadog/core/configuration/components.rb +48 -30
  71. data/lib/datadog/core/configuration/components_state.rb +23 -0
  72. data/lib/datadog/core/configuration/option.rb +79 -43
  73. data/lib/datadog/core/configuration/option_definition.rb +4 -4
  74. data/lib/datadog/core/configuration/options.rb +1 -1
  75. data/lib/datadog/core/configuration/settings.rb +20 -10
  76. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  77. data/lib/datadog/core/configuration.rb +40 -16
  78. data/lib/datadog/core/crashtracking/component.rb +3 -10
  79. data/lib/datadog/core/encoding.rb +1 -1
  80. data/lib/datadog/core/environment/cgroup.rb +10 -12
  81. data/lib/datadog/core/environment/container.rb +38 -40
  82. data/lib/datadog/core/environment/ext.rb +6 -6
  83. data/lib/datadog/core/environment/git.rb +1 -0
  84. data/lib/datadog/core/environment/identity.rb +3 -3
  85. data/lib/datadog/core/environment/platform.rb +3 -3
  86. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  87. data/lib/datadog/core/error.rb +11 -9
  88. data/lib/datadog/core/logger.rb +2 -2
  89. data/lib/datadog/core/metrics/client.rb +20 -21
  90. data/lib/datadog/core/metrics/logging.rb +5 -5
  91. data/lib/datadog/core/process_discovery.rb +32 -0
  92. data/lib/datadog/core/rate_limiter.rb +4 -2
  93. data/lib/datadog/core/remote/client.rb +39 -31
  94. data/lib/datadog/core/remote/component.rb +3 -3
  95. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  96. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  97. data/lib/datadog/core/remote/transport/http/client.rb +1 -1
  98. data/lib/datadog/core/remote/transport/http/config.rb +21 -5
  99. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
  100. data/lib/datadog/core/runtime/metrics.rb +4 -4
  101. data/lib/datadog/core/telemetry/component.rb +78 -53
  102. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  103. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  104. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  105. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  106. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  107. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  108. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  109. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  110. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  111. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  112. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  113. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  114. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  115. data/lib/datadog/core/telemetry/event.rb +17 -472
  116. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  117. data/lib/datadog/core/telemetry/logger.rb +1 -1
  118. data/lib/datadog/core/telemetry/metric.rb +3 -3
  119. data/lib/datadog/core/telemetry/request.rb +3 -3
  120. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  121. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  122. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  123. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  124. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  125. data/lib/datadog/core/telemetry/worker.rb +90 -24
  126. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  127. data/lib/datadog/core/transport/http/builder.rb +13 -13
  128. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  129. data/lib/datadog/core/utils/duration.rb +32 -32
  130. data/lib/datadog/core/utils/forking.rb +2 -2
  131. data/lib/datadog/core/utils/network.rb +6 -6
  132. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  133. data/lib/datadog/core/utils/time.rb +20 -0
  134. data/lib/datadog/core/utils/truncation.rb +21 -0
  135. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  136. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  137. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  138. data/lib/datadog/core/worker.rb +1 -1
  139. data/lib/datadog/core/workers/async.rb +29 -12
  140. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  141. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  142. data/lib/datadog/core.rb +8 -0
  143. data/lib/datadog/di/boot.rb +34 -0
  144. data/lib/datadog/di/remote.rb +2 -0
  145. data/lib/datadog/di.rb +5 -32
  146. data/lib/datadog/error_tracking/collector.rb +87 -0
  147. data/lib/datadog/error_tracking/component.rb +167 -0
  148. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  149. data/lib/datadog/error_tracking/configuration.rb +11 -0
  150. data/lib/datadog/error_tracking/ext.rb +18 -0
  151. data/lib/datadog/error_tracking/extensions.rb +16 -0
  152. data/lib/datadog/error_tracking/filters.rb +77 -0
  153. data/lib/datadog/error_tracking.rb +18 -0
  154. data/lib/datadog/kit/identity.rb +1 -1
  155. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  156. data/lib/datadog/profiling/exporter.rb +1 -1
  157. data/lib/datadog/profiling/ext.rb +0 -1
  158. data/lib/datadog/profiling/flush.rb +1 -1
  159. data/lib/datadog/profiling/http_transport.rb +1 -6
  160. data/lib/datadog/profiling/scheduler.rb +8 -1
  161. data/lib/datadog/profiling/tag_builder.rb +1 -5
  162. data/lib/datadog/tracing/analytics.rb +1 -1
  163. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
  164. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
  165. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  166. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
  167. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  168. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  169. data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
  170. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
  171. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
  172. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  173. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  174. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  175. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  176. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  177. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  178. data/lib/datadog/tracing/contrib/support.rb +28 -0
  179. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  180. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  181. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  182. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  183. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  184. data/lib/datadog/tracing/span_operation.rb +38 -14
  185. data/lib/datadog/tracing/trace_operation.rb +15 -7
  186. data/lib/datadog/tracing/tracer.rb +7 -3
  187. data/lib/datadog/tracing/utils.rb +1 -1
  188. data/lib/datadog/version.rb +1 -1
  189. data/lib/datadog.rb +2 -3
  190. metadata +53 -10
  191. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  192. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  193. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  194. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -29,13 +29,13 @@ module Datadog
29
29
  class << self
30
30
  def hexdigest(type, data)
31
31
  d = case type
32
- when :sha256
33
- ::Digest::SHA256.new
34
- when :sha512
35
- ::Digest::SHA512.new
36
- else
37
- raise InvalidHashTypeError, type
38
- end
32
+ when :sha256
33
+ ::Digest::SHA256.new
34
+ when :sha512
35
+ ::Digest::SHA512.new
36
+ else
37
+ raise InvalidHashTypeError, type
38
+ end
39
39
 
40
40
  while (buf = data.read(DIGEST_CHUNK))
41
41
  d.update(buf)
@@ -30,7 +30,7 @@ module Datadog
30
30
 
31
31
  raise ParseError, "could not parse: #{path.inspect}" if m.nil?
32
32
 
33
- org_id = m['org_id'] ? m['org_id'].to_i : nil
33
+ org_id = m['org_id']&.to_i
34
34
 
35
35
  source = m['source']
36
36
  raise ParseError, 'missing source value' unless source
@@ -28,7 +28,7 @@ module Datadog
28
28
 
29
29
  # Get responses from API
30
30
  yield(api, env)
31
- rescue StandardError => e
31
+ rescue => e
32
32
  message =
33
33
  "Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
34
34
  "Location: #{Array(e.backtrace).first}"
@@ -5,6 +5,7 @@ require 'json'
5
5
  require_relative '../config'
6
6
  require_relative 'client'
7
7
  require_relative '../../../utils/base64'
8
+ require_relative '../../../utils/truncation'
8
9
  require_relative '../../../transport/http/response'
9
10
  require_relative '../../../transport/http/api/endpoint'
10
11
 
@@ -20,9 +21,11 @@ module Datadog
20
21
  include Datadog::Core::Transport::HTTP::Response
21
22
  include Core::Remote::Transport::Config::Response
22
23
 
23
- def initialize(http_response, options = {}) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
24
+ def initialize(http_response, options = {}) # standard:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
24
25
  super(http_response)
25
26
 
27
+ raise AgentErrorResponse.new(http_response.code, http_response.payload) if http_response.code != 200
28
+
26
29
  begin
27
30
  payload = JSON.parse(http_response.payload, symbolize_names: true)
28
31
  rescue JSON::ParserError => e
@@ -130,8 +133,21 @@ module Datadog
130
133
  end
131
134
  end
132
135
 
136
+ # Base class for Remote Configuration Config errors
137
+ class ConfigError < StandardError
138
+ end
139
+
140
+ # When the agent returned an error response to our request
141
+ class AgentErrorResponse < ConfigError
142
+ def initialize(code, body)
143
+ truncated_body = Core::Utils::Truncation.truncate_in_middle(body, 700, 300)
144
+ message = "Agent returned an error response: #{code}: #{truncated_body}"
145
+ super(message)
146
+ end
147
+ end
148
+
133
149
  # When an expected value type is incorrect
134
- class TypeError < StandardError
150
+ class TypeError < ConfigError
135
151
  def initialize(type, value)
136
152
  message = "not a #{type}: #{value.inspect}"
137
153
 
@@ -140,7 +156,7 @@ module Datadog
140
156
  end
141
157
 
142
158
  # When value decoding fails
143
- class DecodeError < StandardError
159
+ class DecodeError < ConfigError
144
160
  def initialize(key, value)
145
161
  message = "could not decode key #{key.inspect}: #{value.inspect}"
146
162
 
@@ -149,7 +165,7 @@ module Datadog
149
165
  end
150
166
 
151
167
  # When value parsing fails
152
- class ParseError < StandardError
168
+ class ParseError < ConfigError
153
169
  def initialize(key, value)
154
170
  message = "could not parse key #{key.inspect}: #{value.inspect}"
155
171
 
@@ -215,7 +231,7 @@ module Datadog
215
231
  env.body = env.request.parcel.data
216
232
 
217
233
  # Query for response
218
- http_response = super(env, &block)
234
+ http_response = super
219
235
 
220
236
  response_options = {}
221
237
 
@@ -79,7 +79,7 @@ module Datadog
79
79
 
80
80
  def call(env, &block)
81
81
  # Query for response
82
- http_response = super(env, &block)
82
+ http_response = super
83
83
 
84
84
  # Process the response
85
85
  body = JSON.parse(http_response.payload, symbolize_names: true) if http_response.ok?
@@ -14,7 +14,7 @@ module Datadog
14
14
  module Runtime
15
15
  # For generating runtime metrics
16
16
  class Metrics < Core::Metrics::Client
17
- def initialize(**options)
17
+ def initialize(telemetry:, **options)
18
18
  super
19
19
 
20
20
  # Initialize service list
@@ -96,7 +96,7 @@ module Datadog
96
96
 
97
97
  def try_flush
98
98
  yield
99
- rescue StandardError => e
99
+ rescue => e
100
100
  Datadog.logger.warn("Error while sending runtime metric. Cause: #{e.class.name} #{e.message}")
101
101
  end
102
102
 
@@ -147,7 +147,7 @@ module Datadog
147
147
  gauge(metric_name, metric_value) if metric_value
148
148
  end
149
149
 
150
- # rubocop:disable Metrics/MethodLength
150
+ # standard:disable Metrics/MethodLength
151
151
  def flush_yjit_stats
152
152
  # Only on Ruby >= 3.2
153
153
  try_flush do
@@ -195,7 +195,7 @@ module Datadog
195
195
  end
196
196
  end
197
197
  end
198
- # rubocop:enable Metrics/MethodLength
198
+ # standard:enable Metrics/MethodLength
199
199
  end
200
200
  end
201
201
  end
@@ -2,12 +2,13 @@
2
2
 
3
3
  require_relative 'emitter'
4
4
  require_relative 'event'
5
- require_relative 'http/transport'
6
5
  require_relative 'metrics_manager'
7
6
  require_relative 'worker'
8
7
  require_relative 'logging'
8
+ require_relative 'transport/http'
9
9
 
10
10
  require_relative '../configuration/ext'
11
+ require_relative '../configuration/agentless_settings_resolver'
11
12
  require_relative '../utils/forking'
12
13
 
13
14
  module Datadog
@@ -15,8 +16,10 @@ module Datadog
15
16
  module Telemetry
16
17
  # Telemetry entrypoint, coordinates sending telemetry events at various points in app lifecycle.
17
18
  # Note: Telemetry does not spawn its worker thread in fork processes, thus no telemetry is sent in forked processes.
19
+ #
20
+ # @api private
18
21
  class Component
19
- attr_reader :enabled, :logger
22
+ attr_reader :enabled, :logger, :transport, :worker
20
23
 
21
24
  include Core::Utils::Forking
22
25
  include Telemetry::Logging
@@ -25,89 +28,100 @@ module Datadog
25
28
  enabled = settings.telemetry.enabled
26
29
  agentless_enabled = settings.telemetry.agentless_enabled
27
30
 
28
- if !agentless_enabled && agent_settings.adapter != Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
29
- enabled = false
30
- logger.debug { "Telemetry disabled. Agent network adapter not supported: #{agent_settings.adapter}" }
31
- end
32
-
33
31
  if agentless_enabled && settings.api_key.nil?
34
32
  enabled = false
35
- logger.debug { 'Telemetry disabled. Agentless telemetry requires an DD_API_KEY variable to be set.' }
33
+ logger.debug { 'Telemetry disabled. Agentless telemetry requires a DD_API_KEY variable to be set.' }
36
34
  end
37
35
 
38
- transport = if agentless_enabled
39
- Datadog::Core::Telemetry::Http::Transport.build_agentless_transport(
40
- api_key: settings.api_key,
41
- dd_site: settings.site,
42
- url_override: settings.telemetry.agentless_url_override
43
- )
44
- else
45
- Datadog::Core::Telemetry::Http::Transport.build_agent_transport(agent_settings)
46
- end
47
-
48
36
  Telemetry::Component.new(
49
- http_transport: transport,
37
+ settings: settings,
38
+ agent_settings: agent_settings,
50
39
  enabled: enabled,
51
- metrics_enabled: enabled && settings.telemetry.metrics_enabled,
52
- heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
53
- metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
54
- dependency_collection: settings.telemetry.dependency_collection,
55
40
  logger: logger,
56
- shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
57
- log_collection_enabled: settings.telemetry.log_collection_enabled
58
41
  )
59
42
  end
60
43
 
61
44
  # @param enabled [Boolean] Determines whether telemetry events should be sent to the API
62
- # @param metrics_enabled [Boolean] Determines whether telemetry metrics should be sent to the API
63
- # @param heartbeat_interval_seconds [Float] How frequently heartbeats will be reported, in seconds.
64
- # @param metrics_aggregation_interval_seconds [Float] How frequently metrics will be aggregated, in seconds.
65
- # @param [Boolean] dependency_collection Whether to send the `app-dependencies-loaded` event
66
- def initialize(
67
- heartbeat_interval_seconds:,
68
- metrics_aggregation_interval_seconds:,
69
- dependency_collection:,
45
+ def initialize( # standard:disable Metrics/MethodLength
46
+ settings:,
47
+ agent_settings:,
70
48
  logger:,
71
- http_transport:,
72
- shutdown_timeout_seconds:,
73
- enabled: true,
74
- metrics_enabled: true,
75
- log_collection_enabled: true
49
+ enabled:
76
50
  )
77
51
  @enabled = enabled
78
- @log_collection_enabled = log_collection_enabled
52
+ @log_collection_enabled = settings.telemetry.log_collection_enabled
79
53
  @logger = logger
80
54
 
81
55
  @metrics_manager = MetricsManager.new(
82
- enabled: enabled && metrics_enabled,
83
- aggregation_interval: metrics_aggregation_interval_seconds
56
+ enabled: @enabled && settings.telemetry.metrics_enabled,
57
+ aggregation_interval: settings.telemetry.metrics_aggregation_interval_seconds,
84
58
  )
85
59
 
60
+ @stopped = false
61
+
62
+ return unless @enabled
63
+
64
+ @transport = if settings.telemetry.agentless_enabled
65
+ agent_settings = Core::Configuration::AgentlessSettingsResolver.call(
66
+ settings,
67
+ host_prefix: 'instrumentation-telemetry-intake',
68
+ url_override: settings.telemetry.agentless_url_override,
69
+ url_override_source: 'c.telemetry.agentless_url_override',
70
+ logger: logger,
71
+ )
72
+ Telemetry::Transport::HTTP.agentless_telemetry(
73
+ agent_settings: agent_settings,
74
+ logger: logger,
75
+ # api_key should have already validated to be
76
+ # not nil by +build+ method above.
77
+ api_key: settings.api_key,
78
+ )
79
+ else
80
+ Telemetry::Transport::HTTP.agent_telemetry(
81
+ agent_settings: agent_settings, logger: logger,
82
+ )
83
+ end
84
+
86
85
  @worker = Telemetry::Worker.new(
87
86
  enabled: @enabled,
88
- heartbeat_interval_seconds: heartbeat_interval_seconds,
89
- metrics_aggregation_interval_seconds: metrics_aggregation_interval_seconds,
90
- emitter: Emitter.new(http_transport: http_transport),
87
+ heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
88
+ metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
89
+ emitter: Emitter.new(
90
+ @transport,
91
+ logger: @logger,
92
+ debug: settings.telemetry.debug,
93
+ ),
91
94
  metrics_manager: @metrics_manager,
92
- dependency_collection: dependency_collection,
95
+ dependency_collection: settings.telemetry.dependency_collection,
93
96
  logger: logger,
94
- shutdown_timeout: shutdown_timeout_seconds
97
+ shutdown_timeout: settings.telemetry.shutdown_timeout_seconds,
95
98
  )
96
-
97
- @stopped = false
98
-
99
- @worker.start
100
99
  end
101
100
 
102
101
  def disable!
103
102
  @enabled = false
104
- @worker.enabled = false
103
+ @worker&.enabled = false
104
+ end
105
+
106
+ def start(initial_event_is_change = false)
107
+ return if !@enabled
108
+
109
+ initial_event = if initial_event_is_change
110
+ Event::SynthAppClientConfigurationChange.new
111
+ else
112
+ Event::AppStarted.new
113
+ end
114
+
115
+ @worker.start(initial_event)
105
116
  end
106
117
 
107
- def stop!
118
+ def shutdown!
108
119
  return if @stopped
109
120
 
110
- @worker.stop(true)
121
+ if defined?(@worker)
122
+ @worker&.stop(true)
123
+ end
124
+
111
125
  @stopped = true
112
126
  end
113
127
 
@@ -129,6 +143,17 @@ module Datadog
129
143
  @worker.enqueue(event)
130
144
  end
131
145
 
146
+ # Wait for the worker to send out all events that have already
147
+ # been queued, up to 15 seconds. Returns whether all events have
148
+ # been flushed.
149
+ #
150
+ # @api private
151
+ def flush
152
+ return if !@enabled || forked?
153
+
154
+ @worker.flush
155
+ end
156
+
132
157
  # Report configuration changes caused by Remote Configuration.
133
158
  def client_configuration_change!(changes)
134
159
  return if !@enabled || forked?
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'request'
4
- require_relative 'http/transport'
4
+ require_relative '../transport/response'
5
5
  require_relative '../utils/sequence'
6
6
  require_relative '../utils/forking'
7
7
 
@@ -10,26 +10,38 @@ module Datadog
10
10
  module Telemetry
11
11
  # Class that emits telemetry events
12
12
  class Emitter
13
- attr_reader :http_transport
13
+ attr_reader :transport, :logger
14
14
 
15
15
  extend Core::Utils::Forking
16
16
 
17
- # @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
18
- # telemetry requests via the agent
19
- def initialize(http_transport:)
20
- @http_transport = http_transport
17
+ # @param transport [Datadog::Core::Telemetry::Transport::Telemetry::Transport]
18
+ # Transport object that can be used to send telemetry requests
19
+ def initialize(transport, logger: Datadog.logger, debug: false)
20
+ @transport = transport
21
+ @logger = logger
22
+ @debug = !!debug
23
+ end
24
+
25
+ def debug?
26
+ @debug
21
27
  end
22
28
 
23
29
  # Retrieves and emits a TelemetryRequest object based on the request type specified
24
30
  def request(event)
25
31
  seq_id = self.class.sequence.next
26
- payload = Request.build_payload(event, seq_id)
27
- res = @http_transport.request(request_type: event.type, payload: payload.to_json)
28
- Datadog.logger.debug { "Telemetry sent for event `#{event.type}` (code: #{res.code.inspect})" }
32
+ payload = Request.build_payload(event, seq_id, debug: debug?)
33
+ res = @transport.send_telemetry(request_type: event.type, payload: payload)
34
+ logger.debug { "Telemetry sent for event `#{event.type}` (response code: #{res.code})" }
29
35
  res
30
36
  rescue => e
31
- Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
32
- Telemetry::Http::InternalErrorResponse.new(e)
37
+ logger.debug {
38
+ "Unable to send telemetry request for event `#{begin
39
+ event.type
40
+ rescue
41
+ "unknown"
42
+ end}`: #{e}"
43
+ }
44
+ Core::Transport::InternalErrorResponse.new(e)
33
45
  end
34
46
 
35
47
  # Initializes a Sequence object to track seq_id if not already initialized; else returns stored
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry class for the 'app-client-configuration-change' event
10
+ class AppClientConfigurationChange < Base
11
+ attr_reader :changes, :origin
12
+
13
+ def type
14
+ 'app-client-configuration-change'
15
+ end
16
+
17
+ def initialize(changes, origin)
18
+ super()
19
+ @changes = changes
20
+ @origin = origin
21
+ end
22
+
23
+ def payload
24
+ {configuration: configuration}
25
+ end
26
+
27
+ def configuration
28
+ config = Datadog.configuration
29
+ seq_id = Event.configuration_sequence.next
30
+
31
+ res = @changes.map do |name, value|
32
+ {
33
+ name: name,
34
+ value: value,
35
+ origin: @origin,
36
+ seq_id: seq_id,
37
+ }
38
+ end
39
+
40
+ unless config.dig('appsec', 'sca_enabled').nil?
41
+ res << {
42
+ name: 'appsec.sca_enabled',
43
+ value: config.appsec.sca_enabled,
44
+ origin: 'code',
45
+ seq_id: seq_id,
46
+ }
47
+ end
48
+
49
+ res
50
+ end
51
+
52
+ def ==(other)
53
+ other.is_a?(AppClientConfigurationChange) && other.changes == @changes && other.origin == @origin
54
+ end
55
+
56
+ alias_method :eql?, :==
57
+
58
+ def hash
59
+ [self.class, @changes, @origin].hash
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry class for the 'app-closing' event
10
+ class AppClosing < Base
11
+ def type
12
+ 'app-closing'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry class for the 'app-dependencies-loaded' event
10
+ class AppDependenciesLoaded < Base
11
+ def type
12
+ 'app-dependencies-loaded'
13
+ end
14
+
15
+ def payload
16
+ {dependencies: dependencies}
17
+ end
18
+
19
+ private
20
+
21
+ def dependencies
22
+ Gem.loaded_specs.collect do |name, gem|
23
+ {
24
+ name: name,
25
+ version: gem.version.to_s,
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry class for the 'app-heartbeat' event
10
+ class AppHeartbeat < Base
11
+ def type
12
+ 'app-heartbeat'
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry class for the 'app-integrations-change' event
10
+ class AppIntegrationsChange < Base
11
+ def type
12
+ 'app-integrations-change'
13
+ end
14
+
15
+ def payload
16
+ {integrations: integrations}
17
+ end
18
+
19
+ private
20
+
21
+ def integrations
22
+ instrumented_integrations = Datadog.configuration.tracing.instrumented_integrations
23
+ Datadog.registry.map do |integration|
24
+ is_instrumented = instrumented_integrations.include?(integration.name)
25
+
26
+ is_enabled = is_instrumented && integration.klass.patcher.patch_successful
27
+
28
+ version = integration.klass.class.version&.to_s
29
+
30
+ res = {
31
+ name: integration.name.to_s,
32
+ enabled: is_enabled,
33
+ version: version,
34
+ compatible: integration.klass.class.compatible?,
35
+ error: (patch_error(integration) if is_instrumented && !is_enabled),
36
+ # TODO: Track if integration is instrumented by manual configuration or by auto instrumentation
37
+ # auto_enabled: is_enabled && ???,
38
+ }
39
+ res.reject! { |_, v| v.nil? }
40
+ res
41
+ end
42
+ end
43
+
44
+ def patch_error(integration)
45
+ patch_error_result = integration.klass.patcher.patch_error_result
46
+ return patch_error_result.compact.to_s if patch_error_result
47
+
48
+ # If no error occurred during patching, but integration is still not instrumented
49
+ "Available?: #{integration.klass.class.available?}" \
50
+ ", Loaded? #{integration.klass.class.loaded?}" \
51
+ ", Compatible? #{integration.klass.class.compatible?}" \
52
+ ", Patchable? #{integration.klass.class.patchable?}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end