datadog 2.1.0 → 2.3.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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -1
  3. data/ext/datadog_profiling_loader/extconf.rb +15 -15
  4. data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
  5. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
  6. data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
  7. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +132 -44
  8. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
  10. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
  11. data/ext/datadog_profiling_native_extension/collectors_stack.c +90 -37
  12. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
  17. data/ext/datadog_profiling_native_extension/extconf.rb +69 -62
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
  20. data/ext/datadog_profiling_native_extension/helpers.h +6 -17
  21. data/ext/datadog_profiling_native_extension/http_transport.c +3 -3
  22. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
  23. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
  24. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -126
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -138
  26. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
  27. data/ext/datadog_profiling_native_extension/profiling.c +0 -2
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
  29. data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
  30. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
  31. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
  32. data/ext/datadog_profiling_native_extension/stack_recorder.c +27 -8
  33. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
  34. data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
  35. data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
  36. data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +20 -7
  37. data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
  38. data/ext/libdatadog_api/datadog_ruby_common.h +57 -0
  39. data/ext/libdatadog_api/extconf.rb +108 -0
  40. data/ext/libdatadog_api/macos_development.md +26 -0
  41. data/ext/libdatadog_extconf_helpers.rb +130 -0
  42. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +49 -0
  43. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
  44. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
  45. data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -0
  46. data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
  47. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
  48. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
  49. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
  50. data/lib/datadog/appsec/extensions.rb +1 -0
  51. data/lib/datadog/appsec/processor/actions.rb +1 -1
  52. data/lib/datadog/appsec/response.rb +15 -1
  53. data/lib/datadog/appsec.rb +1 -0
  54. data/lib/datadog/core/configuration/components.rb +17 -12
  55. data/lib/datadog/core/configuration/settings.rb +93 -7
  56. data/lib/datadog/core/configuration.rb +3 -17
  57. data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
  58. data/lib/datadog/core/crashtracking/component.rb +111 -0
  59. data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
  60. data/lib/datadog/core/deprecations.rb +58 -0
  61. data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
  62. data/lib/datadog/core/environment/yjit.rb +5 -0
  63. data/lib/datadog/core/runtime/ext.rb +1 -0
  64. data/lib/datadog/core/runtime/metrics.rb +6 -0
  65. data/lib/datadog/core/telemetry/component.rb +154 -0
  66. data/lib/datadog/core/telemetry/emitter.rb +9 -11
  67. data/lib/datadog/core/telemetry/event.rb +132 -26
  68. data/lib/datadog/core/telemetry/ext.rb +3 -0
  69. data/lib/datadog/core/telemetry/http/adapters/net.rb +11 -13
  70. data/lib/datadog/core/telemetry/http/ext.rb +3 -0
  71. data/lib/datadog/core/telemetry/http/transport.rb +38 -9
  72. data/lib/datadog/core/telemetry/logging.rb +35 -0
  73. data/lib/datadog/core/telemetry/metric.rb +167 -0
  74. data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
  75. data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
  76. data/lib/datadog/core/telemetry/request.rb +1 -1
  77. data/lib/datadog/core/telemetry/worker.rb +173 -0
  78. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
  79. data/lib/datadog/core/utils/only_once_successful.rb +76 -0
  80. data/lib/datadog/core.rb +2 -19
  81. data/lib/datadog/kit/appsec/events.rb +2 -4
  82. data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
  83. data/lib/datadog/opentelemetry/sdk/span_processor.rb +15 -2
  84. data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
  85. data/lib/datadog/profiling/collectors/code_provenance.rb +24 -11
  86. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +17 -17
  87. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
  88. data/lib/datadog/profiling/collectors/info.rb +3 -3
  89. data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
  90. data/lib/datadog/profiling/component.rb +85 -90
  91. data/lib/datadog/profiling/exporter.rb +3 -3
  92. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
  93. data/lib/datadog/profiling/ext.rb +21 -21
  94. data/lib/datadog/profiling/flush.rb +1 -1
  95. data/lib/datadog/profiling/http_transport.rb +8 -6
  96. data/lib/datadog/profiling/load_native_extension.rb +5 -5
  97. data/lib/datadog/profiling/preload.rb +1 -1
  98. data/lib/datadog/profiling/profiler.rb +5 -8
  99. data/lib/datadog/profiling/scheduler.rb +31 -25
  100. data/lib/datadog/profiling/tag_builder.rb +2 -2
  101. data/lib/datadog/profiling/tasks/exec.rb +5 -5
  102. data/lib/datadog/profiling/tasks/setup.rb +16 -35
  103. data/lib/datadog/profiling.rb +5 -5
  104. data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
  105. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
  106. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
  107. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
  108. data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
  109. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
  110. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
  111. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
  112. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  113. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  114. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  115. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  116. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  117. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  118. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  119. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  120. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  121. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  122. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +2 -1
  123. data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
  124. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
  125. data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
  126. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
  127. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
  128. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
  129. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
  130. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
  131. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
  132. data/lib/datadog/tracing/contrib/analytics.rb +5 -0
  133. data/lib/datadog/tracing/contrib/ext.rb +14 -0
  134. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
  135. data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
  136. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
  137. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +28 -0
  138. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
  139. data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
  140. data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
  141. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
  142. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
  143. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
  144. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
  145. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
  146. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
  147. data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -0
  148. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
  149. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
  150. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  151. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
  152. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
  153. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  154. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
  155. data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
  156. data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
  157. data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
  158. data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
  159. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
  160. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
  161. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
  162. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  163. data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
  164. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  165. data/lib/datadog/tracing/distributed/propagation.rb +9 -2
  166. data/lib/datadog/tracing/distributed/trace_context.rb +3 -2
  167. data/lib/datadog/tracing/metadata/errors.rb +9 -1
  168. data/lib/datadog/tracing/metadata/ext.rb +4 -0
  169. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  170. data/lib/datadog/tracing/span.rb +9 -2
  171. data/lib/datadog/tracing/span_event.rb +41 -0
  172. data/lib/datadog/tracing/span_operation.rb +9 -4
  173. data/lib/datadog/tracing/trace_operation.rb +7 -3
  174. data/lib/datadog/tracing/trace_segment.rb +4 -1
  175. data/lib/datadog/tracing/tracer.rb +9 -2
  176. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
  177. data/lib/datadog/tracing.rb +5 -1
  178. data/lib/datadog/version.rb +2 -2
  179. metadata +43 -12
  180. data/lib/datadog/core/telemetry/client.rb +0 -95
  181. data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
  182. data/lib/datadog/profiling/crashtracker.rb +0 -91
  183. data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -16,22 +16,20 @@ module Datadog
16
16
 
17
17
  # @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
18
18
  # telemetry requests via the agent
19
- def initialize(http_transport: Datadog::Core::Telemetry::Http::Transport.new)
19
+ def initialize(http_transport:)
20
20
  @http_transport = http_transport
21
21
  end
22
22
 
23
23
  # Retrieves and emits a TelemetryRequest object based on the request type specified
24
24
  def request(event)
25
- begin
26
- seq_id = self.class.sequence.next
27
- payload = Request.build_payload(event, seq_id)
28
- res = @http_transport.request(request_type: event.type, payload: payload.to_json)
29
- Datadog.logger.debug { "Telemetry sent for event `#{event.type}` (code: #{res.code.inspect})" }
30
- res
31
- rescue => e
32
- Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
33
- Telemetry::Http::InternalErrorResponse.new(e)
34
- end
25
+ 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})" }
29
+ res
30
+ rescue => e
31
+ Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
32
+ Telemetry::Http::InternalErrorResponse.new(e)
35
33
  end
36
34
 
37
35
  # Initializes a Sequence object to track seq_id if not already initialized; else returns stored
@@ -3,17 +3,27 @@
3
3
  module Datadog
4
4
  module Core
5
5
  module Telemetry
6
+ # Collection of telemetry events
6
7
  class Event
8
+ extend Core::Utils::Forking
9
+
10
+ # returns sequence that increments every time the configuration changes
11
+ def self.configuration_sequence
12
+ after_fork! { @sequence = Datadog::Core::Utils::Sequence.new(1) }
13
+ @sequence ||= Datadog::Core::Utils::Sequence.new(1)
14
+ end
15
+
7
16
  # Base class for all Telemetry V2 events.
8
17
  class Base
9
18
  # The type of the event.
10
19
  # It must be one of the stings defined in the Telemetry V2
11
20
  # specification for event names.
12
- def type; end
21
+ def type
22
+ raise NotImplementedError, 'Must be implemented by subclass'
23
+ end
13
24
 
14
25
  # The JSON payload for the event.
15
- # @param seq_id [Integer] The sequence ID for the event.
16
- def payload(seq_id)
26
+ def payload
17
27
  {}
18
28
  end
19
29
  end
@@ -24,8 +34,7 @@ module Datadog
24
34
  'app-started'
25
35
  end
26
36
 
27
- def payload(seq_id)
28
- @seq_id = seq_id
37
+ def payload
29
38
  {
30
39
  products: products,
31
40
  configuration: configuration,
@@ -38,6 +47,7 @@ module Datadog
38
47
  private
39
48
 
40
49
  def products
50
+ # @type var products: Hash[Symbol, Hash[Symbol, Object]]
41
51
  products = {
42
52
  appsec: {
43
53
  enabled: Datadog::AppSec.enabled?,
@@ -79,16 +89,19 @@ module Datadog
79
89
  ].freeze
80
90
 
81
91
  # rubocop:disable Metrics/AbcSize
92
+ # rubocop:disable Metrics/MethodLength
82
93
  def configuration
83
94
  config = Datadog.configuration
95
+ seq_id = Event.configuration_sequence.next
84
96
 
85
97
  list = [
86
- conf_value('DD_AGENT_HOST', config.agent.host),
87
- conf_value('DD_AGENT_TRANSPORT', agent_transport(config)),
88
- conf_value('DD_TRACE_SAMPLE_RATE', to_value(config.tracing.sampling.default_rate)),
98
+ conf_value('DD_AGENT_HOST', config.agent.host, seq_id),
99
+ conf_value('DD_AGENT_TRANSPORT', agent_transport(config), seq_id),
100
+ conf_value('DD_TRACE_SAMPLE_RATE', to_value(config.tracing.sampling.default_rate), seq_id),
89
101
  conf_value(
90
102
  'DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED',
91
- config.tracing.contrib.global_default_service_name.enabled
103
+ config.tracing.contrib.global_default_service_name.enabled,
104
+ seq_id
92
105
  ),
93
106
  ]
94
107
 
@@ -97,32 +110,45 @@ module Datadog
97
110
  peer_service_mapping = config.tracing.contrib.peer_service_mapping
98
111
  peer_service_mapping_str = peer_service_mapping.map { |key, value| "#{key}:#{value}" }.join(',')
99
112
  end
100
- list << conf_value('DD_TRACE_PEER_SERVICE_MAPPING', peer_service_mapping_str)
113
+ list << conf_value('DD_TRACE_PEER_SERVICE_MAPPING', peer_service_mapping_str, seq_id)
101
114
 
102
115
  # Whitelist of configuration options to send in additional payload object
103
116
  TARGET_OPTIONS.each do |option|
104
117
  split_option = option.split('.')
105
- list << conf_value(option, to_value(config.dig(*split_option)))
118
+ list << conf_value(option, to_value(config.dig(*split_option)), seq_id)
106
119
  end
107
120
 
108
121
  # Add some more custom additional payload values here
109
122
  list.push(
110
- conf_value('tracing.auto_instrument.enabled', !defined?(Datadog::AutoInstrument::LOADED).nil?),
111
- conf_value('tracing.writer_options.buffer_size', to_value(config.tracing.writer_options[:buffer_size])),
112
- conf_value('tracing.writer_options.flush_interval', to_value(config.tracing.writer_options[:flush_interval])),
113
- conf_value('tracing.opentelemetry.enabled', !defined?(Datadog::OpenTelemetry::LOADED).nil?),
123
+ conf_value('tracing.auto_instrument.enabled', !defined?(Datadog::AutoInstrument::LOADED).nil?, seq_id),
124
+ conf_value(
125
+ 'tracing.writer_options.buffer_size',
126
+ to_value(config.tracing.writer_options[:buffer_size]),
127
+ seq_id
128
+ ),
129
+ conf_value(
130
+ 'tracing.writer_options.flush_interval',
131
+ to_value(config.tracing.writer_options[:flush_interval]),
132
+ seq_id
133
+ ),
134
+ conf_value(
135
+ 'tracing.opentelemetry.enabled',
136
+ !defined?(Datadog::OpenTelemetry::LOADED).nil?,
137
+ seq_id
138
+ ),
114
139
  )
115
- list << conf_value('logger.instance', config.logger.instance.class.to_s) if config.logger.instance
140
+ list << conf_value('logger.instance', config.logger.instance.class.to_s, seq_id) if config.logger.instance
116
141
  if config.respond_to?('appsec')
117
- list << conf_value('appsec.enabled', config.dig('appsec', 'enabled'))
118
- list << conf_value('appsec.sca_enabled', config.dig('appsec', 'sca_enabled'))
142
+ list << conf_value('appsec.enabled', config.dig('appsec', 'enabled'), seq_id)
143
+ list << conf_value('appsec.sca_enabled', config.dig('appsec', 'sca_enabled'), seq_id)
119
144
  end
120
- list << conf_value('ci.enabled', config.dig('ci', 'enabled')) if config.respond_to?('ci')
145
+ list << conf_value('ci.enabled', config.dig('ci', 'enabled'), seq_id) if config.respond_to?('ci')
121
146
 
122
147
  list.reject! { |entry| entry[:value].nil? }
123
148
  list
124
149
  end
125
150
  # rubocop:enable Metrics/AbcSize
151
+ # rubocop:enable Metrics/MethodLength
126
152
 
127
153
  def agent_transport(config)
128
154
  adapter = Core::Configuration::AgentSettingsResolver.call(config).adapter
@@ -133,12 +159,12 @@ module Datadog
133
159
  end
134
160
  end
135
161
 
136
- def conf_value(name, value, origin = 'code')
162
+ def conf_value(name, value, seq_id, origin = 'code')
137
163
  {
138
164
  name: name,
139
165
  value: value,
140
166
  origin: origin,
141
- seq_id: @seq_id,
167
+ seq_id: seq_id,
142
168
  }
143
169
  end
144
170
 
@@ -168,7 +194,7 @@ module Datadog
168
194
  'app-dependencies-loaded'
169
195
  end
170
196
 
171
- def payload(seq_id)
197
+ def payload
172
198
  { dependencies: dependencies }
173
199
  end
174
200
 
@@ -191,7 +217,7 @@ module Datadog
191
217
  'app-integrations-change'
192
218
  end
193
219
 
194
- def payload(seq_id)
220
+ def payload
195
221
  { integrations: integrations }
196
222
  end
197
223
 
@@ -244,18 +270,20 @@ module Datadog
244
270
  @origin = origin
245
271
  end
246
272
 
247
- def payload(seq_id)
248
- { configuration: configuration(seq_id) }
273
+ def payload
274
+ { configuration: configuration }
249
275
  end
250
276
 
251
- def configuration(seq_id)
277
+ def configuration
252
278
  config = Datadog.configuration
279
+ seq_id = Event.configuration_sequence.next
253
280
 
254
281
  res = @changes.map do |name, value|
255
282
  {
256
283
  name: name,
257
284
  value: value,
258
285
  origin: @origin,
286
+ seq_id: seq_id,
259
287
  }
260
288
  end
261
289
 
@@ -285,6 +313,84 @@ module Datadog
285
313
  'app-closing'
286
314
  end
287
315
  end
316
+
317
+ # Telemetry class for the 'generate-metrics' event
318
+ class GenerateMetrics < Base
319
+ def type
320
+ 'generate-metrics'
321
+ end
322
+
323
+ def initialize(namespace, metric_series)
324
+ super()
325
+ @namespace = namespace
326
+ @metric_series = metric_series
327
+ end
328
+
329
+ def payload
330
+ {
331
+ namespace: @namespace,
332
+ series: @metric_series.map(&:to_h)
333
+ }
334
+ end
335
+ end
336
+
337
+ # Telemetry class for the 'logs' event
338
+ class Log < Base
339
+ LEVELS = {
340
+ error: 'ERROR',
341
+ debug: 'DEBUG',
342
+ warn: 'WARN',
343
+ }.freeze
344
+
345
+ def type
346
+ 'logs'
347
+ end
348
+
349
+ def initialize(message:, level:)
350
+ super()
351
+ @message = message
352
+ @level = LEVELS.fetch(level) { |k| raise ArgumentError, "Invalid log level :#{k}" }
353
+ end
354
+
355
+ def payload
356
+ {
357
+ logs: [{
358
+ message: @message,
359
+ level: @level,
360
+ # More optional fields to be added here...
361
+ }]
362
+ }
363
+ end
364
+ end
365
+
366
+ # Telemetry class for the 'distributions' event
367
+ class Distributions < GenerateMetrics
368
+ def type
369
+ 'distributions'
370
+ end
371
+ end
372
+
373
+ # Telemetry class for the 'message-batch' event
374
+ class MessageBatch
375
+ attr_reader :events
376
+
377
+ def type
378
+ 'message-batch'
379
+ end
380
+
381
+ def initialize(events)
382
+ @events = events
383
+ end
384
+
385
+ def payload
386
+ @events.map do |event|
387
+ {
388
+ request_type: event.type,
389
+ payload: event.payload,
390
+ }
391
+ end
392
+ end
393
+ end
288
394
  end
289
395
  end
290
396
  end
@@ -5,11 +5,14 @@ module Datadog
5
5
  module Telemetry
6
6
  module Ext
7
7
  ENV_ENABLED = 'DD_INSTRUMENTATION_TELEMETRY_ENABLED'
8
+ ENV_METRICS_ENABLED = 'DD_TELEMETRY_METRICS_ENABLED'
8
9
  ENV_HEARTBEAT_INTERVAL = 'DD_TELEMETRY_HEARTBEAT_INTERVAL'
10
+ ENV_METRICS_AGGREGATION_INTERVAL = 'DD_TELEMETRY_METRICS_AGGREGATION_INTERVAL'
9
11
  ENV_DEPENDENCY_COLLECTION = 'DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED'
10
12
  ENV_INSTALL_ID = 'DD_INSTRUMENTATION_INSTALL_ID'
11
13
  ENV_INSTALL_TYPE = 'DD_INSTRUMENTATION_INSTALL_TYPE'
12
14
  ENV_INSTALL_TIME = 'DD_INSTRUMENTATION_INSTALL_TIME'
15
+ ENV_AGENTLESS_URL_OVERRIDE = 'DD_TELEMETRY_AGENTLESS_URL'
13
16
  end
14
17
  end
15
18
  end
@@ -15,7 +15,7 @@ module Datadog
15
15
  :timeout,
16
16
  :ssl
17
17
 
18
- DEFAULT_TIMEOUT = 30
18
+ DEFAULT_TIMEOUT = 2
19
19
 
20
20
  def initialize(hostname:, port: nil, timeout: DEFAULT_TIMEOUT, ssl: true)
21
21
  @hostname = hostname
@@ -34,19 +34,17 @@ module Datadog
34
34
  end
35
35
 
36
36
  def post(env)
37
- begin
38
- post = ::Net::HTTP::Post.new(env.path, env.headers)
39
- post.body = env.body
40
-
41
- http_response = open do |http|
42
- http.request(post)
43
- end
44
-
45
- Response.new(http_response)
46
- rescue StandardError => e
47
- Datadog.logger.debug("Unable to send telemetry event to agent: #{e}")
48
- Telemetry::Http::InternalErrorResponse.new(e)
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)
49
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)
50
48
  end
51
49
 
52
50
  # Data structure for an HTTP Response
@@ -17,7 +17,10 @@ module Datadog
17
17
  CONTENT_TYPE_APPLICATION_JSON = 'application/json'
18
18
  API_VERSION = 'v2'
19
19
 
20
+ AGENTLESS_HOST_PREFIX = 'instrumentation-telemetry-intake'
21
+
20
22
  AGENT_ENDPOINT = '/telemetry/proxy/api/v2/apmtelemetry'
23
+ AGENTLESS_ENDPOINT = '/api/v2/apmtelemetry'
21
24
  end
22
25
  end
23
26
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../configuration/settings'
4
+ require_relative '../../environment/ext'
4
5
  require_relative '../../transport/ext'
5
6
  require_relative 'env'
6
7
  require_relative 'ext'
@@ -13,18 +14,42 @@ module Datadog
13
14
  # Class to send telemetry data to Telemetry API
14
15
  # Currently only supports the HTTP protocol.
15
16
  class Transport
17
+ def self.build_agent_transport(agent_settings)
18
+ Transport.new(
19
+ host: agent_settings.hostname,
20
+ port: agent_settings.port,
21
+ path: Http::Ext::AGENT_ENDPOINT
22
+ )
23
+ end
24
+
25
+ def self.build_agentless_transport(api_key:, dd_site:, url_override: nil)
26
+ url = url_override || "https://#{Http::Ext::AGENTLESS_HOST_PREFIX}.#{dd_site}:443"
27
+
28
+ uri = URI.parse(url)
29
+ raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
30
+
31
+ Transport.new(
32
+ host: uri.host,
33
+ port: uri.port || 80,
34
+ path: Http::Ext::AGENTLESS_ENDPOINT,
35
+ ssl: uri.scheme == 'https' || uri.port == 443,
36
+ api_key: api_key
37
+ )
38
+ end
39
+
16
40
  attr_reader \
17
41
  :host,
18
42
  :port,
19
43
  :ssl,
20
- :path
21
-
22
- def initialize
23
- agent_settings = Configuration::AgentSettingsResolver.call(Datadog.configuration)
24
- @host = agent_settings.hostname
25
- @port = agent_settings.port
26
- @ssl = false
27
- @path = Http::Ext::AGENT_ENDPOINT
44
+ :path,
45
+ :api_key
46
+
47
+ def initialize(host:, port:, path:, ssl: false, api_key: nil)
48
+ @host = host
49
+ @port = port
50
+ @ssl = ssl
51
+ @path = path
52
+ @api_key = api_key
28
53
  end
29
54
 
30
55
  def request(request_type:, payload:)
@@ -38,7 +63,7 @@ module Datadog
38
63
  private
39
64
 
40
65
  def headers(request_type:, api_version: Http::Ext::API_VERSION)
41
- {
66
+ result = {
42
67
  Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
43
68
  Ext::HEADER_CONTENT_TYPE => Http::Ext::CONTENT_TYPE_APPLICATION_JSON,
44
69
  Ext::HEADER_DD_TELEMETRY_API_VERSION => api_version,
@@ -49,6 +74,10 @@ module Datadog
49
74
  # Enable debug mode for telemetry
50
75
  # HEADER_TELEMETRY_DEBUG_ENABLED => 'true',
51
76
  }
77
+
78
+ result[Ext::HEADER_DD_API_KEY] = api_key unless api_key.nil?
79
+
80
+ result
52
81
  end
53
82
 
54
83
  def adapter
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'event'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ # Logging interface for sending telemetry logs.
9
+ #
10
+ # Reporting internal error so that we can fix them.
11
+ # IMPORTANT: Make sure to not log any sensitive information.
12
+ module Logging
13
+ module_function
14
+
15
+ def report(exception, level:)
16
+ # Annoymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
17
+ message = exception.class.name || exception.class.inspect
18
+
19
+ event = Event::Log.new(
20
+ message: message,
21
+ level: level
22
+ )
23
+
24
+ if (telemetry = Datadog.send(:components).telemetry)
25
+ telemetry.log!(event)
26
+ else
27
+ Datadog.logger.debug do
28
+ "Attempting to send telemetry log when telemetry component is not ready: #{message}"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Telemetry
6
+ # Telemetry metrics data model (internal Datadog metrics for client libraries)
7
+ module Metric
8
+ # Base class for all metric types
9
+ class Base
10
+ attr_reader :name, :tags, :values, :common
11
+
12
+ # @param name [String] metric name
13
+ # @param tags [Array<String>|Hash{String=>String}] metric tags as hash or array of "tag:val" strings
14
+ # @param common [Boolean] true if the metric is common for all languages, false for Ruby-specific metric
15
+ def initialize(name, tags: {}, common: true)
16
+ @name = name
17
+ @values = []
18
+ @tags = tags_to_array(tags)
19
+ @common = common
20
+ end
21
+
22
+ def id
23
+ @id ||= "#{type}::#{name}::#{tags.join(',')}"
24
+ end
25
+
26
+ def track(value)
27
+ raise NotImplementedError, 'method must be implemented in subclasses'
28
+ end
29
+
30
+ def type
31
+ raise NotImplementedError, 'method must be implemented in subclasses'
32
+ end
33
+
34
+ def to_h
35
+ {
36
+ metric: name,
37
+ points: values,
38
+ type: type,
39
+ tags: tags,
40
+ common: common
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def tags_to_array(tags)
47
+ return tags if tags.is_a?(Array)
48
+
49
+ tags.map { |k, v| "#{k}:#{v}" }
50
+ end
51
+ end
52
+
53
+ # Base class for metrics that require aggregation interval
54
+ class IntervalMetric < Base
55
+ attr_reader :interval
56
+
57
+ # @param name [String] metric name
58
+ # @param tags [Array<String>|Hash{String=>String}] metric tags as hash of array of "tag:val" strings
59
+ # @param common [Boolean] true if the metric is common for all languages, false for Ruby-specific metric
60
+ # @param interval [Integer] metrics aggregation interval in seconds
61
+ def initialize(name, interval:, tags: {}, common: true)
62
+ raise ArgumentError, 'interval must be a positive number' if interval.nil? || interval <= 0
63
+
64
+ super(name, tags: tags, common: common)
65
+
66
+ @interval = interval
67
+ end
68
+
69
+ def to_h
70
+ res = super
71
+ res[:interval] = interval
72
+ res
73
+ end
74
+ end
75
+
76
+ # Count metric adds up all the submitted values in a time interval. This would be suitable for a
77
+ # metric tracking the number of website hits, for instance.
78
+ class Count < Base
79
+ TYPE = 'count'
80
+
81
+ def type
82
+ TYPE
83
+ end
84
+
85
+ def track(value)
86
+ value = value.to_i
87
+
88
+ if values.empty?
89
+ values << [Time.now.to_i, value]
90
+ else
91
+ values[0][0] = Time.now.to_i
92
+ values[0][1] += value
93
+ end
94
+ nil
95
+ end
96
+ end
97
+
98
+ # A gauge type takes the last value reported during the interval. This type would make sense for tracking RAM or
99
+ # CPU usage, where taking the last value provides a representative picture of the host’s behavior during the time
100
+ # interval.
101
+ class Gauge < IntervalMetric
102
+ TYPE = 'gauge'
103
+
104
+ def type
105
+ TYPE
106
+ end
107
+
108
+ def track(value)
109
+ if values.empty?
110
+ values << [Time.now.to_i, value]
111
+ else
112
+ values[0][0] = Time.now.to_i
113
+ values[0][1] = value
114
+ end
115
+ nil
116
+ end
117
+ end
118
+
119
+ # The rate type takes the count and divides it by the length of the time interval. This is useful if you’re
120
+ # interested in the number of hits per second.
121
+ class Rate < IntervalMetric
122
+ TYPE = 'rate'
123
+
124
+ def initialize(name, interval:, tags: {}, common: true)
125
+ super
126
+
127
+ @value = 0.0
128
+ end
129
+
130
+ def type
131
+ TYPE
132
+ end
133
+
134
+ def track(value = 1.0)
135
+ @value += value
136
+ @values = [[Time.now.to_i, @value / interval]]
137
+ nil
138
+ end
139
+ end
140
+
141
+ # Distribution metric represents the global statistical distribution of a set of values.
142
+ class Distribution < Base
143
+ TYPE = 'distributions'
144
+
145
+ def type
146
+ TYPE
147
+ end
148
+
149
+ def track(value)
150
+ values << value
151
+ nil
152
+ end
153
+
154
+ # distribution metric data does not have type field
155
+ def to_h
156
+ {
157
+ metric: name,
158
+ points: values,
159
+ tags: tags,
160
+ common: common
161
+ }
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end