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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -2
- data/README.md +1 -1
- data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +10 -1
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +5 -4
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +1 -1
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +391 -0
- data/ext/ddtrace_profiling_native_extension/extconf.rb +2 -0
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +9 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +2 -0
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +2 -1
- data/ext/ddtrace_profiling_native_extension/stack_recorder.h +8 -7
- data/lib/datadog/ci/contrib/cucumber/integration.rb +1 -1
- data/lib/datadog/ci/contrib/rspec/integration.rb +1 -1
- data/lib/datadog/core/configuration/base.rb +9 -0
- data/lib/datadog/core/configuration/components.rb +26 -6
- data/lib/datadog/core/configuration/settings.rb +25 -0
- data/lib/datadog/core/configuration.rb +4 -1
- data/lib/datadog/core/telemetry/client.rb +79 -0
- data/lib/datadog/core/telemetry/collector.rb +234 -0
- data/lib/datadog/core/telemetry/emitter.rb +48 -0
- data/lib/datadog/core/telemetry/event.rb +71 -0
- data/lib/datadog/core/telemetry/ext.rb +11 -0
- data/lib/datadog/core/telemetry/heartbeat.rb +37 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +113 -0
- data/lib/datadog/core/telemetry/http/env.rb +20 -0
- data/lib/datadog/core/telemetry/http/ext.rb +20 -0
- data/lib/datadog/core/telemetry/http/response.rb +68 -0
- data/lib/datadog/core/telemetry/http/transport.rb +53 -0
- data/lib/datadog/core/telemetry/v1/app_event.rb +52 -0
- data/lib/datadog/core/telemetry/v1/application.rb +86 -0
- data/lib/datadog/core/telemetry/v1/configuration.rb +25 -0
- data/lib/datadog/core/telemetry/v1/dependency.rb +36 -0
- data/lib/datadog/core/telemetry/v1/host.rb +51 -0
- data/lib/datadog/core/telemetry/v1/integration.rb +58 -0
- data/lib/datadog/core/telemetry/v1/product.rb +28 -0
- data/lib/datadog/core/telemetry/v1/telemetry_request.rb +100 -0
- data/lib/datadog/core/utils/sequence.rb +5 -0
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +74 -0
- data/lib/datadog/profiling/stack_recorder.rb +1 -1
- data/lib/datadog/profiling.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +2 -0
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +9 -0
- data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/patcher.rb +11 -0
- data/lib/datadog/tracing/contrib/rack/patcher.rb +8 -0
- data/lib/datadog/tracing/trace_operation.rb +1 -1
- data/lib/ddtrace/auto_instrument.rb +7 -0
- data/lib/ddtrace/transport/ext.rb +0 -1
- data/lib/ddtrace/transport/http/adapters/net.rb +1 -0
- data/lib/ddtrace/version.rb +2 -2
- 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
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
244
|
-
|
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,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
|