datadog 2.15.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -2
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
- data/ext/libdatadog_api/crashtracker.c +1 -9
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
- data/ext/libdatadog_api/init.c +15 -0
- data/ext/libdatadog_api/library_config.c +122 -0
- data/ext/libdatadog_api/library_config.h +19 -0
- data/ext/libdatadog_api/process_discovery.c +117 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/lib/datadog/appsec/actions_handler.rb +3 -2
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -4
- data/lib/datadog/appsec/configuration/settings.rb +31 -18
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
- data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
- data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
- data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/event.rb +85 -95
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
- data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
- data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
- data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
- data/lib/datadog/appsec/processor.rb +1 -1
- data/lib/datadog/appsec/remote.rb +14 -13
- data/lib/datadog/appsec/response.rb +6 -6
- data/lib/datadog/appsec/security_engine/runner.rb +1 -1
- data/lib/datadog/appsec/security_event.rb +39 -0
- data/lib/datadog/appsec.rb +1 -1
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/components.rb +19 -10
- data/lib/datadog/core/configuration/option.rb +61 -25
- data/lib/datadog/core/configuration/settings.rb +10 -0
- data/lib/datadog/core/configuration/stable_config.rb +23 -0
- data/lib/datadog/core/configuration.rb +24 -0
- data/lib/datadog/core/crashtracking/component.rb +1 -9
- data/lib/datadog/core/environment/git.rb +1 -0
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +8 -7
- data/lib/datadog/core/process_discovery.rb +32 -0
- data/lib/datadog/core/remote/client.rb +7 -0
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +60 -50
- data/lib/datadog/core/telemetry/emitter.rb +17 -11
- data/lib/datadog/core/telemetry/event.rb +7 -4
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/request.rb +3 -3
- data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
- data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
- data/lib/datadog/core/telemetry/transport/http.rb +63 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
- data/lib/datadog/core/telemetry/worker.rb +45 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/core/workers/async.rb +20 -2
- data/lib/datadog/core/workers/interval_loop.rb +12 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
- data/lib/datadog/core.rb +8 -0
- data/lib/datadog/di/boot.rb +34 -0
- data/lib/datadog/di/remote.rb +2 -0
- data/lib/datadog/di.rb +5 -32
- data/lib/datadog/error_tracking/collector.rb +87 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
- data/lib/datadog/error_tracking/configuration.rb +11 -0
- data/lib/datadog/error_tracking/ext.rb +18 -0
- data/lib/datadog/error_tracking/extensions.rb +16 -0
- data/lib/datadog/error_tracking/filters.rb +77 -0
- data/lib/datadog/error_tracking.rb +18 -0
- data/lib/datadog/kit/identity.rb +1 -1
- data/lib/datadog/profiling/exporter.rb +1 -1
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
- data/lib/datadog/tracing/span_operation.rb +38 -14
- data/lib/datadog/tracing/trace_operation.rb +15 -7
- data/lib/datadog/tracing/tracer.rb +7 -3
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- data/lib/datadog.rb +2 -3
- metadata +34 -8
- data/lib/datadog/core/telemetry/http/env.rb +0 -20
- data/lib/datadog/core/telemetry/http/ext.rb +0 -28
- data/lib/datadog/core/telemetry/http/response.rb +0 -70
- data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -74,10 +74,9 @@ module Datadog
|
|
74
74
|
profiler: {
|
75
75
|
enabled: Datadog::Profiling.enabled?,
|
76
76
|
},
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# }
|
77
|
+
dynamic_instrumentation: {
|
78
|
+
enabled: defined?(Datadog::DI) && Datadog::DI.respond_to?(:enabled?) && Datadog::DI.enabled?,
|
79
|
+
}
|
81
80
|
}
|
82
81
|
|
83
82
|
if (unsupported_reason = Datadog::Profiling.unsupported_reason)
|
@@ -91,6 +90,7 @@ module Datadog
|
|
91
90
|
end
|
92
91
|
|
93
92
|
TARGET_OPTIONS = %w[
|
93
|
+
dynamic_instrumentation.enabled
|
94
94
|
logger.level
|
95
95
|
profiling.advanced.code_provenance_enabled
|
96
96
|
profiling.advanced.endpoint.collection.enabled
|
@@ -114,6 +114,9 @@ module Datadog
|
|
114
114
|
seq_id = Event.configuration_sequence.next
|
115
115
|
|
116
116
|
list = [
|
117
|
+
conf_value('DD_GIT_REPOSITORY_URL', Core::Environment::Git.git_repository_url, seq_id, 'env_var'),
|
118
|
+
conf_value('DD_GIT_COMMIT_SHA', Core::Environment::Git.git_commit_sha, seq_id, 'env_var'),
|
119
|
+
|
117
120
|
conf_value('DD_AGENT_HOST', config.agent.host, seq_id),
|
118
121
|
conf_value('DD_AGENT_TRANSPORT', agent_transport(config), seq_id),
|
119
122
|
conf_value('DD_TRACE_SAMPLE_RATE', to_value(config.tracing.sampling.default_rate), seq_id),
|
@@ -1,108 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# datadog-ci-rb versions 1.15.0 and lower require this file and guard
|
4
|
+
# the require with a rescue of StandardError. Unfortunately LoadError,
|
5
|
+
# which would be raised if the file is missing, is not a subclass of
|
6
|
+
# StandardError and thus would not be caught by the rescue.
|
7
|
+
# We provide this file with a dummy class in it to avoid exceptions
|
8
|
+
# in datadog-ci-rb until version 2.0 is released.
|
9
|
+
#
|
10
|
+
# Note that datadog-ci-rb patches telemetry transport to be "real" even when
|
11
|
+
# webmock is used; this patching won't work with datadog-ci-rb versions
|
12
|
+
# 1.15.0 and older and dd-trace-rb 2.16.0 and newer. There will be no
|
13
|
+
# errors/exceptions reported but telemetry events will not be sent.
|
4
14
|
|
5
15
|
module Datadog
|
6
16
|
module Core
|
7
17
|
module Telemetry
|
8
18
|
module Http
|
9
19
|
module Adapters
|
10
|
-
|
11
|
-
class Net
|
12
|
-
attr_reader \
|
13
|
-
:hostname,
|
14
|
-
:port,
|
15
|
-
:timeout,
|
16
|
-
:ssl
|
17
|
-
|
18
|
-
DEFAULT_TIMEOUT = 2
|
19
|
-
|
20
|
-
def initialize(hostname:, port: nil, timeout: DEFAULT_TIMEOUT, ssl: true)
|
21
|
-
@hostname = hostname
|
22
|
-
@port = port
|
23
|
-
@timeout = timeout
|
24
|
-
@ssl = ssl.nil? || ssl
|
25
|
-
end
|
26
|
-
|
27
|
-
def open(&block)
|
28
|
-
req = ::Net::HTTP.new(@hostname, @port)
|
29
|
-
|
30
|
-
req.use_ssl = @ssl
|
31
|
-
req.open_timeout = req.read_timeout = @timeout
|
32
|
-
|
33
|
-
req.start(&block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def post(env)
|
37
|
-
post = ::Net::HTTP::Post.new(env.path, env.headers)
|
38
|
-
post.body = env.body
|
39
|
-
|
40
|
-
http_response = open do |http|
|
41
|
-
http.request(post)
|
42
|
-
end
|
43
|
-
|
44
|
-
Response.new(http_response)
|
45
|
-
rescue StandardError => e
|
46
|
-
Datadog.logger.debug("Unable to send telemetry event to agent: #{e}")
|
47
|
-
Telemetry::Http::InternalErrorResponse.new(e)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Data structure for an HTTP Response
|
51
|
-
class Response
|
52
|
-
include Datadog::Core::Telemetry::Http::Response
|
53
|
-
|
54
|
-
attr_reader :http_response
|
55
|
-
|
56
|
-
def initialize(http_response)
|
57
|
-
@http_response = http_response
|
58
|
-
end
|
59
|
-
|
60
|
-
def payload
|
61
|
-
return super if http_response.nil?
|
62
|
-
|
63
|
-
http_response.body
|
64
|
-
end
|
65
|
-
|
66
|
-
def code
|
67
|
-
return super if http_response.nil?
|
68
|
-
|
69
|
-
http_response.code.to_i
|
70
|
-
end
|
71
|
-
|
72
|
-
def ok?
|
73
|
-
return super if http_response.nil?
|
74
|
-
|
75
|
-
code.between?(200, 299)
|
76
|
-
end
|
77
|
-
|
78
|
-
def unsupported?
|
79
|
-
return super if http_response.nil?
|
80
|
-
|
81
|
-
code == 415
|
82
|
-
end
|
83
|
-
|
84
|
-
def not_found?
|
85
|
-
return super if http_response.nil?
|
86
|
-
|
87
|
-
code == 404
|
88
|
-
end
|
89
|
-
|
90
|
-
def client_error?
|
91
|
-
return super if http_response.nil?
|
92
|
-
|
93
|
-
code.between?(400, 499)
|
94
|
-
end
|
95
|
-
|
96
|
-
def server_error?
|
97
|
-
return super if http_response.nil?
|
98
|
-
|
99
|
-
code.between?(500, 599)
|
100
|
-
end
|
101
|
-
|
102
|
-
def inspect
|
103
|
-
"#{super}, http_response:#{http_response}"
|
104
|
-
end
|
105
|
-
end
|
20
|
+
class Net # rubocop:disable Lint/EmptyClass
|
106
21
|
end
|
107
22
|
end
|
108
23
|
end
|
@@ -11,11 +11,11 @@ module Datadog
|
|
11
11
|
class << self
|
12
12
|
using Core::Utils::Hash::Refinement
|
13
13
|
|
14
|
-
def build_payload(event, seq_id)
|
14
|
+
def build_payload(event, seq_id, api_version: 'v2', debug: false)
|
15
15
|
hash = {
|
16
|
-
api_version:
|
16
|
+
api_version: api_version,
|
17
17
|
application: application,
|
18
|
-
debug:
|
18
|
+
debug: debug,
|
19
19
|
host: host,
|
20
20
|
payload: event.payload,
|
21
21
|
request_type: event.type,
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../encoding'
|
4
|
+
require_relative '../../../transport/http/api/map'
|
5
|
+
require_relative '../../../transport/http/api/instance'
|
6
|
+
require_relative '../../../transport/http/api/spec'
|
7
|
+
require_relative 'telemetry'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module Core
|
11
|
+
module Telemetry
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
# Namespace for API components
|
15
|
+
module API
|
16
|
+
# Default API versions
|
17
|
+
AGENT_TELEMETRY = 'agent_telemetry'
|
18
|
+
AGENTLESS_TELEMETRY = 'agentless_telemetry'
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def defaults
|
23
|
+
Datadog::Core::Transport::HTTP::API::Map[
|
24
|
+
AGENT_TELEMETRY => Telemetry::API::Spec.new do |s|
|
25
|
+
s.telemetry = Telemetry::API::Endpoint.new(
|
26
|
+
'/telemetry/proxy/api/v2/apmtelemetry',
|
27
|
+
Core::Encoding::JSONEncoder,
|
28
|
+
)
|
29
|
+
end,
|
30
|
+
AGENTLESS_TELEMETRY => Telemetry::API::Spec.new do |s|
|
31
|
+
s.telemetry = Telemetry::API::Endpoint.new(
|
32
|
+
'/api/v2/apmtelemetry',
|
33
|
+
Core::Encoding::JSONEncoder,
|
34
|
+
)
|
35
|
+
end,
|
36
|
+
]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../transport/http/env'
|
4
|
+
require_relative '../../../transport/http/response'
|
5
|
+
|
6
|
+
# TODO: Decouple transport/http/client
|
7
|
+
#
|
8
|
+
# The standard one does `include Transport::HTTP::Statistics` and performs
|
9
|
+
# stats updates, which may or may not be desirable in general.
|
10
|
+
|
11
|
+
module Datadog
|
12
|
+
module Core
|
13
|
+
module Telemetry
|
14
|
+
module Transport
|
15
|
+
module HTTP
|
16
|
+
# Routes, encodes, and sends DI data to the trace agent via HTTP.
|
17
|
+
class Client
|
18
|
+
attr_reader :api, :logger
|
19
|
+
|
20
|
+
def initialize(api, logger:)
|
21
|
+
@api = api
|
22
|
+
@logger = logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_request(request, &block)
|
26
|
+
# Build request into env
|
27
|
+
env = build_env(request)
|
28
|
+
|
29
|
+
# Get responses from API
|
30
|
+
yield(api, env)
|
31
|
+
rescue => e
|
32
|
+
message =
|
33
|
+
"Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
|
34
|
+
"Location: #{Array(e.backtrace).first}"
|
35
|
+
|
36
|
+
logger.debug(message)
|
37
|
+
|
38
|
+
Datadog::Core::Transport::InternalErrorResponse.new(e)
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_env(request)
|
42
|
+
Datadog::Core::Transport::HTTP::Env.new(request)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../transport/http/api/endpoint'
|
4
|
+
require_relative '../../../transport/http/api/instance'
|
5
|
+
require_relative '../../../transport/http/api/spec'
|
6
|
+
require_relative '../../../transport/request'
|
7
|
+
require_relative 'client'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module Core
|
11
|
+
module Telemetry
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
module Telemetry
|
15
|
+
module Client
|
16
|
+
def send_telemetry_payload(request)
|
17
|
+
send_request(request) do |api, env| # steep:ignore
|
18
|
+
api.send_telemetry(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module API
|
24
|
+
class Instance < Core::Transport::HTTP::API::Instance
|
25
|
+
def send_telemetry(env)
|
26
|
+
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('telemetry', self) unless spec.is_a?(Telemetry::API::Spec)
|
27
|
+
|
28
|
+
spec.send_telemetry(env) do |request_env|
|
29
|
+
call(request_env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Spec < Core::Transport::HTTP::API::Spec
|
35
|
+
attr_accessor :telemetry
|
36
|
+
|
37
|
+
def send_telemetry(env, &block)
|
38
|
+
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('telemetry', self) if telemetry.nil?
|
39
|
+
|
40
|
+
telemetry.call(env, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
45
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
46
|
+
|
47
|
+
attr_reader \
|
48
|
+
:encoder
|
49
|
+
|
50
|
+
def initialize(path, encoder)
|
51
|
+
super(:post, path)
|
52
|
+
@encoder = encoder
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(env, &block)
|
56
|
+
# Encode body & type
|
57
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
58
|
+
env.headers.update(headers(
|
59
|
+
request_type: env.request.request_type,
|
60
|
+
api_key: env.request.api_key,
|
61
|
+
))
|
62
|
+
env.body = env.request.parcel.data
|
63
|
+
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
def headers(request_type:, api_version: 'v2', api_key:)
|
68
|
+
{
|
69
|
+
Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
|
70
|
+
# Provided by encoder
|
71
|
+
#'Content-Type' => 'application/json',
|
72
|
+
'DD-Telemetry-API-Version' => api_version,
|
73
|
+
'DD-Telemetry-Request-Type' => request_type,
|
74
|
+
'DD-Client-Library-Language' => Core::Environment::Ext::LANG,
|
75
|
+
'DD-Client-Library-Version' => Core::Environment::Identity.gem_datadog_version_semver2,
|
76
|
+
|
77
|
+
# Enable debug mode for telemetry
|
78
|
+
# 'DD-Telemetry-Debug-Enabled' => 'true',
|
79
|
+
}.tap do |result|
|
80
|
+
result['DD-API-KEY'] = api_key unless api_key.nil?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
HTTP::Client.include(Telemetry::Client)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'telemetry'
|
4
|
+
require_relative 'http/api'
|
5
|
+
require_relative '../../transport/http'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Core
|
9
|
+
module Telemetry
|
10
|
+
module Transport
|
11
|
+
# Namespace for HTTP transport components
|
12
|
+
module HTTP
|
13
|
+
module_function
|
14
|
+
|
15
|
+
# Builds a new Transport::HTTP::Client with default settings
|
16
|
+
# Pass a block to override any settings.
|
17
|
+
def agentless_telemetry(
|
18
|
+
agent_settings:,
|
19
|
+
logger:,
|
20
|
+
api_key: nil,
|
21
|
+
api_version: nil,
|
22
|
+
headers: nil
|
23
|
+
)
|
24
|
+
Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
|
25
|
+
logger: logger,
|
26
|
+
agent_settings: agent_settings,
|
27
|
+
api_version: api_version,
|
28
|
+
headers: headers) do |transport|
|
29
|
+
apis = API.defaults
|
30
|
+
|
31
|
+
transport.api API::AGENTLESS_TELEMETRY, apis[API::AGENTLESS_TELEMETRY]
|
32
|
+
|
33
|
+
# Call block to apply any customization, if provided
|
34
|
+
yield(transport) if block_given?
|
35
|
+
end.to_transport(Core::Telemetry::Transport::Telemetry::Transport).tap do |transport|
|
36
|
+
transport.api_key = api_key
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Builds a new Transport::HTTP::Client with default settings
|
41
|
+
# Pass a block to override any settings.
|
42
|
+
def agent_telemetry(
|
43
|
+
agent_settings:,
|
44
|
+
logger:,
|
45
|
+
api_version: nil,
|
46
|
+
headers: nil
|
47
|
+
)
|
48
|
+
Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
|
49
|
+
logger: logger,
|
50
|
+
agent_settings: agent_settings, api_version: api_version, headers: headers) do |transport|
|
51
|
+
apis = API.defaults
|
52
|
+
|
53
|
+
transport.api API::AGENT_TELEMETRY, apis[API::AGENT_TELEMETRY]
|
54
|
+
|
55
|
+
# Call block to apply any customization, if provided
|
56
|
+
yield(transport) if block_given?
|
57
|
+
end.to_transport(Core::Telemetry::Transport::Telemetry::Transport)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../transport/parcel'
|
4
|
+
require_relative 'http/client'
|
5
|
+
require_relative 'http/telemetry'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Core
|
9
|
+
module Telemetry
|
10
|
+
module Transport
|
11
|
+
module Telemetry
|
12
|
+
class EncodedParcel
|
13
|
+
include Datadog::Core::Transport::Parcel
|
14
|
+
end
|
15
|
+
|
16
|
+
class Request < Datadog::Core::Transport::Request
|
17
|
+
|
18
|
+
attr_reader :request_type
|
19
|
+
attr_reader :api_key
|
20
|
+
|
21
|
+
def initialize(request_type, parcel, api_key)
|
22
|
+
@request_type = request_type
|
23
|
+
super(parcel)
|
24
|
+
@api_key = api_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Transport
|
29
|
+
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
30
|
+
attr_accessor :api_key
|
31
|
+
|
32
|
+
def initialize(apis, default_api, logger:)
|
33
|
+
@apis = apis
|
34
|
+
@logger = logger
|
35
|
+
|
36
|
+
@client = HTTP::Client.new(@apis[default_api], logger: logger)
|
37
|
+
end
|
38
|
+
|
39
|
+
def send_telemetry(request_type:, payload:)
|
40
|
+
json = JSON.dump(payload)
|
41
|
+
parcel = EncodedParcel.new(json)
|
42
|
+
request = Request.new(request_type, parcel, api_key)
|
43
|
+
|
44
|
+
@client.send_telemetry_payload(request)
|
45
|
+
# Perform no error checking here
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -52,10 +52,15 @@ module Datadog
|
|
52
52
|
|
53
53
|
attr_reader :logger
|
54
54
|
|
55
|
+
# Returns true if worker thread is successfully started,
|
56
|
+
# false if worker thread was not started but telemetry is enabled,
|
57
|
+
# nil if telemetry is disabled.
|
55
58
|
def start
|
56
59
|
return if !enabled? || forked?
|
57
60
|
|
58
61
|
# starts async worker
|
62
|
+
# perform should return true if thread was actually started,
|
63
|
+
# false otherwise
|
59
64
|
perform
|
60
65
|
end
|
61
66
|
|
@@ -65,10 +70,15 @@ module Datadog
|
|
65
70
|
super
|
66
71
|
end
|
67
72
|
|
73
|
+
# Returns true if event was enqueued, nil if not.
|
74
|
+
# While returning false may seem more reasonable, the only reason
|
75
|
+
# for not enqueueing event (presently) is that telemetry is disabled
|
76
|
+
# altogether, and in this case other methods return nil.
|
68
77
|
def enqueue(event)
|
69
78
|
return if !enabled? || forked?
|
70
79
|
|
71
80
|
buffer.push(event)
|
81
|
+
true
|
72
82
|
end
|
73
83
|
|
74
84
|
def sent_started_event?
|
@@ -79,6 +89,39 @@ module Datadog
|
|
79
89
|
TELEMETRY_STARTED_ONCE.failed?
|
80
90
|
end
|
81
91
|
|
92
|
+
# Wait for the worker to send out all events that have already
|
93
|
+
# been queued, up to 15 seconds. Returns whether all events have
|
94
|
+
# been flushed.
|
95
|
+
#
|
96
|
+
# @api private
|
97
|
+
def flush
|
98
|
+
return true unless enabled? || !run_loop?
|
99
|
+
|
100
|
+
started = Utils::Time.get_time
|
101
|
+
loop do
|
102
|
+
# The AppStarted event is triggered by the worker itself,
|
103
|
+
# from the worker thread. As such the main thread has no way
|
104
|
+
# to delay itself until that event is queued and we need some
|
105
|
+
# way to wait until that event is sent out to assert on it in
|
106
|
+
# the test suite. Check the run once flag which *should*
|
107
|
+
# indicate the event has been queued (at which point our queue
|
108
|
+
# depth check should waint until it's sent).
|
109
|
+
# This is still a hack because the flag can be overridden
|
110
|
+
# either way with or without the event being sent out.
|
111
|
+
# Note that if the AppStarted sending fails, this check
|
112
|
+
# will return false and flushing will be blocked until the
|
113
|
+
# 15 second timeout.
|
114
|
+
# Note that the first wait interval between telemetry event
|
115
|
+
# sending is 10 seconds, the timeout needs to be strictly
|
116
|
+
# greater than that.
|
117
|
+
return true if buffer.empty? && !in_iteration? && TELEMETRY_STARTED_ONCE.success?
|
118
|
+
|
119
|
+
sleep 0.5
|
120
|
+
|
121
|
+
return false if Utils::Time.get_time - started > 15
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
82
125
|
private
|
83
126
|
|
84
127
|
def perform(*events)
|
@@ -99,6 +142,8 @@ module Datadog
|
|
99
142
|
|
100
143
|
def flush_events(events)
|
101
144
|
return if events.empty?
|
145
|
+
# TODO: can this method silently drop events which are
|
146
|
+
# generated prior to the started event being submitted?
|
102
147
|
return if !enabled? || !sent_started_event?
|
103
148
|
|
104
149
|
events = deduplicate_logs(events)
|
@@ -31,6 +31,12 @@ module Datadog
|
|
31
31
|
#
|
32
32
|
# @param block [Proc] block that returns a `Time` object representing the current wall time
|
33
33
|
def now_provider=(block)
|
34
|
+
class << self
|
35
|
+
# Avoid method redefinition warning.
|
36
|
+
# `rescue nil` is added in case customers remove the method
|
37
|
+
# themselves to squelch the warning.
|
38
|
+
remove_method(:now) rescue nil
|
39
|
+
end
|
34
40
|
define_singleton_method(:now, &block)
|
35
41
|
end
|
36
42
|
|
@@ -43,6 +49,12 @@ module Datadog
|
|
43
49
|
#
|
44
50
|
# @param block [Proc] block that accepts unit and returns timestamp in the requested unit
|
45
51
|
def get_time_provider=(block)
|
52
|
+
class << self
|
53
|
+
# Avoid method redefinition warning
|
54
|
+
# `rescue nil` is added in case customers remove the method
|
55
|
+
# themselves to squelch the warning.
|
56
|
+
remove_method(:get_time) rescue nil
|
57
|
+
end
|
46
58
|
define_singleton_method(:get_time, &block)
|
47
59
|
end
|
48
60
|
|
@@ -47,6 +47,14 @@ module Datadog
|
|
47
47
|
@run_async = false
|
48
48
|
Datadog.logger.debug { "Forcibly terminating worker thread for: #{self}" }
|
49
49
|
worker.terminate
|
50
|
+
# Wait for the worker thread to end
|
51
|
+
begin
|
52
|
+
Timeout.timeout(SHUTDOWN_TIMEOUT) do
|
53
|
+
worker.join
|
54
|
+
end
|
55
|
+
rescue Timeout::Error
|
56
|
+
Datadog.logger.debug { "Worker thread did not end after #{SHUTDOWN_TIMEOUT} seconds: #{self}" }
|
57
|
+
end
|
50
58
|
true
|
51
59
|
end
|
52
60
|
|
@@ -112,23 +120,33 @@ module Datadog
|
|
112
120
|
@worker ||= nil
|
113
121
|
end
|
114
122
|
|
123
|
+
# Returns true if worker thread is successfully started,
|
124
|
+
# false if it is not started. Reasons for not starting the worker
|
125
|
+
# thread: it is already running, or the process forked and fork
|
126
|
+
# policy is to stop the workers on fork (which means they are
|
127
|
+
# not started in children, really).
|
115
128
|
def start_async(&block)
|
116
129
|
mutex.synchronize do
|
117
|
-
return if running?
|
130
|
+
return false if running?
|
118
131
|
|
119
132
|
if forked?
|
120
133
|
case fork_policy
|
121
134
|
when FORK_POLICY_STOP
|
122
135
|
stop_fork
|
136
|
+
false
|
123
137
|
when FORK_POLICY_RESTART
|
138
|
+
# restart_after_fork should return true
|
124
139
|
restart_after_fork(&block)
|
125
140
|
end
|
126
141
|
elsif !run_async?
|
142
|
+
# start_worker should return true
|
127
143
|
start_worker(&block)
|
128
144
|
end
|
129
145
|
end
|
130
146
|
end
|
131
147
|
|
148
|
+
# Returns true if worker thread is successfully started,
|
149
|
+
# which should generally be always.
|
132
150
|
def start_worker
|
133
151
|
@run_async = true
|
134
152
|
@pid = Process.pid
|
@@ -151,7 +169,7 @@ module Datadog
|
|
151
169
|
@worker.name = self.class.name
|
152
170
|
@worker.thread_variable_set(:fork_safe, true)
|
153
171
|
|
154
|
-
|
172
|
+
true
|
155
173
|
end
|
156
174
|
|
157
175
|
def stop_fork
|
@@ -21,7 +21,18 @@ module Datadog
|
|
21
21
|
# Methods that must be prepended
|
22
22
|
module PrependedMethods
|
23
23
|
def perform(*args)
|
24
|
-
perform_loop
|
24
|
+
perform_loop do
|
25
|
+
@in_iteration = true
|
26
|
+
begin
|
27
|
+
super(*args)
|
28
|
+
ensure
|
29
|
+
@in_iteration = false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def in_iteration?
|
35
|
+
defined?(@in_iteration) && @in_iteration
|
25
36
|
end
|
26
37
|
end
|
27
38
|
|
@@ -20,8 +20,8 @@ module Datadog
|
|
20
20
|
attr_reader \
|
21
21
|
:metrics
|
22
22
|
|
23
|
-
def initialize(options
|
24
|
-
@metrics = options.fetch(:metrics) { Core::Runtime::Metrics.new(logger: options[:logger]) }
|
23
|
+
def initialize(telemetry:, **options)
|
24
|
+
@metrics = options.fetch(:metrics) { Core::Runtime::Metrics.new(logger: options[:logger], telemetry: telemetry) }
|
25
25
|
|
26
26
|
# Workers::Async::Thread settings
|
27
27
|
self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
|
data/lib/datadog/core.rb
CHANGED
@@ -11,6 +11,14 @@ module Datadog
|
|
11
11
|
# for higher-level features.
|
12
12
|
module Core
|
13
13
|
extend Core::Deprecations
|
14
|
+
|
15
|
+
LIBDATADOG_API_FAILURE =
|
16
|
+
begin
|
17
|
+
require "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}"
|
18
|
+
nil
|
19
|
+
rescue LoadError => e
|
20
|
+
e.message
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
24
|
extend Core::Extensions
|