ddtrace 1.3.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
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