datadog 2.10.0 → 2.12.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 +56 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +44 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +56 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
- data/ext/datadog_profiling_native_extension/profiling.c +7 -0
- data/ext/libdatadog_api/crashtracker.c +4 -4
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +64 -11
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
- data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
- data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +10 -12
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +65 -73
- data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -25
- data/lib/datadog/appsec/contrib/rails/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -49
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +0 -3
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -25
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/appsec.rb +3 -0
- data/lib/datadog/core/configuration/components.rb +8 -2
- data/lib/datadog/core/configuration/ext.rb +1 -1
- data/lib/datadog/core/configuration/option_definition.rb +2 -0
- data/lib/datadog/core/configuration/settings.rb +22 -6
- data/lib/datadog/core/encoding.rb +16 -0
- data/lib/datadog/core/environment/agent_info.rb +77 -0
- data/lib/datadog/core/remote/component.rb +11 -9
- data/lib/datadog/core/remote/transport/http/api.rb +13 -18
- data/lib/datadog/core/remote/transport/http/config.rb +0 -18
- data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
- data/lib/datadog/core/remote/transport/http.rb +7 -12
- data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
- data/lib/datadog/core/remote/worker.rb +10 -7
- data/lib/datadog/core/telemetry/component.rb +5 -1
- data/lib/datadog/core/telemetry/event.rb +5 -0
- data/lib/datadog/core/telemetry/worker.rb +9 -5
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
- data/lib/datadog/core/transport/response.rb +4 -0
- data/lib/datadog/di/code_tracker.rb +15 -8
- data/lib/datadog/di/component.rb +2 -3
- data/lib/datadog/di/configuration/settings.rb +14 -0
- data/lib/datadog/di/contrib.rb +2 -0
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/probe.rb +3 -6
- data/lib/datadog/di/probe_manager.rb +5 -2
- data/lib/datadog/di/probe_notifier_worker.rb +35 -8
- data/lib/datadog/di/remote.rb +3 -3
- data/lib/datadog/di/transport/diagnostics.rb +61 -0
- data/lib/datadog/di/transport/http/api.rb +52 -0
- data/lib/datadog/di/transport/http/client.rb +46 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
- data/lib/datadog/di/transport/http/input.rb +94 -0
- data/lib/datadog/di/transport/http.rb +119 -0
- data/lib/datadog/di/transport/input.rb +61 -0
- data/lib/datadog/di/utils.rb +91 -0
- data/lib/datadog/di.rb +5 -1
- data/lib/datadog/profiling/component.rb +2 -8
- data/lib/datadog/profiling/load_native_extension.rb +1 -33
- data/lib/datadog/tracing/component.rb +1 -0
- data/lib/datadog/tracing/configuration/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
- data/lib/datadog/tracing/sync_writer.rb +5 -2
- data/lib/datadog/tracing/tracer.rb +10 -7
- data/lib/datadog/tracing/transport/http/api.rb +11 -2
- data/lib/datadog/tracing/transport/http/traces.rb +0 -3
- data/lib/datadog/tracing/transport/http.rb +12 -7
- data/lib/datadog/tracing/transport/serializable_trace.rb +8 -4
- data/lib/datadog/tracing/transport/traces.rb +25 -8
- data/lib/datadog/tracing/workers/trace_writer.rb +4 -1
- data/lib/datadog/tracing/workers.rb +5 -4
- data/lib/datadog/tracing/writer.rb +6 -2
- data/lib/datadog/version.rb +1 -1
- metadata +33 -29
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
- data/lib/datadog/appsec/contrib/patcher.rb +0 -12
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
- data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
- data/lib/datadog/appsec/reactive/engine.rb +0 -47
- data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
- data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
- data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
- data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
- data/lib/datadog/di/transport.rb +0 -79
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Diagnostics
|
10
|
+
module Client
|
11
|
+
def send_diagnostics_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_diagnostics(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_diagnostics(env)
|
21
|
+
raise DiagnosticsNotSupportedError, spec unless spec.is_a?(Diagnostics::API::Spec)
|
22
|
+
|
23
|
+
spec.send_diagnostics(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DiagnosticsNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Diagnostics not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :diagnostics
|
45
|
+
|
46
|
+
def send_diagnostics(env, &block)
|
47
|
+
raise NoDiagnosticsEndpointDefinedError, self if diagnostics.nil?
|
48
|
+
|
49
|
+
diagnostics.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoDiagnosticsEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No diagnostics endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
attr_reader :encoder
|
70
|
+
|
71
|
+
def initialize(path, encoder)
|
72
|
+
super(:post, path)
|
73
|
+
@encoder = encoder
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env, &block)
|
77
|
+
event_payload = Core::Vendor::Multipart::Post::UploadIO.new(
|
78
|
+
StringIO.new(env.request.parcel.data), 'application/json', 'event.json'
|
79
|
+
)
|
80
|
+
env.form = {'event' => event_payload}
|
81
|
+
|
82
|
+
super(env, &block)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
HTTP::Client.include(Diagnostics::Client)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Input
|
10
|
+
module Client
|
11
|
+
def send_input_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_input(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_input(env)
|
21
|
+
raise InputNotSupportedError, spec unless spec.is_a?(Input::API::Spec)
|
22
|
+
|
23
|
+
spec.send_input(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class InputNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Input not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :input
|
45
|
+
|
46
|
+
def send_input(env, &block)
|
47
|
+
raise NoInputEndpointDefinedError, self if input.nil?
|
48
|
+
|
49
|
+
input.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoInputEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No input endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
70
|
+
|
71
|
+
attr_reader \
|
72
|
+
:encoder
|
73
|
+
|
74
|
+
def initialize(path, encoder)
|
75
|
+
super(:post, path)
|
76
|
+
@encoder = encoder
|
77
|
+
end
|
78
|
+
|
79
|
+
def call(env, &block)
|
80
|
+
# Encode body & type
|
81
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
82
|
+
env.body = env.request.parcel.data
|
83
|
+
|
84
|
+
super(env, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
HTTP::Client.include(Input::Client)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
require_relative '../../core/environment/container'
|
6
|
+
require_relative '../../core/environment/ext'
|
7
|
+
require_relative '../../core/transport/ext'
|
8
|
+
require_relative '../../core/transport/http/adapters/net'
|
9
|
+
require_relative '../../core/transport/http/adapters/test'
|
10
|
+
require_relative '../../core/transport/http/adapters/unix_socket'
|
11
|
+
require_relative 'diagnostics'
|
12
|
+
require_relative 'input'
|
13
|
+
require_relative 'http/api'
|
14
|
+
require_relative '../../core/transport/http/builder'
|
15
|
+
require_relative '../../../datadog/version'
|
16
|
+
|
17
|
+
module Datadog
|
18
|
+
module DI
|
19
|
+
module Transport
|
20
|
+
# Namespace for HTTP transport components
|
21
|
+
module HTTP
|
22
|
+
module_function
|
23
|
+
|
24
|
+
# Builds a new Transport::HTTP::Client
|
25
|
+
def new(klass, &block)
|
26
|
+
Core::Transport::HTTP::Builder.new(
|
27
|
+
api_instance_class: API::Instance, &block
|
28
|
+
).to_transport(klass)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Builds a new Transport::HTTP::Client with default settings
|
32
|
+
# Pass a block to override any settings.
|
33
|
+
def diagnostics(
|
34
|
+
agent_settings:,
|
35
|
+
**options
|
36
|
+
)
|
37
|
+
new(DI::Transport::Diagnostics::Transport) do |transport|
|
38
|
+
transport.adapter(agent_settings)
|
39
|
+
transport.headers default_headers
|
40
|
+
|
41
|
+
apis = API.defaults
|
42
|
+
|
43
|
+
transport.api API::DIAGNOSTICS, apis[API::DIAGNOSTICS]
|
44
|
+
|
45
|
+
# Apply any settings given by options
|
46
|
+
unless options.empty?
|
47
|
+
transport.default_api = options[:api_version] if options.key?(:api_version)
|
48
|
+
transport.headers options[:headers] if options.key?(:headers)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Call block to apply any customization, if provided
|
52
|
+
yield(transport) if block_given?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Builds a new Transport::HTTP::Client with default settings
|
57
|
+
# Pass a block to override any settings.
|
58
|
+
def input(
|
59
|
+
agent_settings:,
|
60
|
+
**options
|
61
|
+
)
|
62
|
+
new(DI::Transport::Input::Transport) do |transport|
|
63
|
+
transport.adapter(agent_settings)
|
64
|
+
transport.headers default_headers
|
65
|
+
|
66
|
+
apis = API.defaults
|
67
|
+
|
68
|
+
transport.api API::INPUT, apis[API::INPUT]
|
69
|
+
|
70
|
+
# Apply any settings given by options
|
71
|
+
unless options.empty?
|
72
|
+
transport.default_api = options[:api_version] if options.key?(:api_version)
|
73
|
+
transport.headers options[:headers] if options.key?(:headers)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Call block to apply any customization, if provided
|
77
|
+
yield(transport) if block_given?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def default_headers
|
82
|
+
{
|
83
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
|
84
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG => Datadog::Core::Environment::Ext::LANG,
|
85
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION => Datadog::Core::Environment::Ext::LANG_VERSION,
|
86
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER =>
|
87
|
+
Datadog::Core::Environment::Ext::LANG_INTERPRETER,
|
88
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER_VENDOR => Core::Environment::Ext::LANG_ENGINE,
|
89
|
+
Datadog::Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION =>
|
90
|
+
Datadog::Core::Environment::Ext::GEM_DATADOG_VERSION
|
91
|
+
}.tap do |headers|
|
92
|
+
# Add container ID, if present.
|
93
|
+
container_id = Datadog::Core::Environment::Container.container_id
|
94
|
+
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil?
|
95
|
+
# Pretend that stats computation are already done by the client
|
96
|
+
if Datadog.configuration.appsec.standalone.enabled
|
97
|
+
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def default_adapter
|
103
|
+
Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
104
|
+
end
|
105
|
+
|
106
|
+
# Add adapters to registry
|
107
|
+
Datadog::Core::Transport::HTTP::Builder::REGISTRY.set(
|
108
|
+
Datadog::Core::Transport::HTTP::Adapters::Net,
|
109
|
+
Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
110
|
+
)
|
111
|
+
Datadog::Core::Transport::HTTP::Builder::REGISTRY.set(Datadog::Core::Transport::HTTP::Adapters::Test, Datadog::Core::Transport::Ext::Test::ADAPTER)
|
112
|
+
Datadog::Core::Transport::HTTP::Builder::REGISTRY.set(
|
113
|
+
Datadog::Core::Transport::HTTP::Adapters::UnixSocket,
|
114
|
+
Datadog::Core::Transport::Ext::UnixSocket::ADAPTER
|
115
|
+
)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../core/transport/parcel'
|
4
|
+
require_relative 'http/client'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module DI
|
8
|
+
module Transport
|
9
|
+
module Input
|
10
|
+
class EncodedParcel
|
11
|
+
include Datadog::Core::Transport::Parcel
|
12
|
+
end
|
13
|
+
|
14
|
+
class Request < Datadog::Core::Transport::Request
|
15
|
+
end
|
16
|
+
|
17
|
+
class Transport
|
18
|
+
attr_reader :client, :apis, :default_api, :current_api_id
|
19
|
+
|
20
|
+
def initialize(apis, default_api)
|
21
|
+
@apis = apis
|
22
|
+
|
23
|
+
@client = HTTP::Client.new(current_api)
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_api
|
27
|
+
@apis[HTTP::API::INPUT]
|
28
|
+
end
|
29
|
+
|
30
|
+
def send_input(payload)
|
31
|
+
json = JSON.dump(payload)
|
32
|
+
parcel = EncodedParcel.new(json)
|
33
|
+
request = Request.new(parcel)
|
34
|
+
|
35
|
+
response = @client.send_input_payload(request)
|
36
|
+
unless response.ok?
|
37
|
+
# TODO Datadog::Core::Transport::InternalErrorResponse
|
38
|
+
# does not have +code+ method, what is the actual API of
|
39
|
+
# these response objects?
|
40
|
+
raise Error::AgentCommunicationError, "send_input failed: #{begin
|
41
|
+
response.code
|
42
|
+
rescue
|
43
|
+
"???"
|
44
|
+
end}: #{response.payload}"
|
45
|
+
end
|
46
|
+
rescue Error::AgentCommunicationError
|
47
|
+
raise
|
48
|
+
# Datadog::Core::Transport does not perform any exception mapping,
|
49
|
+
# therefore we could have any exception here from failure to parse
|
50
|
+
# agent URI for example.
|
51
|
+
# If we ever implement retries for network errors, we should distinguish
|
52
|
+
# actual network errors from non-network errors that are raised by
|
53
|
+
# transport code.
|
54
|
+
rescue => exc
|
55
|
+
raise Error::AgentCommunicationError, "send_input failed: #{exc.class}: #{exc}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/datadog/di/utils.rb
CHANGED
@@ -3,6 +3,82 @@
|
|
3
3
|
module Datadog
|
4
4
|
module DI
|
5
5
|
module Utils
|
6
|
+
# General path matching considerations
|
7
|
+
# ------------------------------------
|
8
|
+
#
|
9
|
+
# The following use cases must be supported:
|
10
|
+
# 1. The "probe path" is relative path to the file from source code
|
11
|
+
# repository root. The project is deployed from the repository root,
|
12
|
+
# such that that same relative path exists at runtime from the
|
13
|
+
# root of the application.
|
14
|
+
# 2. The "probe path" is a relative path to the file in a monorepo
|
15
|
+
# where the project being deployed is in a subdirectory.
|
16
|
+
# This the "probe path" contains additional directory components
|
17
|
+
# in the beginning that do not exist in the runtime environment.
|
18
|
+
# 3. The "probe path" is an absolute path to the file on the customer's
|
19
|
+
# development system. As specified this path definitely does not
|
20
|
+
# exist at runtime, and can start with a prefix that is unknown
|
21
|
+
# to any both UI and tracer code.
|
22
|
+
# 4. Same as (3), but the customer is using a Windows computer for
|
23
|
+
# development and has the path specified in the wrong case
|
24
|
+
# (which works fine on their development machine).
|
25
|
+
# 5. The "probe path" is the basename or any suffix of the path to
|
26
|
+
# the desired file, typed manually by the customer into the UI.
|
27
|
+
#
|
28
|
+
# A related concern is that if multiple runtime paths match the path
|
29
|
+
# specification in the probe, the tracer must return an error to the
|
30
|
+
# backend/UI rather than instrumenting any of the matching paths.
|
31
|
+
#
|
32
|
+
# The logic for path matching should therefore, generally, be as follows:
|
33
|
+
# 1. If the "probe path" is absolute, see if it exists at runtime.
|
34
|
+
# If so, take it as the desired path and finish.
|
35
|
+
# 2. Attempt to identify the application root, by checking if the current
|
36
|
+
# working directory contains a file called Gemfile. If yes, assume
|
37
|
+
# the current working directory is the application root, otherwise
|
38
|
+
# consider the application root to be unknown.
|
39
|
+
# 3. If the application root is known and the "probe path" is relative,
|
40
|
+
# concatenate the "probe path" to the application root and check
|
41
|
+
# if the resulting path exists at runtime. If so, take it as the
|
42
|
+
# desired path and finish.
|
43
|
+
# 4. If the "probe path" is relative, go through the known file paths,
|
44
|
+
# filter these paths down to those whose suffix is the "probe path",
|
45
|
+
# and check how many we are left with. If exactly one, assume this
|
46
|
+
# is the desired path and finish. If more than one, return an error
|
47
|
+
# "multiple matching paths".
|
48
|
+
# 5. If the application root is known, for each suffix of the "probe path",
|
49
|
+
# see if that relative paths concatenated to the application root
|
50
|
+
# results in a known file. If a known file is found, assume this
|
51
|
+
# is the wanted file and finish.
|
52
|
+
# 6. For each suffix of the "probe path", filter the set of known paths
|
53
|
+
# down to those that end in the suffix. If exactly one path remains
|
54
|
+
# for a given suffix, assume this is the wanted path and finish.
|
55
|
+
# If more than one path remains for a given suffix, return the error
|
56
|
+
# "multiple matching paths".
|
57
|
+
# 7. Repeat step 5 but perform case-insensitive comparison.
|
58
|
+
# 8. Repeat step 6 but perform case-insensitive comparison.
|
59
|
+
#
|
60
|
+
# Note that we do not look for "probe paths" under the current working
|
61
|
+
# directory at runtime if the current working directory does not contain
|
62
|
+
# a Gemfile, to avoid finding files from potentially undesired bases.
|
63
|
+
#
|
64
|
+
# What "known file"/"known path" means also differs based on the
|
65
|
+
# operation being performed:
|
66
|
+
# - If the operation is "install a probe", "known file/path" can
|
67
|
+
# include files on the filesystem that have not been loaded as
|
68
|
+
# well as paths from the code tracker.
|
69
|
+
# - If the operation is "check if any pending probes match the file
|
70
|
+
# that was just loaded", we would only consider the path that was
|
71
|
+
# just loaded and not check the filesystem.
|
72
|
+
#
|
73
|
+
# Filesystem inquiries are obviously quite expensive and should be
|
74
|
+
# cached. For the vast majority of applications it should be safe to
|
75
|
+
# indefinitely cache whether a particular filesystem paths exists
|
76
|
+
# in both positive and negative.
|
77
|
+
#
|
78
|
+
# As a "quick fix", currently after performing the suffix matching
|
79
|
+
# we just strip leading directory components from the "probe path"
|
80
|
+
# until we get a match via a "suffix of the suffix".
|
81
|
+
|
6
82
|
# Returns whether the provided +path+ matches the user-designated
|
7
83
|
# file suffix (of a line probe).
|
8
84
|
#
|
@@ -41,6 +117,21 @@ module Datadog
|
|
41
117
|
# !!(path =~ %r,(/|\A)#{Regexp.quote(suffix)}\z,)
|
42
118
|
end
|
43
119
|
end
|
120
|
+
|
121
|
+
# Returns whether the provided +path+ matches the "probe path" in
|
122
|
+
# +spec+. Attempts all of the fuzzy matches by stripping directories
|
123
|
+
# from the front of +spec+. Does not consider othr known paths to
|
124
|
+
# identify the case of (potentially) multiple matching paths for +spec+.
|
125
|
+
module_function def path_can_match_spec?(path, spec)
|
126
|
+
return true if path_matches_suffix?(path, spec)
|
127
|
+
|
128
|
+
spec = spec.dup
|
129
|
+
loop do
|
130
|
+
return false unless spec.include?('/')
|
131
|
+
spec.sub!(%r{.*/+}, '')
|
132
|
+
return true if path_matches_suffix?(path, spec)
|
133
|
+
end
|
134
|
+
end
|
44
135
|
end
|
45
136
|
end
|
46
137
|
end
|
data/lib/datadog/di.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'di/logger'
|
3
4
|
require_relative 'di/base'
|
4
5
|
require_relative 'di/error'
|
5
6
|
require_relative 'di/code_tracker'
|
@@ -15,7 +16,8 @@ require_relative 'di/probe_notifier_worker'
|
|
15
16
|
require_relative 'di/redactor'
|
16
17
|
require_relative 'di/remote'
|
17
18
|
require_relative 'di/serializer'
|
18
|
-
require_relative 'di/transport'
|
19
|
+
#require_relative 'di/transport'
|
20
|
+
require_relative 'di/transport/http'
|
19
21
|
require_relative 'di/utils'
|
20
22
|
|
21
23
|
module Datadog
|
@@ -58,6 +60,8 @@ if %w(1 true).include?(ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore
|
|
58
60
|
#
|
59
61
|
# If DI is enabled programmatically, the application can (and must,
|
60
62
|
# for line probes to work) activate tracking in an initializer.
|
63
|
+
# We seem to have Datadog.logger here already
|
64
|
+
Datadog.logger.debug("di: activating code tracking")
|
61
65
|
Datadog::DI.activate_tracking
|
62
66
|
end
|
63
67
|
|
@@ -435,17 +435,11 @@ module Datadog
|
|
435
435
|
end
|
436
436
|
|
437
437
|
private_class_method def self.enable_gvl_profiling?(settings, logger)
|
438
|
-
if RUBY_VERSION < "3.2"
|
439
|
-
if settings.profiling.advanced.preview_gvl_enabled
|
440
|
-
logger.warn("GVL profiling is currently not supported in Ruby < 3.2 and will not be enabled.")
|
441
|
-
end
|
442
|
-
|
443
|
-
return false
|
444
|
-
end
|
438
|
+
return false if RUBY_VERSION < "3.2"
|
445
439
|
|
446
440
|
# GVL profiling only makes sense in the context of timeline. We could emit a warning here, but not sure how
|
447
441
|
# useful it is -- if a customer disables timeline, there's nowhere to look for GVL profiling anyway!
|
448
|
-
settings.profiling.advanced.timeline_enabled && settings.profiling.advanced.
|
442
|
+
settings.profiling.advanced.timeline_enabled && settings.profiling.advanced.gvl_enabled
|
449
443
|
end
|
450
444
|
end
|
451
445
|
end
|
@@ -1,41 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# This file is used to load the profiling native extension. It works in two steps:
|
4
|
-
#
|
5
|
-
# 1. Load the datadog_profiling_loader extension. This extension will be used to load the actual extension, but in
|
6
|
-
# a special way that avoids exposing native-level code symbols. See `datadog_profiling_loader.c` for more details.
|
7
|
-
#
|
8
|
-
# 2. Use the Datadog::Profiling::Loader exposed by the datadog_profiling_loader extension to load the actual
|
9
|
-
# profiling native extension.
|
10
|
-
#
|
11
|
-
# All code on this file is on-purpose at the top-level; this makes it so this file is executed only once,
|
12
|
-
# the first time it gets required, to avoid any issues with the native extension being initialized more than once.
|
13
|
-
|
14
3
|
begin
|
15
|
-
require "
|
4
|
+
require "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
|
16
5
|
rescue LoadError => e
|
17
6
|
raise LoadError,
|
18
7
|
"Failed to load the profiling loader extension. To fix this, please remove and then reinstall datadog " \
|
19
8
|
"(Details: #{e.message})"
|
20
9
|
end
|
21
|
-
|
22
|
-
extension_name = "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
|
23
|
-
file_name = "#{extension_name}.#{RbConfig::CONFIG["DLEXT"]}"
|
24
|
-
full_file_path = "#{__dir__}/../../#{file_name}"
|
25
|
-
|
26
|
-
unless File.exist?(full_file_path)
|
27
|
-
extension_dir = Gem.loaded_specs["datadog"].extension_dir
|
28
|
-
candidate_path = "#{extension_dir}/#{file_name}"
|
29
|
-
if File.exist?(candidate_path)
|
30
|
-
full_file_path = candidate_path
|
31
|
-
else
|
32
|
-
# We found none of the files. This is unexpected. Let's go ahead anyway, the error is going to be reported further
|
33
|
-
# down anyway.
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
init_function_name = "Init_#{extension_name.split(".").first}"
|
38
|
-
|
39
|
-
status, result = Datadog::Profiling::Loader._native_load(full_file_path, init_function_name)
|
40
|
-
|
41
|
-
raise "Failure to load #{extension_name} due to #{result}" if status == :error
|
@@ -16,6 +16,7 @@ module Datadog
|
|
16
16
|
# @public_api
|
17
17
|
module SpanAttributeSchema
|
18
18
|
ENV_GLOBAL_DEFAULT_SERVICE_NAME_ENABLED = 'DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED'
|
19
|
+
ENV_PEER_SERVICE_DEFAULTS_ENABLED = 'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED'
|
19
20
|
ENV_PEER_SERVICE_MAPPING = 'DD_TRACE_PEER_SERVICE_MAPPING'
|
20
21
|
end
|
21
22
|
|
@@ -130,6 +130,20 @@ module Datadog
|
|
130
130
|
o.default({})
|
131
131
|
end
|
132
132
|
|
133
|
+
# Enables population of default in the `peer.service` span tag.
|
134
|
+
# Explicitly setting the `peer.service` for an integration will
|
135
|
+
# still be honored with this option disabled.
|
136
|
+
#
|
137
|
+
# Also when disabled, other peer service related configurations have no effect.
|
138
|
+
#
|
139
|
+
# @default `DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED` environment variable, otherwise `false`
|
140
|
+
# @return [Boolean]
|
141
|
+
option :peer_service_defaults do |o|
|
142
|
+
o.env Tracing::Configuration::Ext::SpanAttributeSchema::ENV_PEER_SERVICE_DEFAULTS_ENABLED
|
143
|
+
o.type :bool
|
144
|
+
o.default false
|
145
|
+
end
|
146
|
+
|
133
147
|
# Global service name behavior
|
134
148
|
settings :global_default_service_name do
|
135
149
|
# Overrides default service name to global service name
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
module GraphQL
|
7
|
+
module Configuration
|
8
|
+
# Parses the environment variable `DD_TRACE_GRAPHQL_ERROR_EXTENSIONS` for error extension names declaration.
|
9
|
+
class ErrorExtensionEnvParser
|
10
|
+
# Parses the environment variable `DD_TRACE_GRAPHQL_ERROR_EXTENSIONS` into an array of error extension names.
|
11
|
+
def self.call(values)
|
12
|
+
# Split by comma, remove leading and trailing whitespaces,
|
13
|
+
# remove empty values, and remove repeated values.
|
14
|
+
values.split(',').each(&:strip!).reject(&:empty?).uniq
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../configuration/settings'
|
4
4
|
require_relative '../ext'
|
5
|
+
require_relative 'error_extension_env_parser'
|
5
6
|
|
6
7
|
module Datadog
|
7
8
|
module Tracing
|
@@ -44,9 +45,19 @@ module Datadog
|
|
44
45
|
end
|
45
46
|
|
46
47
|
option :with_unified_tracer do |o|
|
48
|
+
o.env Ext::ENV_WITH_UNIFIED_TRACER
|
47
49
|
o.type :bool
|
48
50
|
o.default false
|
49
51
|
end
|
52
|
+
|
53
|
+
# Capture error extensions provided by the user in their GraphQL error responses.
|
54
|
+
# The extensions can be anything, so the user is responsible for ensuring they are safe to capture.
|
55
|
+
option :error_extensions do |o|
|
56
|
+
o.env Ext::ENV_ERROR_EXTENSIONS
|
57
|
+
o.type :array, nilable: false
|
58
|
+
o.default []
|
59
|
+
o.env_parser { |v| ErrorExtensionEnvParser.call(v) }
|
60
|
+
end
|
50
61
|
end
|
51
62
|
end
|
52
63
|
end
|
@@ -11,8 +11,13 @@ module Datadog
|
|
11
11
|
# @!visibility private
|
12
12
|
ENV_ANALYTICS_ENABLED = 'DD_TRACE_GRAPHQL_ANALYTICS_ENABLED'
|
13
13
|
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_GRAPHQL_ANALYTICS_SAMPLE_RATE'
|
14
|
+
ENV_WITH_UNIFIED_TRACER = 'DD_TRACE_GRAPHQL_WITH_UNIFIED_TRACER'
|
15
|
+
ENV_ERROR_EXTENSIONS = 'DD_TRACE_GRAPHQL_ERROR_EXTENSIONS'
|
14
16
|
SERVICE_NAME = 'graphql'
|
15
17
|
TAG_COMPONENT = 'graphql'
|
18
|
+
|
19
|
+
# Span event name for query-level errors
|
20
|
+
EVENT_QUERY_ERROR = 'dd.graphql.query.error'
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|