ddtrace 1.3.0 → 1.4.1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -2
  3. data/README.md +1 -1
  4. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +10 -1
  5. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +5 -4
  6. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +1 -1
  7. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +391 -0
  8. data/ext/ddtrace_profiling_native_extension/extconf.rb +2 -0
  9. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +9 -0
  10. data/ext/ddtrace_profiling_native_extension/profiling.c +2 -0
  11. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +2 -1
  12. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +8 -7
  13. data/lib/datadog/ci/contrib/cucumber/integration.rb +1 -1
  14. data/lib/datadog/ci/contrib/rspec/integration.rb +1 -1
  15. data/lib/datadog/core/configuration/base.rb +9 -0
  16. data/lib/datadog/core/configuration/components.rb +26 -6
  17. data/lib/datadog/core/configuration/settings.rb +25 -0
  18. data/lib/datadog/core/configuration.rb +4 -1
  19. data/lib/datadog/core/telemetry/client.rb +79 -0
  20. data/lib/datadog/core/telemetry/collector.rb +234 -0
  21. data/lib/datadog/core/telemetry/emitter.rb +48 -0
  22. data/lib/datadog/core/telemetry/event.rb +71 -0
  23. data/lib/datadog/core/telemetry/ext.rb +11 -0
  24. data/lib/datadog/core/telemetry/heartbeat.rb +37 -0
  25. data/lib/datadog/core/telemetry/http/adapters/net.rb +113 -0
  26. data/lib/datadog/core/telemetry/http/env.rb +20 -0
  27. data/lib/datadog/core/telemetry/http/ext.rb +20 -0
  28. data/lib/datadog/core/telemetry/http/response.rb +68 -0
  29. data/lib/datadog/core/telemetry/http/transport.rb +53 -0
  30. data/lib/datadog/core/telemetry/v1/app_event.rb +52 -0
  31. data/lib/datadog/core/telemetry/v1/application.rb +86 -0
  32. data/lib/datadog/core/telemetry/v1/configuration.rb +25 -0
  33. data/lib/datadog/core/telemetry/v1/dependency.rb +36 -0
  34. data/lib/datadog/core/telemetry/v1/host.rb +51 -0
  35. data/lib/datadog/core/telemetry/v1/integration.rb +58 -0
  36. data/lib/datadog/core/telemetry/v1/product.rb +28 -0
  37. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +100 -0
  38. data/lib/datadog/core/utils/sequence.rb +5 -0
  39. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +74 -0
  40. data/lib/datadog/profiling/stack_recorder.rb +1 -1
  41. data/lib/datadog/profiling.rb +1 -0
  42. data/lib/datadog/tracing/contrib/extensions.rb +2 -0
  43. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +9 -0
  44. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  45. data/lib/datadog/tracing/contrib/patcher.rb +11 -0
  46. data/lib/datadog/tracing/contrib/rack/patcher.rb +8 -0
  47. data/lib/datadog/tracing/trace_operation.rb +1 -1
  48. data/lib/ddtrace/auto_instrument.rb +7 -0
  49. data/lib/ddtrace/transport/ext.rb +0 -1
  50. data/lib/ddtrace/transport/http/adapters/net.rb +1 -0
  51. data/lib/ddtrace/version.rb +2 -2
  52. metadata +26 -5
@@ -79,6 +79,15 @@ module Datadog
79
79
  options_hash
80
80
  end
81
81
 
82
+ # Retrieves a nested option from a list of symbols
83
+ def dig(*options)
84
+ raise ArgumentError, 'expected at least one option' if options.empty?
85
+
86
+ options.inject(self) do |receiver, option|
87
+ receiver.send(option)
88
+ end
89
+ end
90
+
82
91
  def reset!
83
92
  reset_options!
84
93
  end
@@ -5,6 +5,7 @@ require_relative '../diagnostics/environment_logger'
5
5
  require_relative '../diagnostics/health'
6
6
  require_relative '../logger'
7
7
  require_relative '../runtime/metrics'
8
+ require_relative '../telemetry/client'
8
9
  require_relative '../workers/runtime_metrics'
9
10
 
10
11
  require_relative '../../tracing/tracer'
@@ -51,6 +52,10 @@ module Datadog
51
52
  Core::Workers::RuntimeMetrics.new(options)
52
53
  end
53
54
 
55
+ def build_telemetry(settings)
56
+ Telemetry::Client.new(enabled: settings.telemetry.enabled)
57
+ end
58
+
54
59
  def build_tracer(settings, agent_settings)
55
60
  # If a custom tracer has been provided, use it instead.
56
61
  # Ignore all other options (they should already be configured.)
@@ -235,13 +240,21 @@ module Datadog
235
240
 
236
241
  # NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
237
242
 
238
- trace_identifiers_helper = Profiling::TraceIdentifiers::Helper.new(
239
- tracer: tracer,
240
- endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled
241
- )
243
+ if settings.profiling.advanced.force_enable_new_profiler
244
+ recorder = Datadog::Profiling::StackRecorder.new
245
+ collector = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
246
+ recorder: recorder,
247
+ max_frames: settings.profiling.advanced.max_frames
248
+ )
249
+ else
250
+ trace_identifiers_helper = Profiling::TraceIdentifiers::Helper.new(
251
+ tracer: tracer,
252
+ endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled
253
+ )
242
254
 
243
- recorder = build_profiler_old_recorder(settings)
244
- collector = build_profiler_oldstack_collector(settings, recorder, trace_identifiers_helper)
255
+ recorder = build_profiler_old_recorder(settings)
256
+ collector = build_profiler_oldstack_collector(settings, recorder, trace_identifiers_helper)
257
+ end
245
258
 
246
259
  exporter = build_profiler_exporter(settings, recorder)
247
260
  transport = build_profiler_transport(settings, agent_settings)
@@ -326,6 +339,7 @@ module Datadog
326
339
  :logger,
327
340
  :profiler,
328
341
  :runtime_metrics,
342
+ :telemetry,
329
343
  :tracer
330
344
 
331
345
  def initialize(settings)
@@ -345,6 +359,9 @@ module Datadog
345
359
 
346
360
  # Health metrics
347
361
  @health_metrics = self.class.build_health_metrics(settings)
362
+
363
+ # Telemetry
364
+ @telemetry = self.class.build_telemetry(settings)
348
365
  end
349
366
 
350
367
  # Starts up components
@@ -401,6 +418,9 @@ module Datadog
401
418
 
402
419
  unused_statsd = (old_statsd - (old_statsd & new_statsd))
403
420
  unused_statsd.each(&:close)
421
+
422
+ telemetry.stop!
423
+ telemetry.emit_closing! unless replacement
404
424
  end
405
425
  end
406
426
  # rubocop:enable Metrics/ClassLength
@@ -5,6 +5,7 @@ require 'logger'
5
5
  require_relative 'base'
6
6
  require_relative '../environment/ext'
7
7
  require_relative '../runtime/ext'
8
+ require_relative '../telemetry/ext'
8
9
  require_relative '../../profiling/ext'
9
10
  require_relative '../../tracing/configuration/ext'
10
11
 
@@ -240,6 +241,16 @@ module Datadog
240
241
  o.default { env_to_bool('DD_PROFILING_LEGACY_TRANSPORT_ENABLED', false) }
241
242
  o.lazy
242
243
  end
244
+
245
+ # Forces enabling the new profiler. We do not yet recommend turning on this option.
246
+ #
247
+ # Note that setting this to "false" (or not setting it) will not prevent the new profiler from
248
+ # being automatically used in the future.
249
+ # This option will be deprecated for removal once the new profiler gets enabled by default for all customers.
250
+ option :force_enable_new_profiler do |o|
251
+ o.default { env_to_bool('DD_PROFILING_FORCE_ENABLE_NEW', false) }
252
+ o.lazy
253
+ end
243
254
  end
244
255
 
245
256
  # @public_api
@@ -618,6 +629,20 @@ module Datadog
618
629
  o.default { ENV.fetch(Core::Environment::Ext::ENV_VERSION, nil) }
619
630
  o.lazy
620
631
  end
632
+
633
+ # Client-side telemetry configuration
634
+ # @public_api
635
+ settings :telemetry do
636
+ # Enable telemetry collection. This allows telemetry events to be emitted to the telemetry API.
637
+ #
638
+ # @default `DD_INSTRUMENTATION_TELEMETRY_ENABLED` environment variable, otherwise `false`. In a future release,
639
+ # this value will be changed to `true` by default as documented [here](https://docs.datadoghq.com/tracing/configure_data_security/#telemetry-collection).
640
+ # @return [Boolean]
641
+ option :enabled do |o|
642
+ o.default { env_to_bool(Core::Telemetry::Ext::ENV_ENABLED, false) }
643
+ o.lazy
644
+ end
645
+ end
621
646
  end
622
647
  # rubocop:enable Metrics/BlockLength
623
648
  # rubocop:enable Metrics/ClassLength
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'configuration/components'
4
4
  require_relative 'configuration/settings'
5
+ require_relative 'telemetry/emitter'
5
6
  require_relative 'logger'
6
7
  require_relative 'pin'
7
8
 
@@ -89,7 +90,9 @@ module Datadog
89
90
  if components?
90
91
  replace_components!(configuration, @components)
91
92
  else
92
- build_components(configuration)
93
+ components = build_components(configuration)
94
+ components.telemetry.started!
95
+ components
93
96
  end
94
97
  )
95
98
  end
@@ -0,0 +1,79 @@
1
+ # typed: true
2
+
3
+ require_relative 'emitter'
4
+ require_relative 'heartbeat'
5
+ require_relative '../utils/forking'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Telemetry
10
+ # Telemetry entrypoint, coordinates sending telemetry events at various points in app lifecyle
11
+ class Client
12
+ attr_reader \
13
+ :emitter,
14
+ :enabled,
15
+ :unsupported,
16
+ :worker
17
+
18
+ include Core::Utils::Forking
19
+
20
+ # @param enabled [Boolean] Determines whether telemetry events should be sent to the API
21
+ def initialize(enabled: true)
22
+ @enabled = enabled
23
+ @emitter = Emitter.new
24
+ @stopped = false
25
+ @unsupported = false
26
+ @worker = Telemetry::Heartbeat.new(enabled: @enabled) do
27
+ heartbeat!
28
+ end
29
+ end
30
+
31
+ def disable!
32
+ @enabled = false
33
+ @worker.enabled = false
34
+ end
35
+
36
+ def started!
37
+ return if !@enabled || forked?
38
+
39
+ res = @emitter.request(:'app-started')
40
+
41
+ if res.not_found? # Telemetry is only supported by agent versions 7.34 and up
42
+ Datadog.logger.debug('Agent does not support telemetry; disabling future telemetry events.')
43
+ disable!
44
+ @unsupported = true # Prevent telemetry from getting re-enabled
45
+ end
46
+
47
+ res
48
+ end
49
+
50
+ def emit_closing!
51
+ return if !@enabled || forked?
52
+
53
+ @emitter.request(:'app-closing')
54
+ end
55
+
56
+ def stop!
57
+ return if @stopped
58
+
59
+ @worker.stop(true, 0)
60
+ @stopped = true
61
+ end
62
+
63
+ def integrations_change!
64
+ return if !@enabled || forked?
65
+
66
+ @emitter.request(:'app-integrations-change')
67
+ end
68
+
69
+ private
70
+
71
+ def heartbeat!
72
+ return if !@enabled || forked?
73
+
74
+ @emitter.request(:'app-heartbeat')
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ # typed: true
4
+
5
+ require 'etc'
6
+
7
+ require_relative '../configuration/agent_settings_resolver'
8
+ require_relative '../environment/ext'
9
+ require_relative '../environment/platform'
10
+ require_relative 'v1/application'
11
+ require_relative 'v1/dependency'
12
+ require_relative 'v1/host'
13
+ require_relative 'v1/integration'
14
+ require_relative 'v1/product'
15
+ require_relative '../../../ddtrace/transport/ext'
16
+
17
+ module Datadog
18
+ module Core
19
+ module Telemetry
20
+ # Module defining methods for collecting metadata for telemetry
21
+ # rubocop:disable Metrics/ModuleLength
22
+ module Collector
23
+ include Datadog::Core::Configuration
24
+
25
+ # Forms a hash of configuration key value pairs to be sent in the additional payload
26
+ def additional_payload
27
+ additional_payload_variables
28
+ end
29
+
30
+ # Forms a telemetry application object
31
+ def application
32
+ Telemetry::V1::Application.new(
33
+ env: env,
34
+ language_name: Datadog::Core::Environment::Ext::LANG,
35
+ language_version: Datadog::Core::Environment::Ext::LANG_VERSION,
36
+ products: products,
37
+ runtime_name: Datadog::Core::Environment::Ext::RUBY_ENGINE,
38
+ runtime_version: Datadog::Core::Environment::Ext::ENGINE_VERSION,
39
+ service_name: service_name,
40
+ service_version: service_version,
41
+ tracer_version: library_version
42
+ )
43
+ end
44
+
45
+ # Forms a hash of standard key value pairs to be sent in the app-started event configuration
46
+ def configurations
47
+ configurations = {
48
+ DD_AGENT_HOST: Datadog.configuration.agent.host,
49
+ DD_AGENT_TRANSPORT: agent_transport,
50
+ DD_TRACE_SAMPLE_RATE: format_configuration_value(Datadog.configuration.tracing.sampling.default_rate),
51
+ }
52
+ compact_hash(configurations)
53
+ end
54
+
55
+ # Forms a telemetry app-started dependencies object
56
+ def dependencies
57
+ Gem.loaded_specs.collect do |name, loaded_gem|
58
+ Datadog::Core::Telemetry::V1::Dependency.new(
59
+ name: name, version: loaded_gem.version.to_s, hash: loaded_gem.hash.to_s
60
+ )
61
+ end
62
+ end
63
+
64
+ # Forms a telemetry host object
65
+ def host
66
+ Telemetry::V1::Host.new(
67
+ container_id: Core::Environment::Container.container_id,
68
+ hostname: Core::Environment::Platform.hostname,
69
+ kernel_name: Core::Environment::Platform.kernel_name,
70
+ kernel_release: Core::Environment::Platform.kernel_release,
71
+ kernel_version: Core::Environment::Platform.kernel_version
72
+ )
73
+ end
74
+
75
+ # Forms a telemetry app-started integrations object
76
+ def integrations
77
+ Datadog.registry.map do |integration|
78
+ is_instrumented = instrumented?(integration)
79
+ is_enabled = is_instrumented && patched?(integration)
80
+ Telemetry::V1::Integration.new(
81
+ name: integration.name.to_s,
82
+ enabled: is_enabled,
83
+ version: integration_version(integration),
84
+ compatible: integration_compatible?(integration),
85
+ error: (patch_error(integration) if is_instrumented && !is_enabled),
86
+ auto_enabled: is_enabled ? integration_auto_instrument?(integration) : nil
87
+ )
88
+ end
89
+ end
90
+
91
+ # Returns the runtime ID of the current process
92
+ def runtime_id
93
+ Datadog::Core::Environment::Identity.id
94
+ end
95
+
96
+ # Returns the current as a UNIX timestamp in seconds
97
+ def tracer_time
98
+ Time.now.to_i
99
+ end
100
+
101
+ private
102
+
103
+ TARGET_OPTIONS = [
104
+ 'ci.enabled',
105
+ 'logger.level',
106
+ 'profiling.advanced.code_provenance_enabled',
107
+ 'profiling.advanced.endpoint.collection.enabled',
108
+ 'profiling.enabled',
109
+ 'runtime_metrics.enabled',
110
+ 'tracing.analytics.enabled',
111
+ 'tracing.distributed_tracing.propagation_inject_style',
112
+ 'tracing.distributed_tracing.propagation_extract_style',
113
+ 'tracing.enabled',
114
+ 'tracing.log_injection',
115
+ 'tracing.partial_flush.enabled',
116
+ 'tracing.partial_flush.min_spans_threshold',
117
+ 'tracing.priority_sampling',
118
+ 'tracing.report_hostname',
119
+ 'tracing.sampling.default_rate',
120
+ 'tracing.sampling.rate_limit'
121
+ ].freeze
122
+
123
+ def additional_payload_variables
124
+ # Whitelist of configuration options to send in additional payload object
125
+ configuration = Datadog.configuration
126
+ options = TARGET_OPTIONS.each_with_object({}) do |option, hash|
127
+ split_option = option.split('.')
128
+ hash[option] = format_configuration_value(configuration.dig(*split_option))
129
+ end
130
+
131
+ # Add some more custom additional payload values here
132
+ options['tracing.auto_instrument.enabled'] = !defined?(Datadog::AutoInstrument::LOADED).nil?
133
+ options['tracing.writer_options.buffer_size'] =
134
+ format_configuration_value(configuration.tracing.writer_options[:buffer_size])
135
+ options['tracing.writer_options.flush_interval'] =
136
+ format_configuration_value(configuration.tracing.writer_options[:flush_interval])
137
+ options['logger.instance'] = configuration.logger.instance.class.to_s
138
+ options['appsec.enabled'] = configuration.dig('appsec', 'enabled') if configuration.respond_to?('appsec')
139
+ compact_hash(options)
140
+ end
141
+
142
+ def format_configuration_value(value)
143
+ # TODO: Add float if telemetry starts accepting it
144
+ case value
145
+ when Integer, String, true, false, nil
146
+ value
147
+ else
148
+ value.to_s
149
+ end
150
+ end
151
+
152
+ # Manual implementation of hash.compact used because it is unsupported by older Ruby versions (<2.4)
153
+ def compact_hash(hash)
154
+ hash.delete_if { |_k, v| v.nil? }
155
+ end
156
+
157
+ def env
158
+ Datadog.configuration.env
159
+ end
160
+
161
+ def service_name
162
+ Datadog.configuration.service
163
+ end
164
+
165
+ def service_version
166
+ Datadog.configuration.version
167
+ end
168
+
169
+ def library_version
170
+ Core::Environment::Identity.tracer_version
171
+ end
172
+
173
+ def products
174
+ Telemetry::V1::Product.new(profiler: profiler, appsec: appsec)
175
+ end
176
+
177
+ def profiler
178
+ { version: library_version }
179
+ end
180
+
181
+ def appsec
182
+ { version: library_version }
183
+ end
184
+
185
+ def agent_transport
186
+ adapter = Core::Configuration::AgentSettingsResolver.call(Datadog.configuration).adapter
187
+ if adapter == Datadog::Transport::Ext::UnixSocket::ADAPTER
188
+ 'UDS'
189
+ else
190
+ 'TCP'
191
+ end
192
+ end
193
+
194
+ def instrumented_integrations
195
+ Datadog.configuration.tracing.instrumented_integrations
196
+ end
197
+
198
+ def instrumented?(integration)
199
+ instrumented_integrations.include?(integration.name)
200
+ end
201
+
202
+ def patched?(integration)
203
+ !!integration.klass.patcher.patch_successful
204
+ end
205
+
206
+ def integration_auto_instrument?(integration)
207
+ integration.klass.auto_instrument?
208
+ end
209
+
210
+ def integration_compatible?(integration)
211
+ integration.klass.class.compatible?
212
+ end
213
+
214
+ def integration_version(integration)
215
+ integration.klass.class.version ? integration.klass.class.version.to_s : nil
216
+ end
217
+
218
+ def patch_error(integration)
219
+ patch_error_result = integration.klass.patcher.patch_error_result
220
+ if patch_error_result.nil? # if no error occurred during patching, but integration is still not instrumented
221
+ desc = "Available?: #{integration.klass.class.available?}"
222
+ desc += ", Loaded? #{integration.klass.class.loaded?}"
223
+ desc += ", Compatible? #{integration.klass.class.compatible?}"
224
+ desc += ", Patchable? #{integration.klass.class.patchable?}"
225
+ desc
226
+ else
227
+ patch_error_result.to_s
228
+ end
229
+ end
230
+ end
231
+ # rubocop:enable Metrics/ModuleLength
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,48 @@
1
+ # typed: true
2
+
3
+ require_relative 'event'
4
+ require_relative 'http/transport'
5
+ require_relative '../utils/sequence'
6
+ require_relative '../utils/forking'
7
+
8
+ module Datadog
9
+ module Core
10
+ module Telemetry
11
+ # Class that emits telemetry events
12
+ class Emitter
13
+ attr_reader :http_transport
14
+
15
+ extend Core::Utils::Forking
16
+
17
+ # @param sequence [Datadog::Core::Utils::Sequence] Sequence object that stores and increments a counter
18
+ # @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
19
+ # telemetry requests via the agent
20
+ def initialize(http_transport: Datadog::Core::Telemetry::Http::Transport.new)
21
+ @http_transport = http_transport
22
+ end
23
+
24
+ # Retrieves and emits a TelemetryRequest object based on the request type specified
25
+ # @param request_type [String] the type of telemetry request to collect data for
26
+ def request(request_type)
27
+ begin
28
+ request = Datadog::Core::Telemetry::Event.new.telemetry_request(
29
+ request_type: request_type,
30
+ seq_id: self.class.sequence.next
31
+ ).to_h
32
+ @http_transport.request(request_type: request_type.to_s, payload: request.to_json)
33
+ rescue StandardError => e
34
+ Datadog.logger.debug("Unable to send telemetry request for event `#{request_type}`: #{e}")
35
+ Telemetry::Http::InternalErrorResponse.new(e)
36
+ end
37
+ end
38
+
39
+ # Initializes a Sequence object to track seq_id if not already initialized; else returns stored
40
+ # Sequence object
41
+ def self.sequence
42
+ after_fork! { @sequence = Datadog::Core::Utils::Sequence.new(1) }
43
+ @sequence ||= Datadog::Core::Utils::Sequence.new(1)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,71 @@
1
+ # typed: true
2
+
3
+ require_relative 'collector'
4
+ require_relative 'v1/app_event'
5
+ require_relative 'v1/telemetry_request'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Telemetry
10
+ # Class defining methods to construct a Telemetry event
11
+ class Event
12
+ include Kernel
13
+
14
+ include Telemetry::Collector
15
+
16
+ API_VERSION = 'v1'.freeze
17
+
18
+ attr_reader \
19
+ :api_version
20
+
21
+ def initialize
22
+ @api_version = API_VERSION
23
+ end
24
+
25
+ # Forms a TelemetryRequest object based on the event request_type
26
+ # @param request_type [String] the type of telemetry request to collect data for
27
+ # @param seq_id [Integer] the ID of the request; incremented each time a telemetry request is sent to the API
28
+ def telemetry_request(request_type:, seq_id:)
29
+ Telemetry::V1::TelemetryRequest.new(
30
+ api_version: @api_version,
31
+ application: application,
32
+ host: host,
33
+ payload: payload(request_type),
34
+ request_type: request_type,
35
+ runtime_id: runtime_id,
36
+ seq_id: seq_id,
37
+ tracer_time: tracer_time,
38
+ )
39
+ end
40
+
41
+ private
42
+
43
+ def payload(request_type)
44
+ case request_type
45
+ when :'app-started'
46
+ app_started
47
+ when :'app-closing', :'app-heartbeat'
48
+ {}
49
+ when :'app-integrations-change'
50
+ app_integrations_change
51
+ else
52
+ raise ArgumentError, "Request type invalid, received request_type: #{@request_type}"
53
+ end
54
+ end
55
+
56
+ def app_started
57
+ Telemetry::V1::AppEvent.new(
58
+ dependencies: dependencies,
59
+ integrations: integrations,
60
+ configuration: configurations,
61
+ additional_payload: additional_payload
62
+ )
63
+ end
64
+
65
+ def app_integrations_change
66
+ Telemetry::V1::AppEvent.new(integrations: integrations)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,11 @@
1
+ # typed: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Telemetry
6
+ module Ext
7
+ ENV_ENABLED = 'DD_INSTRUMENTATION_TELEMETRY_ENABLED'.freeze
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ # typed: false
2
+
3
+ require_relative '../worker'
4
+ require_relative '../workers/polling'
5
+
6
+ module Datadog
7
+ module Core
8
+ module Telemetry
9
+ # Periodically (every DEFAULT_INTERVAL_SECONDS) sends a heartbeat event to the telemetry API.
10
+ class Heartbeat < Core::Worker
11
+ include Core::Workers::Polling
12
+
13
+ DEFAULT_INTERVAL_SECONDS = 60
14
+
15
+ def initialize(enabled: true, interval: DEFAULT_INTERVAL_SECONDS, &block)
16
+ # Workers::Polling settings
17
+ self.enabled = enabled
18
+ # Workers::IntervalLoop settings
19
+ self.loop_base_interval = interval
20
+ self.fork_policy = Core::Workers::Async::Thread::FORK_POLICY_STOP
21
+ super(&block)
22
+ start
23
+ end
24
+
25
+ def loop_wait_before_first_iteration?
26
+ true
27
+ end
28
+
29
+ private
30
+
31
+ def start
32
+ perform
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end