datadog 2.14.0 → 2.16.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 (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -1
  3. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +7 -6
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  5. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  6. data/ext/datadog_profiling_native_extension/encoded_profile.c +69 -0
  7. data/ext/datadog_profiling_native_extension/encoded_profile.h +7 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  9. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  10. data/ext/datadog_profiling_native_extension/http_transport.c +25 -32
  11. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  12. data/ext/datadog_profiling_native_extension/stack_recorder.c +22 -21
  13. data/ext/libdatadog_api/crashtracker.c +1 -9
  14. data/ext/libdatadog_api/crashtracker.h +5 -0
  15. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  16. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  17. data/ext/libdatadog_api/init.c +15 -0
  18. data/ext/libdatadog_api/library_config.c +122 -0
  19. data/ext/libdatadog_api/library_config.h +19 -0
  20. data/ext/libdatadog_api/process_discovery.c +117 -0
  21. data/ext/libdatadog_api/process_discovery.h +5 -0
  22. data/lib/datadog/appsec/actions_handler.rb +3 -2
  23. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  24. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  25. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  26. data/lib/datadog/appsec/autoload.rb +1 -1
  27. data/lib/datadog/appsec/component.rb +29 -20
  28. data/lib/datadog/appsec/compressed_json.rb +40 -0
  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 +2 -2
  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 +95 -134
  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 +16 -11
  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/configuration/agentless_settings_resolver.rb +176 -0
  68. data/lib/datadog/core/configuration/components.rb +19 -10
  69. data/lib/datadog/core/configuration/option.rb +61 -25
  70. data/lib/datadog/core/configuration/settings.rb +10 -0
  71. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  72. data/lib/datadog/core/configuration.rb +24 -0
  73. data/lib/datadog/core/crashtracking/component.rb +1 -9
  74. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  75. data/lib/datadog/core/environment/git.rb +1 -0
  76. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  77. data/lib/datadog/core/metrics/client.rb +8 -7
  78. data/lib/datadog/core/process_discovery.rb +32 -0
  79. data/lib/datadog/core/remote/client.rb +7 -0
  80. data/lib/datadog/core/runtime/metrics.rb +1 -1
  81. data/lib/datadog/core/telemetry/component.rb +60 -50
  82. data/lib/datadog/core/telemetry/emitter.rb +17 -11
  83. data/lib/datadog/core/telemetry/event.rb +7 -4
  84. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  85. data/lib/datadog/core/telemetry/metric.rb +5 -5
  86. data/lib/datadog/core/telemetry/request.rb +4 -4
  87. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  88. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  89. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  90. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  91. data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
  92. data/lib/datadog/core/telemetry/worker.rb +45 -0
  93. data/lib/datadog/core/utils/time.rb +12 -0
  94. data/lib/datadog/core/workers/async.rb +20 -2
  95. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  96. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  97. data/lib/datadog/core.rb +8 -0
  98. data/lib/datadog/di/boot.rb +34 -0
  99. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  100. data/lib/datadog/di/remote.rb +2 -0
  101. data/lib/datadog/di/transport/http/diagnostics.rb +0 -1
  102. data/lib/datadog/di/transport/http/input.rb +0 -1
  103. data/lib/datadog/di/transport/http.rb +0 -6
  104. data/lib/datadog/di.rb +5 -32
  105. data/lib/datadog/error_tracking/collector.rb +87 -0
  106. data/lib/datadog/error_tracking/component.rb +167 -0
  107. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  108. data/lib/datadog/error_tracking/configuration.rb +11 -0
  109. data/lib/datadog/error_tracking/ext.rb +18 -0
  110. data/lib/datadog/error_tracking/extensions.rb +16 -0
  111. data/lib/datadog/error_tracking/filters.rb +77 -0
  112. data/lib/datadog/error_tracking.rb +18 -0
  113. data/lib/datadog/kit/identity.rb +1 -1
  114. data/lib/datadog/profiling/collectors/info.rb +3 -0
  115. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  116. data/lib/datadog/profiling/exporter.rb +3 -4
  117. data/lib/datadog/profiling/ext.rb +0 -1
  118. data/lib/datadog/profiling/flush.rb +4 -7
  119. data/lib/datadog/profiling/http_transport.rb +10 -59
  120. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  121. data/lib/datadog/profiling.rb +1 -0
  122. data/lib/datadog/tracing/analytics.rb +1 -1
  123. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  124. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  125. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  126. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  127. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  128. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  129. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  130. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  131. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  132. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  133. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  134. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  135. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  136. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  137. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  138. data/lib/datadog/tracing/span_event.rb +1 -1
  139. data/lib/datadog/tracing/span_operation.rb +38 -14
  140. data/lib/datadog/tracing/trace_operation.rb +15 -7
  141. data/lib/datadog/tracing/tracer.rb +7 -3
  142. data/lib/datadog/tracing/utils.rb +1 -1
  143. data/lib/datadog/version.rb +1 -1
  144. data/lib/datadog.rb +2 -3
  145. metadata +40 -10
  146. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  147. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  148. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  149. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -140,6 +140,13 @@ module Datadog
140
140
  "ruby.gem.libdatadog.platform:#{gem_spec('libdatadog').platform}",
141
141
  ]
142
142
 
143
+ if (git_repository_url = Core::Environment::Git.git_repository_url)
144
+ client_tracer_tags << "git.repository_url:#{git_repository_url}"
145
+ end
146
+ if (git_commit_sha = Core::Environment::Git.git_commit_sha)
147
+ client_tracer_tags << "git.commit.sha:#{git_commit_sha}"
148
+ end
149
+
143
150
  client_tracer = {
144
151
  runtime_id: Core::Environment::Identity.id,
145
152
  language: Core::Environment::Identity.lang,
@@ -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
@@ -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
@@ -16,7 +17,7 @@ module Datadog
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.
18
19
  class Component
19
- attr_reader :enabled, :logger
20
+ attr_reader :enabled, :logger, :transport, :worker
20
21
 
21
22
  include Core::Utils::Forking
22
23
  include Telemetry::Logging
@@ -25,89 +26,87 @@ module Datadog
25
26
  enabled = settings.telemetry.enabled
26
27
  agentless_enabled = settings.telemetry.agentless_enabled
27
28
 
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
29
  if agentless_enabled && settings.api_key.nil?
34
30
  enabled = false
35
- logger.debug { 'Telemetry disabled. Agentless telemetry requires an DD_API_KEY variable to be set.' }
31
+ logger.debug { 'Telemetry disabled. Agentless telemetry requires a DD_API_KEY variable to be set.' }
36
32
  end
37
33
 
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
34
  Telemetry::Component.new(
49
- http_transport: transport,
35
+ settings: settings,
36
+ agent_settings: agent_settings,
50
37
  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
38
  logger: logger,
56
- shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
57
- log_collection_enabled: settings.telemetry.log_collection_enabled
58
39
  )
59
40
  end
60
41
 
61
42
  # @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:,
43
+ def initialize( # rubocop: disable Metrics/MethodLength
44
+ settings:,
45
+ agent_settings:,
70
46
  logger:,
71
- http_transport:,
72
- shutdown_timeout_seconds:,
73
- enabled: true,
74
- metrics_enabled: true,
75
- log_collection_enabled: true
47
+ enabled:
76
48
  )
77
49
  @enabled = enabled
78
- @log_collection_enabled = log_collection_enabled
50
+ @log_collection_enabled = settings.telemetry.log_collection_enabled
79
51
  @logger = logger
80
52
 
81
53
  @metrics_manager = MetricsManager.new(
82
- enabled: enabled && metrics_enabled,
83
- aggregation_interval: metrics_aggregation_interval_seconds
54
+ enabled: @enabled && settings.telemetry.metrics_enabled,
55
+ aggregation_interval: settings.telemetry.metrics_aggregation_interval_seconds,
84
56
  )
85
57
 
58
+ @stopped = false
59
+
60
+ return unless @enabled
61
+
62
+ @transport = if settings.telemetry.agentless_enabled
63
+ agent_settings = Core::Configuration::AgentlessSettingsResolver.call(
64
+ settings,
65
+ host_prefix: 'instrumentation-telemetry-intake',
66
+ url_override: settings.telemetry.agentless_url_override,
67
+ url_override_source: 'c.telemetry.agentless_url_override',
68
+ logger: logger,
69
+ )
70
+ Telemetry::Transport::HTTP.agentless_telemetry(
71
+ agent_settings: agent_settings,
72
+ logger: logger,
73
+ # api_key should have already validated to be
74
+ # not nil by +build+ method above.
75
+ api_key: settings.api_key,
76
+ )
77
+ else
78
+ Telemetry::Transport::HTTP.agent_telemetry(
79
+ agent_settings: agent_settings, logger: logger,
80
+ )
81
+ end
82
+
86
83
  @worker = Telemetry::Worker.new(
87
84
  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),
85
+ heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
86
+ metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
87
+ emitter: Emitter.new(
88
+ @transport,
89
+ logger: @logger,
90
+ debug: settings.telemetry.debug,
91
+ ),
91
92
  metrics_manager: @metrics_manager,
92
- dependency_collection: dependency_collection,
93
+ dependency_collection: settings.telemetry.dependency_collection,
93
94
  logger: logger,
94
- shutdown_timeout: shutdown_timeout_seconds
95
+ shutdown_timeout: settings.telemetry.shutdown_timeout_seconds,
95
96
  )
96
97
 
97
- @stopped = false
98
-
99
98
  @worker.start
100
99
  end
101
100
 
102
101
  def disable!
103
102
  @enabled = false
104
- @worker.enabled = false
103
+ @worker&.enabled = false
105
104
  end
106
105
 
107
106
  def stop!
108
107
  return if @stopped
109
108
 
110
- @worker.stop(true)
109
+ @worker&.stop(true)
111
110
  @stopped = true
112
111
  end
113
112
 
@@ -129,6 +128,17 @@ module Datadog
129
128
  @worker.enqueue(event)
130
129
  end
131
130
 
131
+ # Wait for the worker to send out all events that have already
132
+ # been queued, up to 15 seconds. Returns whether all events have
133
+ # been flushed.
134
+ #
135
+ # @api private
136
+ def flush
137
+ return if !@enabled || forked?
138
+
139
+ @worker.flush
140
+ end
141
+
132
142
  # Report configuration changes caused by Remote Configuration.
133
143
  def client_configuration_change!(changes)
134
144
  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,32 @@ 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 { "Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}" }
38
+ Core::Transport::InternalErrorResponse.new(e)
33
39
  end
34
40
 
35
41
  # Initializes a Sequence object to track seq_id if not already initialized; else returns stored
@@ -74,10 +74,9 @@ module Datadog
74
74
  profiler: {
75
75
  enabled: Datadog::Profiling.enabled?,
76
76
  },
77
- # DEV: Not implemented yet
78
- # dynamic_instrumentation: {
79
- # enabled: true,
80
- # }
77
+ dynamic_instrumentation: {
78
+ enabled: defined?(Datadog::DI) && Datadog::DI.respond_to?(:enabled?) && Datadog::DI.enabled?,
79
+ }
81
80
  }
82
81
 
83
82
  if (unsupported_reason = Datadog::Profiling.unsupported_reason)
@@ -91,6 +90,7 @@ module Datadog
91
90
  end
92
91
 
93
92
  TARGET_OPTIONS = %w[
93
+ dynamic_instrumentation.enabled
94
94
  logger.level
95
95
  profiling.advanced.code_provenance_enabled
96
96
  profiling.advanced.endpoint.collection.enabled
@@ -114,6 +114,9 @@ module Datadog
114
114
  seq_id = Event.configuration_sequence.next
115
115
 
116
116
  list = [
117
+ conf_value('DD_GIT_REPOSITORY_URL', Core::Environment::Git.git_repository_url, seq_id, 'env_var'),
118
+ conf_value('DD_GIT_COMMIT_SHA', Core::Environment::Git.git_commit_sha, seq_id, 'env_var'),
119
+
117
120
  conf_value('DD_AGENT_HOST', config.agent.host, seq_id),
118
121
  conf_value('DD_AGENT_TRANSPORT', agent_transport(config), seq_id),
119
122
  conf_value('DD_TRACE_SAMPLE_RATE', to_value(config.tracing.sampling.default_rate), seq_id),
@@ -1,108 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../response'
3
+ # datadog-ci-rb versions 1.15.0 and lower require this file and guard
4
+ # the require with a rescue of StandardError. Unfortunately LoadError,
5
+ # which would be raised if the file is missing, is not a subclass of
6
+ # StandardError and thus would not be caught by the rescue.
7
+ # We provide this file with a dummy class in it to avoid exceptions
8
+ # in datadog-ci-rb until version 2.0 is released.
9
+ #
10
+ # Note that datadog-ci-rb patches telemetry transport to be "real" even when
11
+ # webmock is used; this patching won't work with datadog-ci-rb versions
12
+ # 1.15.0 and older and dd-trace-rb 2.16.0 and newer. There will be no
13
+ # errors/exceptions reported but telemetry events will not be sent.
4
14
 
5
15
  module Datadog
6
16
  module Core
7
17
  module Telemetry
8
18
  module Http
9
19
  module Adapters
10
- # Class defining methods to make http requests via NET
11
- class Net
12
- attr_reader \
13
- :hostname,
14
- :port,
15
- :timeout,
16
- :ssl
17
-
18
- DEFAULT_TIMEOUT = 2
19
-
20
- def initialize(hostname:, port: nil, timeout: DEFAULT_TIMEOUT, ssl: true)
21
- @hostname = hostname
22
- @port = port
23
- @timeout = timeout
24
- @ssl = ssl.nil? || ssl
25
- end
26
-
27
- def open(&block)
28
- req = ::Net::HTTP.new(@hostname, @port)
29
-
30
- req.use_ssl = @ssl
31
- req.open_timeout = req.read_timeout = @timeout
32
-
33
- req.start(&block)
34
- end
35
-
36
- def post(env)
37
- post = ::Net::HTTP::Post.new(env.path, env.headers)
38
- post.body = env.body
39
-
40
- http_response = open do |http|
41
- http.request(post)
42
- end
43
-
44
- Response.new(http_response)
45
- rescue StandardError => e
46
- Datadog.logger.debug("Unable to send telemetry event to agent: #{e}")
47
- Telemetry::Http::InternalErrorResponse.new(e)
48
- end
49
-
50
- # Data structure for an HTTP Response
51
- class Response
52
- include Datadog::Core::Telemetry::Http::Response
53
-
54
- attr_reader :http_response
55
-
56
- def initialize(http_response)
57
- @http_response = http_response
58
- end
59
-
60
- def payload
61
- return super if http_response.nil?
62
-
63
- http_response.body
64
- end
65
-
66
- def code
67
- return super if http_response.nil?
68
-
69
- http_response.code.to_i
70
- end
71
-
72
- def ok?
73
- return super if http_response.nil?
74
-
75
- code.between?(200, 299)
76
- end
77
-
78
- def unsupported?
79
- return super if http_response.nil?
80
-
81
- code == 415
82
- end
83
-
84
- def not_found?
85
- return super if http_response.nil?
86
-
87
- code == 404
88
- end
89
-
90
- def client_error?
91
- return super if http_response.nil?
92
-
93
- code.between?(400, 499)
94
- end
95
-
96
- def server_error?
97
- return super if http_response.nil?
98
-
99
- code.between?(500, 599)
100
- end
101
-
102
- def inspect
103
- "#{super}, http_response:#{http_response}"
104
- end
105
- end
20
+ class Net # rubocop:disable Lint/EmptyClass
106
21
  end
107
22
  end
108
23
  end
@@ -108,9 +108,9 @@ module Datadog
108
108
  value = value.to_i
109
109
 
110
110
  if values.empty?
111
- values << [Time.now.to_i, value]
111
+ values << [Core::Utils::Time.now.to_i, value]
112
112
  else
113
- values[0][0] = Time.now.to_i
113
+ values[0][0] = Core::Utils::Time.now.to_i
114
114
  values[0][1] += value
115
115
  end
116
116
  nil
@@ -129,9 +129,9 @@ module Datadog
129
129
 
130
130
  def track(value)
131
131
  if values.empty?
132
- values << [Time.now.to_i, value]
132
+ values << [Core::Utils::Time.now.to_i, value]
133
133
  else
134
- values[0][0] = Time.now.to_i
134
+ values[0][0] = Core::Utils::Time.now.to_i
135
135
  values[0][1] = value
136
136
  end
137
137
  nil
@@ -155,7 +155,7 @@ module Datadog
155
155
 
156
156
  def track(value = 1.0)
157
157
  @value += value
158
- @values = [[Time.now.to_i, @value / interval]]
158
+ @values = [[Core::Utils::Time.now.to_i, @value / interval]]
159
159
  nil
160
160
  end
161
161
  end
@@ -11,17 +11,17 @@ module Datadog
11
11
  class << self
12
12
  using Core::Utils::Hash::Refinement
13
13
 
14
- def build_payload(event, seq_id)
14
+ def build_payload(event, seq_id, api_version: 'v2', debug: false)
15
15
  hash = {
16
- api_version: Http::Ext::API_VERSION,
16
+ api_version: api_version,
17
17
  application: application,
18
- debug: false,
18
+ debug: debug,
19
19
  host: host,
20
20
  payload: event.payload,
21
21
  request_type: event.type,
22
22
  runtime_id: Core::Environment::Identity.id,
23
23
  seq_id: seq_id,
24
- tracer_time: Time.now.to_i,
24
+ tracer_time: Core::Utils::Time.now.to_i,
25
25
  }
26
26
  hash.compact!
27
27
  hash
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../encoding'
4
+ require_relative '../../../transport/http/api/map'
5
+ require_relative '../../../transport/http/api/instance'
6
+ require_relative '../../../transport/http/api/spec'
7
+ require_relative 'telemetry'
8
+
9
+ module Datadog
10
+ module Core
11
+ module Telemetry
12
+ module Transport
13
+ module HTTP
14
+ # Namespace for API components
15
+ module API
16
+ # Default API versions
17
+ AGENT_TELEMETRY = 'agent_telemetry'
18
+ AGENTLESS_TELEMETRY = 'agentless_telemetry'
19
+
20
+ module_function
21
+
22
+ def defaults
23
+ Datadog::Core::Transport::HTTP::API::Map[
24
+ AGENT_TELEMETRY => Telemetry::API::Spec.new do |s|
25
+ s.telemetry = Telemetry::API::Endpoint.new(
26
+ '/telemetry/proxy/api/v2/apmtelemetry',
27
+ Core::Encoding::JSONEncoder,
28
+ )
29
+ end,
30
+ AGENTLESS_TELEMETRY => Telemetry::API::Spec.new do |s|
31
+ s.telemetry = Telemetry::API::Endpoint.new(
32
+ '/api/v2/apmtelemetry',
33
+ Core::Encoding::JSONEncoder,
34
+ )
35
+ end,
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../transport/http/env'
4
+ require_relative '../../../transport/http/response'
5
+
6
+ # TODO: Decouple transport/http/client
7
+ #
8
+ # The standard one does `include Transport::HTTP::Statistics` and performs
9
+ # stats updates, which may or may not be desirable in general.
10
+
11
+ module Datadog
12
+ module Core
13
+ module Telemetry
14
+ module Transport
15
+ module HTTP
16
+ # Routes, encodes, and sends DI data to the trace agent via HTTP.
17
+ class Client
18
+ attr_reader :api, :logger
19
+
20
+ def initialize(api, logger:)
21
+ @api = api
22
+ @logger = logger
23
+ end
24
+
25
+ def send_request(request, &block)
26
+ # Build request into env
27
+ env = build_env(request)
28
+
29
+ # Get responses from API
30
+ yield(api, env)
31
+ rescue => e
32
+ message =
33
+ "Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
34
+ "Location: #{Array(e.backtrace).first}"
35
+
36
+ logger.debug(message)
37
+
38
+ Datadog::Core::Transport::InternalErrorResponse.new(e)
39
+ end
40
+
41
+ def build_env(request)
42
+ Datadog::Core::Transport::HTTP::Env.new(request)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../transport/http/api/endpoint'
4
+ require_relative '../../../transport/http/api/instance'
5
+ require_relative '../../../transport/http/api/spec'
6
+ require_relative '../../../transport/request'
7
+ require_relative 'client'
8
+
9
+ module Datadog
10
+ module Core
11
+ module Telemetry
12
+ module Transport
13
+ module HTTP
14
+ module Telemetry
15
+ module Client
16
+ def send_telemetry_payload(request)
17
+ send_request(request) do |api, env| # steep:ignore
18
+ api.send_telemetry(env)
19
+ end
20
+ end
21
+ end
22
+
23
+ module API
24
+ class Instance < Core::Transport::HTTP::API::Instance
25
+ def send_telemetry(env)
26
+ raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('telemetry', self) unless spec.is_a?(Telemetry::API::Spec)
27
+
28
+ spec.send_telemetry(env) do |request_env|
29
+ call(request_env)
30
+ end
31
+ end
32
+ end
33
+
34
+ class Spec < Core::Transport::HTTP::API::Spec
35
+ attr_accessor :telemetry
36
+
37
+ def send_telemetry(env, &block)
38
+ raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('telemetry', self) if telemetry.nil?
39
+
40
+ telemetry.call(env, &block)
41
+ end
42
+ end
43
+
44
+ class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
45
+ HEADER_CONTENT_TYPE = 'Content-Type'
46
+
47
+ attr_reader \
48
+ :encoder
49
+
50
+ def initialize(path, encoder)
51
+ super(:post, path)
52
+ @encoder = encoder
53
+ end
54
+
55
+ def call(env, &block)
56
+ # Encode body & type
57
+ env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
58
+ env.headers.update(headers(
59
+ request_type: env.request.request_type,
60
+ api_key: env.request.api_key,
61
+ ))
62
+ env.body = env.request.parcel.data
63
+
64
+ super
65
+ end
66
+
67
+ def headers(request_type:, api_version: 'v2', api_key:)
68
+ {
69
+ Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
70
+ # Provided by encoder
71
+ #'Content-Type' => 'application/json',
72
+ 'DD-Telemetry-API-Version' => api_version,
73
+ 'DD-Telemetry-Request-Type' => request_type,
74
+ 'DD-Client-Library-Language' => Core::Environment::Ext::LANG,
75
+ 'DD-Client-Library-Version' => Core::Environment::Identity.gem_datadog_version_semver2,
76
+
77
+ # Enable debug mode for telemetry
78
+ # 'DD-Telemetry-Debug-Enabled' => 'true',
79
+ }.tap do |result|
80
+ result['DD-API-KEY'] = api_key unless api_key.nil?
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ HTTP::Client.include(Telemetry::Client)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end