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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -1
  3. data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +44 -1
  5. data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
  6. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  7. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  8. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  9. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +56 -0
  10. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
  11. data/ext/datadog_profiling_native_extension/profiling.c +7 -0
  12. data/ext/libdatadog_api/crashtracker.c +4 -4
  13. data/ext/libdatadog_extconf_helpers.rb +1 -1
  14. data/lib/datadog/appsec/configuration/settings.rb +64 -11
  15. data/lib/datadog/appsec/contrib/active_record/patcher.rb +0 -3
  16. data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
  17. data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
  18. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
  19. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
  20. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
  21. data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
  22. data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
  23. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  24. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  25. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
  26. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  27. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  28. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  29. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  30. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
  31. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +10 -12
  32. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  33. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +65 -73
  34. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  35. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -25
  36. data/lib/datadog/appsec/contrib/rails/patcher.rb +0 -3
  37. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  38. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  39. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
  40. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -49
  41. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +0 -3
  42. data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -25
  43. data/lib/datadog/appsec/remote.rb +4 -0
  44. data/lib/datadog/appsec.rb +3 -0
  45. data/lib/datadog/core/configuration/components.rb +8 -2
  46. data/lib/datadog/core/configuration/ext.rb +1 -1
  47. data/lib/datadog/core/configuration/option_definition.rb +2 -0
  48. data/lib/datadog/core/configuration/settings.rb +22 -6
  49. data/lib/datadog/core/encoding.rb +16 -0
  50. data/lib/datadog/core/environment/agent_info.rb +77 -0
  51. data/lib/datadog/core/remote/component.rb +11 -9
  52. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  53. data/lib/datadog/core/remote/transport/http/config.rb +0 -18
  54. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
  55. data/lib/datadog/core/remote/transport/http.rb +7 -12
  56. data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
  57. data/lib/datadog/core/remote/worker.rb +10 -7
  58. data/lib/datadog/core/telemetry/component.rb +5 -1
  59. data/lib/datadog/core/telemetry/event.rb +5 -0
  60. data/lib/datadog/core/telemetry/worker.rb +9 -5
  61. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  62. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
  63. data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
  64. data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
  65. data/lib/datadog/core/transport/response.rb +4 -0
  66. data/lib/datadog/di/code_tracker.rb +15 -8
  67. data/lib/datadog/di/component.rb +2 -3
  68. data/lib/datadog/di/configuration/settings.rb +14 -0
  69. data/lib/datadog/di/contrib.rb +2 -0
  70. data/lib/datadog/di/logger.rb +30 -0
  71. data/lib/datadog/di/probe.rb +3 -6
  72. data/lib/datadog/di/probe_manager.rb +5 -2
  73. data/lib/datadog/di/probe_notifier_worker.rb +35 -8
  74. data/lib/datadog/di/remote.rb +3 -3
  75. data/lib/datadog/di/transport/diagnostics.rb +61 -0
  76. data/lib/datadog/di/transport/http/api.rb +52 -0
  77. data/lib/datadog/di/transport/http/client.rb +46 -0
  78. data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
  79. data/lib/datadog/di/transport/http/input.rb +94 -0
  80. data/lib/datadog/di/transport/http.rb +119 -0
  81. data/lib/datadog/di/transport/input.rb +61 -0
  82. data/lib/datadog/di/utils.rb +91 -0
  83. data/lib/datadog/di.rb +5 -1
  84. data/lib/datadog/profiling/component.rb +2 -8
  85. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  86. data/lib/datadog/tracing/component.rb +1 -0
  87. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  88. data/lib/datadog/tracing/contrib/extensions.rb +14 -0
  89. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  90. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  91. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  92. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  93. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  94. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  95. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  96. data/lib/datadog/tracing/sync_writer.rb +5 -2
  97. data/lib/datadog/tracing/tracer.rb +10 -7
  98. data/lib/datadog/tracing/transport/http/api.rb +11 -2
  99. data/lib/datadog/tracing/transport/http/traces.rb +0 -3
  100. data/lib/datadog/tracing/transport/http.rb +12 -7
  101. data/lib/datadog/tracing/transport/serializable_trace.rb +8 -4
  102. data/lib/datadog/tracing/transport/traces.rb +25 -8
  103. data/lib/datadog/tracing/workers/trace_writer.rb +4 -1
  104. data/lib/datadog/tracing/workers.rb +5 -4
  105. data/lib/datadog/tracing/writer.rb +6 -2
  106. data/lib/datadog/version.rb +1 -1
  107. metadata +33 -29
  108. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  109. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  110. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  111. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  112. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  113. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  114. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  115. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  116. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  117. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  118. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  119. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  120. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  121. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  122. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  123. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  124. 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
@@ -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.preview_gvl_enabled
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 "datadog_profiling_loader.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
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
@@ -49,6 +49,7 @@ module Datadog
49
49
  Tracing::Tracer.new(
50
50
  default_service: settings.service,
51
51
  enabled: settings.tracing.enabled,
52
+ logger: logger,
52
53
  trace_flush: trace_flush,
53
54
  sampler: sampler_delegator,
54
55
  span_sampler: build_span_sampler(settings),
@@ -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