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
@@ -47,14 +47,26 @@ module Datadog
47
47
  end
48
48
 
49
49
  def execute_query(*args, query:, **kwargs)
50
- trace(proc { super }, 'execute', query.selected_operation_name, query: query) do |span|
51
- span.set_tag('graphql.source', query.query_string)
52
- span.set_tag('graphql.operation.type', query.selected_operation.operation_type)
53
- span.set_tag('graphql.operation.name', query.selected_operation_name) if query.selected_operation_name
54
- query.variables.instance_variable_get(:@storage).each do |key, value|
55
- span.set_tag("graphql.variables.#{key}", value)
56
- end
57
- end
50
+ trace(
51
+ proc { super },
52
+ 'execute',
53
+ query.selected_operation_name,
54
+ lambda { |span|
55
+ span.set_tag('graphql.source', query.query_string)
56
+ span.set_tag('graphql.operation.type', query.selected_operation.operation_type)
57
+ if query.selected_operation_name
58
+ span.set_tag(
59
+ 'graphql.operation.name',
60
+ query.selected_operation_name
61
+ )
62
+ end
63
+ query.variables.instance_variable_get(:@storage).each do |key, value|
64
+ span.set_tag("graphql.variables.#{key}", value)
65
+ end
66
+ },
67
+ ->(span) { add_query_error_events(span, query.context.errors) },
68
+ query: query,
69
+ )
58
70
  end
59
71
 
60
72
  def execute_query_lazy(*args, query:, multiplex:, **kwargs)
@@ -131,7 +143,16 @@ module Datadog
131
143
 
132
144
  private
133
145
 
134
- def trace(callable, trace_key, resource, **kwargs)
146
+ # Traces the given callable with the given trace key, resource, and kwargs.
147
+ #
148
+ # @param callable [Proc] the original method call
149
+ # @param trace_key [String] the sub-operation name (`"graphql.#{trace_key}"`)
150
+ # @param resource [String] the resource name for the trace
151
+ # @param before [Proc, nil] a callable to run before the trace, same as the block parameter
152
+ # @param after [Proc, nil] a callable to run after the trace, which has access to query values after execution
153
+ # @param kwargs [Hash] the arguments to pass to `prepare_span`
154
+ # @yield [Span] the block to run before the trace, same as the `before` parameter
155
+ def trace(callable, trace_key, resource, before = nil, after = nil, **kwargs, &before_block)
135
156
  config = Datadog.configuration.tracing[:graphql]
136
157
 
137
158
  Tracing.trace(
@@ -144,11 +165,20 @@ module Datadog
144
165
  Contrib::Analytics.set_sample_rate(span, config[:analytics_sample_rate])
145
166
  end
146
167
 
147
- yield(span) if block_given?
168
+ # A sanity check for us.
169
+ raise 'Please provide either `before` or a block, but not both' if before && before_block
170
+
171
+ if (before_callable = before || before_block)
172
+ before_callable.call(span)
173
+ end
148
174
 
149
175
  prepare_span(trace_key, kwargs, span) if @has_prepare_span
150
176
 
151
- callable.call
177
+ ret = callable.call
178
+
179
+ after.call(span) if after
180
+
181
+ ret
152
182
  end
153
183
  end
154
184
 
@@ -163,6 +193,67 @@ module Datadog
163
193
  operations
164
194
  end
165
195
  end
196
+
197
+ # Create a Span Event for each error that occurs at query level.
198
+ #
199
+ # These are represented in the Datadog App as special GraphQL errors,
200
+ # given their event name `dd.graphql.query.error`.
201
+ def add_query_error_events(span, errors)
202
+ capture_extensions = Datadog.configuration.tracing[:graphql][:error_extensions]
203
+ errors.each do |error|
204
+ extensions = if !capture_extensions.empty? && (extensions = error.extensions)
205
+ # Capture extensions, ensuring all values are primitives
206
+ extensions.each_with_object({}) do |(key, value), hash|
207
+ next unless capture_extensions.include?(key.to_s)
208
+
209
+ value = case value
210
+ when TrueClass, FalseClass, Integer, Float
211
+ value
212
+ else
213
+ # Stringify anything that is not a boolean or a number
214
+ value.to_s
215
+ end
216
+
217
+ hash["extensions.#{key}"] = value
218
+ end
219
+ else
220
+ {}
221
+ end
222
+
223
+ # {::GraphQL::Error#to_h} returns the error formatted in compliance with the GraphQL spec.
224
+ # This is an unwritten contract in the `graphql` library.
225
+ # See for an example: https://github.com/rmosolgo/graphql-ruby/blob/0afa241775e5a113863766cce126214dee093464/lib/graphql/execution_error.rb#L32
226
+ graphql_error = error.to_h
227
+ error = Core::Error.build_from(error)
228
+
229
+ span.span_events << Datadog::Tracing::SpanEvent.new(
230
+ Ext::EVENT_QUERY_ERROR,
231
+ attributes: extensions.merge!(
232
+ message: graphql_error['message'],
233
+ type: error.type,
234
+ stacktrace: error.backtrace,
235
+ locations: serialize_error_locations(graphql_error['locations']),
236
+ path: graphql_error['path'],
237
+ )
238
+ )
239
+ end
240
+ end
241
+
242
+ # Serialize error's `locations` array as an array of Strings, given
243
+ # Span Events do not support hashes nested inside arrays.
244
+ #
245
+ # Here's an example in which `locations`:
246
+ # [
247
+ # {"line" => 3, "column" => 10},
248
+ # {"line" => 7, "column" => 8},
249
+ # ]
250
+ # is serialized as:
251
+ # ["3:10", "7:8"]
252
+ def serialize_error_locations(locations)
253
+ locations.map do |location|
254
+ "#{location['line']}:#{location['column']}"
255
+ end
256
+ end
166
257
  end
167
258
  end
168
259
  end
@@ -31,7 +31,17 @@ module Datadog
31
31
  end
32
32
 
33
33
  def self.to_rack_header(name)
34
- "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
34
+ key = name.to_s.upcase.gsub(/[-\s]/, '_')
35
+ case key
36
+ when 'CONTENT_TYPE', 'CONTENT_LENGTH'
37
+ # NOTE: The Rack spec says:
38
+ # > The environment must not contain the keys HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH
39
+ # > (use the versions without HTTP_).
40
+ # See https://github.com/rack/rack/blob/e217a399eb116362710aac7c5b8dc691ea2189b3/SPEC.rdoc?plain=1#L119-L121
41
+ key
42
+ else
43
+ "HTTP_#{key}"
44
+ end
35
45
  end
36
46
  end
37
47
  end
@@ -43,7 +43,7 @@ module Datadog
43
43
  # so that all spans will be added to the distributed trace.
44
44
  if configuration[:distributed_tracing]
45
45
  trace_digest = Contrib::HTTP.extract(env)
46
- Tracing.continue_trace!(trace_digest)
46
+ Tracing.continue_trace!(trace_digest) if trace_digest
47
47
  end
48
48
 
49
49
  TraceProxyMiddleware.call(env, configuration) do
@@ -21,9 +21,14 @@ module Datadog
21
21
  end
22
22
 
23
23
  def self.set_peer_service!(span, sources)
24
+ config = Datadog.configuration.tracing.contrib
25
+
26
+ # If `peer_service_defaults` is disabled, we only read peer service from an explicitly set `peer.service` tag
27
+ sources = Datadog::Tracing::Contrib::SpanAttributeSchema::REFLEXIVE_SOURCES unless config.peer_service_defaults
28
+
24
29
  # Acquire all peer.service values as well as any potential remapping
25
30
  peer_service_val, peer_service_source = set_peer_service_from_source(span, sources)
26
- remap_val = Datadog.configuration.tracing.contrib.peer_service_mapping[peer_service_val]
31
+ remap_val = config.peer_service_mapping[peer_service_val]
27
32
 
28
33
  # Only continue to setting peer.service if actual source is found
29
34
  return false unless peer_service_source
@@ -17,6 +17,7 @@ module Datadog
17
17
  # @public_api
18
18
  class SyncWriter
19
19
  attr_reader \
20
+ :logger,
20
21
  :events,
21
22
  :transport
22
23
 
@@ -25,7 +26,9 @@ module Datadog
25
26
  # @param [Hash<Symbol,Object>] transport_options options for the default transport instance.
26
27
  # @param [Datadog::Tracing::Configuration::AgentSettingsResolver::AgentSettings] agent_settings agent options for
27
28
  # the default transport instance.
28
- def initialize(transport: nil, transport_options: {}, agent_settings: nil)
29
+ def initialize(transport: nil, transport_options: {}, agent_settings: nil, logger: Datadog.logger)
30
+ @logger = logger
31
+
29
32
  @transport = transport || begin
30
33
  transport_options[:agent_settings] = agent_settings if agent_settings
31
34
  Transport::HTTP.default(**transport_options)
@@ -40,7 +43,7 @@ module Datadog
40
43
  def write(trace)
41
44
  flush_trace(trace)
42
45
  rescue => e
43
- Datadog.logger.debug(e)
46
+ logger.debug(e)
44
47
  end
45
48
 
46
49
  # Does nothing.
@@ -28,7 +28,8 @@ module Datadog
28
28
  :provider,
29
29
  :sampler,
30
30
  :span_sampler,
31
- :tags
31
+ :tags,
32
+ :logger
32
33
 
33
34
  attr_accessor \
34
35
  :default_service,
@@ -52,17 +53,19 @@ module Datadog
52
53
  context_provider: DefaultContextProvider.new,
53
54
  default_service: Core::Environment::Ext::FALLBACK_SERVICE_NAME,
54
55
  enabled: true,
56
+ logger: Datadog.logger,
55
57
  sampler: Sampling::PrioritySampler.new(
56
58
  base_sampler: Sampling::AllSampler.new,
57
59
  post_sampler: Sampling::RuleSampler.new
58
60
  ),
59
61
  span_sampler: Sampling::Span::Sampler.new,
60
62
  tags: {},
61
- writer: Writer.new
63
+ writer: Writer.new(logger: logger)
62
64
  )
63
65
  @trace_flush = trace_flush
64
66
  @default_service = default_service
65
67
  @enabled = enabled
68
+ @logger = logger
66
69
  @provider = context_provider
67
70
  @sampler = sampler
68
71
  @span_sampler = span_sampler
@@ -146,7 +149,7 @@ module Datadog
146
149
  active_trace
147
150
  end
148
151
  rescue StandardError => e
149
- Datadog.logger.debug { "Failed to trace: #{e}" }
152
+ logger.debug { "Failed to trace: #{e}" }
150
153
 
151
154
  # Tracing failed: fallback and run code without tracing.
152
155
  return skip_trace(name, &block)
@@ -268,7 +271,7 @@ module Datadog
268
271
  @sampler.sample!(trace_op)
269
272
  rescue StandardError => e
270
273
  SAMPLE_TRACE_LOG_ONLY_ONCE.run do
271
- Datadog.logger.warn { "Failed to sample trace: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
274
+ logger.warn { "Failed to sample trace: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
272
275
  end
273
276
  end
274
277
  end
@@ -488,7 +491,7 @@ module Datadog
488
491
  @span_sampler.sample!(trace_op, span)
489
492
  rescue StandardError => e
490
493
  SAMPLE_SPAN_LOG_ONLY_ONCE.run do
491
- Datadog.logger.warn { "Failed to sample span: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
494
+ logger.warn { "Failed to sample span: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
492
495
  end
493
496
  end
494
497
  end
@@ -504,7 +507,7 @@ module Datadog
504
507
  write(trace) if trace && !trace.empty?
505
508
  rescue StandardError => e
506
509
  FLUSH_TRACE_LOG_ONLY_ONCE.run do
507
- Datadog.logger.warn { "Failed to flush trace: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
510
+ logger.warn { "Failed to flush trace: #{e.class.name} #{e} at #{Array(e.backtrace).first}" }
508
511
  end
509
512
  end
510
513
  end
@@ -518,7 +521,7 @@ module Datadog
518
521
  return unless trace && @writer
519
522
 
520
523
  if Datadog.configuration.diagnostics.debug
521
- Datadog.logger.debug { "Writing #{trace.length} spans (enabled: #{@enabled})\n#{trace.spans.pretty_inspect}" }
524
+ logger.debug { "Writing #{trace.length} spans (enabled: #{@enabled})\n#{trace.spans.pretty_inspect}" }
522
525
  end
523
526
 
524
527
  @writer.write(trace)
@@ -3,7 +3,8 @@
3
3
  require_relative '../../../core/encoding'
4
4
 
5
5
  require_relative '../../../core/transport/http/api/map'
6
- require_relative 'api/spec'
6
+ require_relative '../../../core/transport/http/api/instance'
7
+ require_relative '../../../core/transport/http/api/spec'
7
8
 
8
9
  require_relative 'traces'
9
10
 
@@ -20,7 +21,7 @@ module Datadog
20
21
  module_function
21
22
 
22
23
  def defaults
23
- Datadog::Core::Transport::HTTP::API::Map[
24
+ Core::Transport::HTTP::API::Map[
24
25
  V4 => Spec.new do |s|
25
26
  s.traces = Traces::API::Endpoint.new(
26
27
  '/v0.4/traces',
@@ -36,6 +37,14 @@ module Datadog
36
37
  end,
37
38
  ].with_fallbacks(V4 => V3)
38
39
  end
40
+
41
+ class Instance < Core::Transport::HTTP::API::Instance
42
+ include Traces::API::Instance
43
+ end
44
+
45
+ class Spec < Core::Transport::HTTP::API::Spec
46
+ include Traces::API::Spec
47
+ end
39
48
  end
40
49
  end
41
50
  end
@@ -6,7 +6,6 @@ require_relative '../traces'
6
6
  require_relative 'client'
7
7
  require_relative '../../../core/transport/http/response'
8
8
  require_relative '../../../core/transport/http/api/endpoint'
9
- require_relative 'api/instance'
10
9
 
11
10
  module Datadog
12
11
  module Tracing
@@ -143,8 +142,6 @@ module Datadog
143
142
 
144
143
  # Add traces behavior to transport components
145
144
  HTTP::Client.include(Traces::Client)
146
- HTTP::API::Spec.include(Traces::API::Spec)
147
- HTTP::API::Instance.include(Traces::API::Instance)
148
145
  end
149
146
  end
150
147
  end
@@ -8,8 +8,8 @@ require_relative '../../core/transport/ext'
8
8
  require_relative '../../core/transport/http/adapters/net'
9
9
  require_relative '../../core/transport/http/adapters/test'
10
10
  require_relative '../../core/transport/http/adapters/unix_socket'
11
+ require_relative '../../core/transport/http/builder'
11
12
  require_relative 'http/api'
12
- require_relative 'http/builder'
13
13
  require_relative '../../../datadog/version'
14
14
 
15
15
  module Datadog
@@ -30,8 +30,10 @@ module Datadog
30
30
  module_function
31
31
 
32
32
  # Builds a new Transport::HTTP::Client
33
- def new(&block)
34
- Builder.new(&block).to_transport
33
+ def new(klass, &block)
34
+ Core::Transport::HTTP::Builder.new(
35
+ api_instance_class: API::Instance, &block
36
+ ).to_transport(klass)
35
37
  end
36
38
 
37
39
  # Builds a new Transport::HTTP::Client with default settings
@@ -40,7 +42,7 @@ module Datadog
40
42
  agent_settings: DO_NOT_USE_ENVIRONMENT_AGENT_SETTINGS,
41
43
  **options
42
44
  )
43
- new do |transport|
45
+ new(Transport::Traces::Transport) do |transport|
44
46
  transport.adapter(agent_settings)
45
47
  transport.headers default_headers
46
48
 
@@ -86,12 +88,15 @@ module Datadog
86
88
  end
87
89
 
88
90
  # Add adapters to registry
89
- Builder::REGISTRY.set(
91
+ Core::Transport::HTTP::Builder::REGISTRY.set(
90
92
  Datadog::Core::Transport::HTTP::Adapters::Net,
91
93
  Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
92
94
  )
93
- Builder::REGISTRY.set(Datadog::Core::Transport::HTTP::Adapters::Test, Datadog::Core::Transport::Ext::Test::ADAPTER)
94
- Builder::REGISTRY.set(
95
+ Core::Transport::HTTP::Builder::REGISTRY.set(
96
+ Datadog::Core::Transport::HTTP::Adapters::Test,
97
+ Datadog::Core::Transport::Ext::Test::ADAPTER
98
+ )
99
+ Core::Transport::HTTP::Builder::REGISTRY.set(
95
100
  Datadog::Core::Transport::HTTP::Adapters::UnixSocket,
96
101
  Datadog::Core::Transport::Ext::UnixSocket::ADAPTER
97
102
  )
@@ -14,7 +14,7 @@ module Datadog
14
14
 
15
15
  # @param trace [Datadog::Trace] the trace to serialize
16
16
  # @param native_events_supported [Boolean] whether the agent supports span events as a top-level field
17
- def initialize(trace, native_events_supported = false)
17
+ def initialize(trace, native_events_supported:)
18
18
  @trace = trace
19
19
  @native_events_supported = native_events_supported
20
20
  end
@@ -29,13 +29,17 @@ module Datadog
29
29
  # @param packer [MessagePack::Packer] serialization buffer, can be +nil+ with JRuby
30
30
  def to_msgpack(packer = nil)
31
31
  # As of 1.3.3, JRuby implementation doesn't pass an existing packer
32
- trace.spans.map { |s| SerializableSpan.new(s, @native_events_supported) }.to_msgpack(packer)
32
+ trace.spans.map do |s|
33
+ SerializableSpan.new(s, native_events_supported: @native_events_supported)
34
+ end.to_msgpack(packer)
33
35
  end
34
36
 
35
37
  # JSON serializer interface.
36
38
  # Used by older version of the transport.
37
39
  def to_json(*args)
38
- trace.spans.map { |s| SerializableSpan.new(s, @native_events_supported).to_hash }.to_json(*args)
40
+ trace.spans.map do |s|
41
+ SerializableSpan.new(s, native_events_supported: @native_events_supported).to_hash
42
+ end.to_json(*args)
39
43
  end
40
44
  end
41
45
 
@@ -46,7 +50,7 @@ module Datadog
46
50
 
47
51
  # @param span [Datadog::Span] the span to serialize
48
52
  # @param native_events_supported [Boolean] whether the agent supports span events as a top-level field
49
- def initialize(span, native_events_supported)
53
+ def initialize(span, native_events_supported:)
50
54
  @span = span
51
55
  @trace_id = Tracing::Utils::TraceId.to_low_order(span.trace_id)
52
56
  @native_events_supported = native_events_supported
@@ -50,8 +50,9 @@ module Datadog
50
50
  #
51
51
  # @param encoder [Datadog::Core::Encoding::Encoder]
52
52
  # @param max_size [String] maximum acceptable payload size
53
- def initialize(encoder, max_size: DEFAULT_MAX_PAYLOAD_SIZE)
53
+ def initialize(encoder, native_events_supported:, max_size: DEFAULT_MAX_PAYLOAD_SIZE)
54
54
  @encoder = encoder
55
+ @native_events_supported = native_events_supported
55
56
  @max_size = max_size
56
57
  end
57
58
 
@@ -77,7 +78,7 @@ module Datadog
77
78
  private
78
79
 
79
80
  def encode_one(trace)
80
- encoded = Encoder.encode_trace(encoder, trace)
81
+ encoded = Encoder.encode_trace(encoder, trace, native_events_supported: @native_events_supported)
81
82
 
82
83
  if encoded.size > max_size
83
84
  # This single trace is too large, we can't flush it
@@ -95,17 +96,18 @@ module Datadog
95
96
  module Encoder
96
97
  module_function
97
98
 
98
- def encode_trace(encoder, trace)
99
+ def encode_trace(encoder, trace, native_events_supported:)
99
100
  # Format the trace for transport
100
101
  TraceFormatter.format!(trace)
101
102
 
102
103
  # Make the trace serializable
103
- serializable_trace = SerializableTrace.new(trace)
104
-
105
- Datadog.logger.debug { "Flushing trace: #{JSON.dump(serializable_trace)}" }
104
+ serializable_trace = SerializableTrace.new(trace, native_events_supported: native_events_supported)
106
105
 
107
106
  # Encode the trace
108
- encoder.encode(serializable_trace)
107
+ encoder.encode(serializable_trace).tap do |encoded|
108
+ # Print the actual serialized trace, since the encoder can change make non-trivial changes
109
+ Datadog.logger.debug { "Flushing trace: #{encoder.decode(encoded)}" }
110
+ end
109
111
  end
110
112
  end
111
113
 
@@ -126,7 +128,10 @@ module Datadog
126
128
 
127
129
  def send_traces(traces)
128
130
  encoder = current_api.encoder
129
- chunker = Datadog::Tracing::Transport::Traces::Chunker.new(encoder)
131
+ chunker = Datadog::Tracing::Transport::Traces::Chunker.new(
132
+ encoder,
133
+ native_events_supported: native_events_supported?
134
+ )
130
135
 
131
136
  responses = chunker.encode_in_chunks(traces.lazy).map do |encoded_traces, trace_count|
132
137
  request = Request.new(EncodedParcel.new(encoded_traces, trace_count))
@@ -188,6 +193,18 @@ module Datadog
188
193
  @client = HTTP::Client.new(current_api)
189
194
  end
190
195
 
196
+ # Queries the agent for native span events serialization support.
197
+ # This changes how the serialization of span events performed.
198
+ def native_events_supported?
199
+ return @native_events_supported if defined?(@native_events_supported)
200
+
201
+ if (res = Datadog.send(:components).agent_info.fetch)
202
+ @native_events_supported = res.span_events == true
203
+ else
204
+ false
205
+ end
206
+ end
207
+
191
208
  # Raised when configured with an unknown API version
192
209
  class UnknownApiVersionError < StandardError
193
210
  attr_reader :version
@@ -17,10 +17,13 @@ module Datadog
17
17
  # Writes traces to transport synchronously
18
18
  class TraceWriter < Core::Worker
19
19
  attr_reader \
20
+ :logger,
20
21
  :transport
21
22
 
22
23
  # rubocop:disable Lint/MissingSuper
23
24
  def initialize(options = {})
25
+ @logger = options[:logger] || Datadog.logger
26
+
24
27
  transport_options = options.fetch(:transport_options, {})
25
28
 
26
29
  transport_options[:agent_settings] = options[:agent_settings] if options.key?(:agent_settings)
@@ -43,7 +46,7 @@ module Datadog
43
46
  traces = process_traces(traces)
44
47
  flush_traces(traces)
45
48
  rescue StandardError => e
46
- Datadog.logger.warn(
49
+ logger.warn(
47
50
  "Error while writing traces: dropped #{traces.length} items. Cause: #{e} Location: #{Array(e.backtrace).first}"
48
51
  )
49
52
  end
@@ -18,8 +18,7 @@ module Datadog
18
18
  BACK_OFF_MAX = 5
19
19
  DEFAULT_SHUTDOWN_TIMEOUT = 1
20
20
 
21
- attr_reader \
22
- :trace_buffer
21
+ attr_reader :trace_buffer, :logger
23
22
 
24
23
  def initialize(options = {})
25
24
  @transport = options[:transport]
@@ -42,6 +41,8 @@ module Datadog
42
41
  @mutex = Mutex.new
43
42
  @worker = nil
44
43
  @run = false
44
+
45
+ @logger = options.fetch(:logger)
45
46
  end
46
47
 
47
48
  # Callback function that process traces and executes the +send_traces()+ method.
@@ -56,7 +57,7 @@ module Datadog
56
57
  # ensures that the thread will not die because of an exception.
57
58
  # TODO[manu]: findout the reason and reschedule the send if it's not
58
59
  # a fatal exception
59
- Datadog.logger.warn(
60
+ logger.warn(
60
61
  "Error during traces flush: dropped #{traces.length} items. Cause: #{e} Location: #{Array(e.backtrace).first}"
61
62
  )
62
63
  end
@@ -68,7 +69,7 @@ module Datadog
68
69
  return if @run
69
70
 
70
71
  @run = true
71
- Datadog.logger.debug { "Starting thread for: #{self}" }
72
+ logger.debug { "Starting thread for: #{self}" }
72
73
  @worker = Thread.new { perform }
73
74
  @worker.name = self.class.name
74
75
  @worker.thread_variable_set(:fork_safe, true)
@@ -13,11 +13,14 @@ module Datadog
13
13
  # @public_api
14
14
  class Writer
15
15
  attr_reader \
16
+ :logger,
16
17
  :transport,
17
18
  :worker,
18
19
  :events
19
20
 
20
21
  def initialize(options = {})
22
+ @logger = options[:logger] || Datadog.logger
23
+
21
24
  # writer and transport parameters
22
25
  @buff_size = options.fetch(:buffer_size, Workers::AsyncTransport::DEFAULT_BUFFER_MAX_SIZE)
23
26
  @flush_interval = options.fetch(:flush_interval, Workers::AsyncTransport::DEFAULT_FLUSH_INTERVAL)
@@ -119,7 +122,7 @@ module Datadog
119
122
  if worker_local
120
123
  worker_local.enqueue_trace(trace)
121
124
  elsif !@stopped
122
- Datadog.logger.debug('Writer either failed to start or was stopped before #write could complete')
125
+ logger.debug('Writer either failed to start or was stopped before #write could complete')
123
126
  end
124
127
  end
125
128
 
@@ -160,7 +163,8 @@ module Datadog
160
163
  buffer_size: @buff_size,
161
164
  on_trace: @trace_handler,
162
165
  interval: @flush_interval,
163
- shutdown_timeout: @shutdown_timeout
166
+ shutdown_timeout: @shutdown_timeout,
167
+ logger: logger,
164
168
  )
165
169
 
166
170
  @worker.start
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 10
6
+ MINOR = 12
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil