ddtrace 1.4.1 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +144 -1
  3. data/LICENSE-3rdparty.csv +1 -0
  4. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +9 -2
  5. data/ext/ddtrace_profiling_loader/extconf.rb +17 -0
  6. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +38 -2
  7. data/ext/ddtrace_profiling_native_extension/clock_id.h +1 -0
  8. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +1 -0
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +517 -42
  10. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +3 -0
  11. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +208 -30
  12. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +156 -46
  13. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +11 -2
  14. data/ext/ddtrace_profiling_native_extension/extconf.rb +11 -1
  15. data/ext/ddtrace_profiling_native_extension/http_transport.c +83 -64
  16. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +4 -4
  17. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +3 -4
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +59 -0
  19. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  20. data/ext/ddtrace_profiling_native_extension/profiling.c +10 -0
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +0 -1
  22. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +4 -2
  23. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +45 -29
  24. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +7 -7
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +1169 -275
  26. data/lib/datadog/appsec/assets/waf_rules/risky.json +78 -78
  27. data/lib/datadog/appsec/assets/waf_rules/strict.json +278 -88
  28. data/lib/datadog/appsec/configuration/settings.rb +0 -2
  29. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +25 -20
  30. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
  31. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +11 -11
  32. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +11 -11
  33. data/lib/datadog/appsec/contrib/rack/request.rb +3 -0
  34. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +46 -19
  35. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -6
  36. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +11 -11
  38. data/lib/datadog/appsec/contrib/rails/request.rb +3 -0
  39. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +14 -12
  40. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +11 -11
  41. data/lib/datadog/appsec/event.rb +6 -10
  42. data/lib/datadog/appsec/instrumentation/gateway.rb +16 -2
  43. data/lib/datadog/appsec/processor.rb +18 -2
  44. data/lib/datadog/ci/ext/environment.rb +16 -4
  45. data/lib/datadog/core/configuration/agent_settings_resolver.rb +0 -3
  46. data/lib/datadog/core/configuration/components.rb +28 -16
  47. data/lib/datadog/core/configuration/settings.rb +127 -8
  48. data/lib/datadog/core/configuration.rb +1 -1
  49. data/lib/datadog/core/diagnostics/environment_logger.rb +5 -1
  50. data/lib/datadog/core/header_collection.rb +41 -0
  51. data/lib/datadog/core/telemetry/collector.rb +0 -2
  52. data/lib/datadog/core/utils/compression.rb +5 -1
  53. data/lib/datadog/core/workers/async.rb +0 -2
  54. data/lib/datadog/core.rb +0 -54
  55. data/lib/datadog/opentracer/tracer.rb +4 -6
  56. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +12 -2
  57. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +5 -3
  58. data/lib/datadog/profiling/collectors/old_stack.rb +1 -1
  59. data/lib/datadog/profiling/exporter.rb +2 -4
  60. data/lib/datadog/profiling/http_transport.rb +1 -1
  61. data/lib/datadog/profiling.rb +1 -1
  62. data/lib/datadog/tracing/client_ip.rb +164 -0
  63. data/lib/datadog/tracing/configuration/ext.rb +14 -0
  64. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +2 -0
  65. data/lib/datadog/tracing/contrib/aws/services.rb +0 -2
  66. data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
  67. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -0
  68. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +2 -0
  69. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -0
  70. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +2 -2
  71. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +2 -0
  72. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -0
  73. data/lib/datadog/tracing/contrib/ext.rb +25 -0
  74. data/lib/datadog/tracing/contrib/faraday/middleware.rb +3 -2
  75. data/lib/datadog/tracing/contrib/grape/endpoint.rb +0 -2
  76. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +1 -1
  77. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +5 -0
  78. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +7 -1
  79. data/lib/datadog/tracing/contrib/grpc/ext.rb +2 -0
  80. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
  81. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +22 -0
  82. data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
  83. data/lib/datadog/tracing/contrib/hanami/integration.rb +44 -0
  84. data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
  85. data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
  86. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
  87. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
  88. data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -0
  89. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +2 -0
  90. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -0
  91. data/lib/datadog/tracing/contrib/mongodb/ext.rb +7 -0
  92. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -0
  93. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +12 -0
  94. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
  95. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -0
  96. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +12 -0
  97. data/lib/datadog/tracing/contrib/pg/ext.rb +2 -1
  98. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +38 -21
  99. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +43 -0
  100. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +32 -0
  101. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
  102. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +49 -0
  103. data/lib/datadog/tracing/contrib/rack/header_collection.rb +35 -0
  104. data/lib/datadog/tracing/contrib/rack/middlewares.rb +105 -43
  105. data/lib/datadog/tracing/contrib/redis/ext.rb +2 -0
  106. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +4 -2
  107. data/lib/datadog/tracing/contrib/redis/integration.rb +2 -1
  108. data/lib/datadog/tracing/contrib/redis/patcher.rb +40 -0
  109. data/lib/datadog/tracing/contrib/redis/tags.rb +5 -0
  110. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +2 -0
  111. data/lib/datadog/tracing/contrib/sinatra/env.rb +12 -23
  112. data/lib/datadog/tracing/contrib/sinatra/ext.rb +7 -3
  113. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +2 -2
  114. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +8 -80
  115. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +14 -9
  116. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +92 -10
  117. data/lib/datadog/tracing/contrib.rb +1 -0
  118. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
  119. data/lib/datadog/tracing/distributed/headers/datadog.rb +122 -30
  120. data/lib/datadog/tracing/distributed/headers/ext.rb +2 -0
  121. data/lib/datadog/tracing/flush.rb +57 -35
  122. data/lib/datadog/tracing/metadata/ext.rb +11 -9
  123. data/lib/datadog/tracing/metadata/tagging.rb +9 -0
  124. data/lib/datadog/tracing/propagation/http.rb +9 -1
  125. data/lib/datadog/tracing/sampling/ext.rb +31 -0
  126. data/lib/datadog/tracing/sampling/priority_sampler.rb +46 -4
  127. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +8 -9
  128. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +29 -5
  129. data/lib/datadog/tracing/sampling/rate_limiter.rb +3 -0
  130. data/lib/datadog/tracing/sampling/rate_sampler.rb +20 -3
  131. data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -3
  132. data/lib/datadog/tracing/sampling/span/ext.rb +25 -0
  133. data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
  134. data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
  135. data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
  136. data/lib/datadog/tracing/sampling/span/sampler.rb +75 -0
  137. data/lib/datadog/tracing/span_operation.rb +0 -2
  138. data/lib/datadog/tracing/trace_digest.rb +3 -0
  139. data/lib/datadog/tracing/trace_operation.rb +32 -3
  140. data/lib/datadog/tracing/trace_segment.rb +7 -2
  141. data/lib/datadog/tracing/tracer.rb +34 -6
  142. data/lib/datadog/tracing/writer.rb +7 -0
  143. data/lib/ddtrace/transport/trace_formatter.rb +7 -0
  144. data/lib/ddtrace/transport/traces.rb +3 -1
  145. data/lib/ddtrace/version.rb +1 -1
  146. metadata +36 -18
  147. data/lib/datadog/profiling/old_ext.rb +0 -42
  148. data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
  149. data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
  150. data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
  151. data/lib/datadog/profiling/transport/http/api.rb +0 -45
  152. data/lib/datadog/profiling/transport/http/builder.rb +0 -30
  153. data/lib/datadog/profiling/transport/http/client.rb +0 -37
  154. data/lib/datadog/profiling/transport/http/response.rb +0 -21
  155. data/lib/datadog/profiling/transport/http.rb +0 -118
@@ -0,0 +1,49 @@
1
+ # typed: false
2
+
3
+ require_relative 'sql_comment/comment'
4
+ require_relative 'sql_comment/ext'
5
+
6
+ module Datadog
7
+ module Tracing
8
+ module Contrib
9
+ module Propagation
10
+ # Implements sql comment propagation related contracts.
11
+ module SqlComment
12
+ def self.annotate!(span_op, mode)
13
+ return unless mode.enabled?
14
+
15
+ # PENDING: Until `traceparent`` implementation in `full` mode
16
+ # span_op.set_tag(Ext::TAG_DBM_TRACE_INJECTED, true) if mode.full?
17
+ end
18
+
19
+ def self.prepend_comment(sql, span_op, mode)
20
+ return sql unless mode.enabled?
21
+
22
+ tags = {
23
+ Ext::KEY_DATABASE_SERVICE => span_op.service,
24
+ Ext::KEY_ENVIRONMENT => datadog_configuration.env,
25
+ Ext::KEY_PARENT_SERVICE => datadog_configuration.service,
26
+ Ext::KEY_VERSION => datadog_configuration.version
27
+ }
28
+
29
+ # PENDING: Until `traceparent`` implementation in `full` mode
30
+ # tags.merge!(trace_context(span_op)) if mode.full?
31
+
32
+ "#{Comment.new(tags)} #{sql}"
33
+ end
34
+
35
+ def self.datadog_configuration
36
+ Datadog.configuration
37
+ end
38
+
39
+ # TODO: Derive from trace
40
+ def self.trace_context(_)
41
+ {
42
+ # traceparent: '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01'
43
+ }.freeze
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../../../core/header_collection'
2
+
3
+ module Datadog
4
+ module Tracing
5
+ module Contrib
6
+ module Rack
7
+ # Classes and utilities for handling headers in Rack.
8
+ module Header
9
+ # An implementation of a header collection that looks up headers from a Rack environment.
10
+ class RequestHeaderCollection < Datadog::Core::HeaderCollection
11
+ # Creates a header collection from a rack environment.
12
+ def initialize(env)
13
+ super()
14
+ @env = env
15
+ end
16
+
17
+ # Gets the value of the header with the given name.
18
+ def get(header_name)
19
+ @env[Header.to_rack_header(header_name)]
20
+ end
21
+
22
+ # Tests whether a header with the given name exists in the environment.
23
+ def key?(header_name)
24
+ @env.key?(Header.to_rack_header(header_name))
25
+ end
26
+ end
27
+
28
+ def self.to_rack_header(name)
29
+ "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -3,12 +3,14 @@
3
3
  require 'date'
4
4
 
5
5
  require_relative '../../../core/environment/variable_helpers'
6
+ require_relative '../../client_ip'
6
7
  require_relative '../../metadata/ext'
7
8
  require_relative '../../propagation/http'
8
9
  require_relative '../analytics'
10
+ require_relative '../utils/quantization/http'
9
11
  require_relative 'ext'
12
+ require_relative 'header_collection'
10
13
  require_relative 'request_queue'
11
- require_relative '../utils/quantization/http'
12
14
 
13
15
  module Datadog
14
16
  module Tracing
@@ -54,16 +56,18 @@ module Datadog
54
56
  # Find out if this is rack within rack
55
57
  previous_request_span = env[Ext::RACK_ENV_REQUEST_SPAN]
56
58
 
59
+ return @app.call(env) if previous_request_span
60
+
57
61
  # Extract distributed tracing context before creating any spans,
58
62
  # so that all spans will be added to the distributed trace.
59
- if configuration[:distributed_tracing] && previous_request_span.nil?
63
+ if configuration[:distributed_tracing]
60
64
  trace_digest = Tracing::Propagation::HTTP.extract(env)
61
65
  Tracing.continue_trace!(trace_digest)
62
66
  end
63
67
 
64
68
  # Create a root Span to keep track of frontend web servers
65
69
  # (i.e. Apache, nginx) if the header is properly set
66
- frontend_span = compute_queue_time(env) if previous_request_span.nil?
70
+ frontend_span = compute_queue_time(env)
67
71
 
68
72
  trace_options = { span_type: Tracing::Metadata::Ext::HTTP::TYPE_INBOUND }
69
73
  trace_options[:service] = configuration[:service_name] if configuration[:service_name]
@@ -121,20 +125,17 @@ module Datadog
121
125
  # rubocop:disable Metrics/PerceivedComplexity
122
126
  # rubocop:disable Metrics/MethodLength
123
127
  def set_request_tags!(trace, request_span, env, status, headers, response, original_env)
124
- # http://www.rubydoc.info/github/rack/rack/file/SPEC
125
- # The source of truth in Rack is the PATH_INFO key that holds the
126
- # URL for the current request; but some frameworks may override that
127
- # value, especially during exception handling.
128
- #
129
- # Because of this, we prefer to use REQUEST_URI, if available, which is the
130
- # relative path + query string, and doesn't mutate.
131
- #
132
- # REQUEST_URI is only available depending on what web server is running though.
133
- # So when its not available, we want the original, unmutated PATH_INFO, which
134
- # is just the relative path without query strings.
135
- url = env['REQUEST_URI'] || original_env['PATH_INFO']
136
- request_headers = parse_request_headers(env)
137
- response_headers = parse_response_headers(headers || {})
128
+ request_header_collection = Header::RequestHeaderCollection.new(env)
129
+ request_headers_tags = parse_request_headers(request_header_collection)
130
+ response_headers_tags = parse_response_headers(headers || {})
131
+
132
+ # Since it could be mutated, it would be more accurate to fetch from the original env,
133
+ # e.g. ActionDispatch::ShowExceptions middleware with Rails exceptions_app configuration
134
+ original_request_method = original_env['REQUEST_METHOD']
135
+
136
+ # request_headers is subject to filtering and configuration so we
137
+ # get the user agent separately
138
+ user_agent = parse_user_agent_header(request_header_collection)
138
139
 
139
140
  # The priority
140
141
  # 1. User overrides span.resource
@@ -143,11 +144,11 @@ module Datadog
143
144
  # 4. Fallback with verb + status, eq `GET 200`
144
145
  request_span.resource ||=
145
146
  if configuration[:middleware_names] && env['RESPONSE_MIDDLEWARE']
146
- "#{env['RESPONSE_MIDDLEWARE']}##{env['REQUEST_METHOD']}"
147
+ "#{env['RESPONSE_MIDDLEWARE']}##{original_request_method}"
147
148
  elsif trace.resource_override?
148
149
  trace.resource
149
150
  else
150
- "#{env['REQUEST_METHOD']} #{status}".strip
151
+ "#{original_request_method} #{status}".strip
151
152
  end
152
153
 
153
154
  # Overrides the trace resource if it never been set
@@ -166,11 +167,17 @@ module Datadog
166
167
  Contrib::Analytics.set_measured(request_span)
167
168
 
168
169
  if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD).nil?
169
- request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, env['REQUEST_METHOD'])
170
+ request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, original_request_method)
170
171
  end
171
172
 
173
+ url = parse_url(env, original_env)
174
+
172
175
  if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_URL).nil?
173
- options = configuration[:quantize]
176
+ options = configuration[:quantize] || {}
177
+
178
+ # Quantization::HTTP.url base defaults to :show, but we are transitioning
179
+ options[:base] ||= :exclude
180
+
174
181
  request_span.set_tag(
175
182
  Tracing::Metadata::Ext::HTTP::TAG_URL,
176
183
  Contrib::Utils::Quantization::HTTP.url(url, options)
@@ -178,29 +185,43 @@ module Datadog
178
185
  end
179
186
 
180
187
  if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_BASE_URL).nil?
181
- request_obj = ::Rack::Request.new(env)
188
+ options = configuration[:quantize]
189
+
190
+ unless options[:base] == :show
191
+ base_url = Contrib::Utils::Quantization::HTTP.base_url(url)
182
192
 
183
- base_url = if request_obj.respond_to?(:base_url)
184
- request_obj.base_url
185
- else
186
- # Compatibility for older Rack versions
187
- request_obj.url.chomp(request_obj.fullpath)
188
- end
193
+ unless base_url.empty?
194
+ request_span.set_tag(
195
+ Tracing::Metadata::Ext::HTTP::TAG_BASE_URL,
196
+ base_url
197
+ )
198
+ end
199
+ end
200
+ end
189
201
 
190
- request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_BASE_URL, base_url)
202
+ if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
203
+ Tracing::ClientIp.set_client_ip_tag(
204
+ request_span,
205
+ headers: request_header_collection,
206
+ remote_ip: env['REMOTE_ADDR']
207
+ )
191
208
  end
192
209
 
193
210
  if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE).nil? && status
194
211
  request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, status)
195
212
  end
196
213
 
214
+ if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_USER_AGENT).nil? && user_agent
215
+ request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_USER_AGENT, user_agent)
216
+ end
217
+
197
218
  # Request headers
198
- request_headers.each do |name, value|
219
+ request_headers_tags.each do |name, value|
199
220
  request_span.set_tag(name, value) if request_span.get_tag(name).nil?
200
221
  end
201
222
 
202
223
  # Response headers
203
- response_headers.each do |name, value|
224
+ response_headers_tags.each do |name, value|
204
225
  request_span.set_tag(name, value) if request_span.get_tag(name).nil?
205
226
  end
206
227
 
@@ -219,14 +240,59 @@ module Datadog
219
240
  Datadog.configuration.tracing[:rack]
220
241
  end
221
242
 
222
- def parse_request_headers(env)
223
- {}.tap do |result|
224
- whitelist = configuration[:headers][:request] || []
225
- whitelist.each do |header|
226
- rack_header = header_to_rack_header(header)
227
- if env.key?(rack_header)
228
- result[Tracing::Metadata::Ext::HTTP::RequestHeaders.to_tag(header)] = env[rack_header]
229
- end
243
+ def parse_url(env, original_env)
244
+ request_obj = ::Rack::Request.new(env)
245
+
246
+ # scheme, host, and port
247
+ base_url = if request_obj.respond_to?(:base_url)
248
+ request_obj.base_url
249
+ else
250
+ # Compatibility for older Rack versions
251
+ request_obj.url.chomp(request_obj.fullpath)
252
+ end
253
+
254
+ # https://github.com/rack/rack/blob/main/SPEC.rdoc
255
+ #
256
+ # The source of truth in Rack is the PATH_INFO key that holds the
257
+ # URL for the current request; but some frameworks may override that
258
+ # value, especially during exception handling.
259
+ #
260
+ # Because of this, we prefer to use REQUEST_URI, if available, which is the
261
+ # relative path + query string, and doesn't mutate.
262
+ #
263
+ # REQUEST_URI is only available depending on what web server is running though.
264
+ # So when its not available, we want the original, unmutated PATH_INFO, which
265
+ # is just the relative path without query strings.
266
+ #
267
+ # SCRIPT_NAME is the first part of the request URL path, so that
268
+ # the application can know its virtual location. It should be
269
+ # prepended to PATH_INFO to reflect the correct user visible path.
270
+ request_uri = env['REQUEST_URI'].to_s
271
+ fullpath = if request_uri.empty?
272
+ query_string = original_env['QUERY_STRING'].to_s
273
+ path = original_env['SCRIPT_NAME'].to_s + original_env['PATH_INFO'].to_s
274
+
275
+ query_string.empty? ? path : "#{path}?#{query_string}"
276
+ else
277
+ # normally REQUEST_URI starts at the path, but it
278
+ # might contain the full URL in some cases (e.g WEBrick)
279
+ request_uri.sub(/^#{base_url}/, '')
280
+ end
281
+
282
+ base_url + fullpath
283
+ end
284
+
285
+ def parse_user_agent_header(headers)
286
+ headers.get(Tracing::Metadata::Ext::HTTP::HEADER_USER_AGENT)
287
+ end
288
+
289
+ def parse_request_headers(headers)
290
+ whitelist = configuration[:headers][:request] || []
291
+ whitelist.each_with_object({}) do |header, result|
292
+ header_value = headers.get(header)
293
+ unless header_value.nil?
294
+ header_tag = Tracing::Metadata::Ext::HTTP::RequestHeaders.to_tag(header)
295
+ result[header_tag] = header_value
230
296
  end
231
297
  end
232
298
  end
@@ -248,10 +314,6 @@ module Datadog
248
314
  end
249
315
  end
250
316
  end
251
-
252
- def header_to_rack_header(name)
253
- "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
254
- end
255
317
  end
256
318
  end
257
319
  end
@@ -19,6 +19,8 @@ module Datadog
19
19
  TYPE = 'redis'.freeze
20
20
  TAG_COMPONENT = 'redis'.freeze
21
21
  TAG_OPERATION_COMMAND = 'command'.freeze
22
+ TAG_SYSTEM = 'redis'.freeze
23
+ TAG_DATABASE_INDEX = 'db.redis.database_index'.freeze
22
24
  end
23
25
  end
24
26
  end
@@ -21,7 +21,8 @@ module Datadog
21
21
  def call(*args, &block)
22
22
  response = nil
23
23
  Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
24
- span.service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
24
+ span.service = Datadog.configuration_for(redis_instance, :service_name) ||
25
+ datadog_configuration[:service_name]
25
26
  span.span_type = Contrib::Redis::Ext::TYPE
26
27
  span.resource = get_command(args)
27
28
  Contrib::Redis::Tags.set_common_tags(self, span)
@@ -35,7 +36,8 @@ module Datadog
35
36
  def call_pipeline(*args, &block)
36
37
  response = nil
37
38
  Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
38
- span.service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
39
+ span.service = Datadog.configuration_for(redis_instance, :service_name) ||
40
+ datadog_configuration[:service_name]
39
41
  span.span_type = Contrib::Redis::Ext::TYPE
40
42
  commands = get_pipeline_commands(args)
41
43
  span.resource = commands.any? ? commands.join("\n") : '(none)'
@@ -13,6 +13,7 @@ module Datadog
13
13
  include Contrib::Integration
14
14
 
15
15
  MINIMUM_VERSION = Gem::Version.new('3.2')
16
+ MAX_VERSION = Gem::Version.new('5')
16
17
 
17
18
  # @public_api Changing the integration name or integration options can cause breaking changes
18
19
  register_as :redis, auto_patch: true
@@ -26,7 +27,7 @@ module Datadog
26
27
  end
27
28
 
28
29
  def self.compatible?
29
- super && version >= MINIMUM_VERSION
30
+ super && version >= MINIMUM_VERSION && version < MAX_VERSION
30
31
  end
31
32
 
32
33
  def new_configuration
@@ -12,6 +12,41 @@ module Datadog
12
12
  module Patcher
13
13
  include Contrib::Patcher
14
14
 
15
+ # Patch for redis instance
16
+ module InstancePatch
17
+ def self.included(base)
18
+ base.prepend(InstanceMethods)
19
+ end
20
+
21
+ # Instance method patch for redis instance
22
+ module InstanceMethods
23
+ # `options` could be frozen
24
+ def initialize(options = {})
25
+ super(options.merge(redis_instance: self))
26
+ end
27
+ end
28
+ end
29
+
30
+ # Patch for redis client
31
+ module ClientPatch
32
+ def self.included(base)
33
+ base.prepend(InstanceMethods)
34
+ end
35
+
36
+ # Instance method patch for redis client
37
+ module InstanceMethods
38
+ def initialize(options = {})
39
+ @redis_instance = options.delete(:redis_instance)
40
+
41
+ super(options)
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :redis_instance
47
+ end
48
+ end
49
+
15
50
  module_function
16
51
 
17
52
  def target_version
@@ -26,6 +61,11 @@ module Datadog
26
61
  require_relative 'quantize'
27
62
  require_relative 'instrumentation'
28
63
 
64
+ # InstancePatch and ClientPatch allows the client object to access pin on redis instance
65
+ ::Redis.include(InstancePatch)
66
+ ::Redis::Client.include(ClientPatch)
67
+
68
+ # TODO: To support redis-rb 5.x, Redis::Client -> RedisClient
29
69
  ::Redis::Client.include(Instrumentation)
30
70
  end
31
71
  end
@@ -3,6 +3,7 @@
3
3
  require_relative '../../metadata/ext'
4
4
  require_relative '../analytics'
5
5
  require_relative 'ext'
6
+ require_relative '../ext'
6
7
 
7
8
  module Datadog
8
9
  module Tracing
@@ -22,8 +23,12 @@ module Datadog
22
23
  # Set analytics sample rate
23
24
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
24
25
 
26
+ span.set_tag Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM
27
+
25
28
  span.set_tag Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, client.host
26
29
  span.set_tag Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, client.port
30
+
31
+ span.set_tag Ext::TAG_DATABASE_INDEX, client.db.to_s
27
32
  span.set_tag Ext::TAG_DB, client.db
28
33
  span.set_tag Ext::TAG_RAW_COMMAND, span.resource if show_command_args?
29
34
  end
@@ -34,6 +34,8 @@ module Datadog
34
34
  def datadog_tag_request(uri, span)
35
35
  span.resource = method.to_s.upcase
36
36
 
37
+ span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
38
+
37
39
  span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
38
40
  span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_REQUEST)
39
41
 
@@ -13,14 +13,12 @@ module Datadog
13
13
  module Env
14
14
  module_function
15
15
 
16
- def datadog_span(env, app)
17
- request_span = env[Ext::RACK_ENV_REQUEST_SPAN]
18
- request_span && request_span[app]
16
+ def datadog_span(env)
17
+ env[Ext::RACK_ENV_SINATRA_REQUEST_SPAN]
19
18
  end
20
19
 
21
- def set_datadog_span(env, app, span)
22
- hash = (env[Ext::RACK_ENV_REQUEST_SPAN] ||= {})
23
- hash[app] = span
20
+ def set_datadog_span(env, span)
21
+ env[Ext::RACK_ENV_SINATRA_REQUEST_SPAN] = span
24
22
  end
25
23
 
26
24
  def request_header_tags(env, headers)
@@ -40,24 +38,15 @@ module Datadog
40
38
  "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
41
39
  end
42
40
 
43
- # Was a Sinatra already traced in this request?
44
- # We don't want to create spans for intermediate Sinatra
45
- # middlewares that don't match the request at hand.
46
- def middleware_traced?(env)
47
- env[Ext::RACK_ENV_MIDDLEWARE_TRACED]
48
- end
49
-
50
- def set_middleware_traced(env, bool)
51
- env[Ext::RACK_ENV_MIDDLEWARE_TRACED] = bool
52
- end
41
+ def route_path(env, use_script_names: Datadog.configuration.tracing[:sinatra][:resource_script_names])
42
+ return unless env['sinatra.route']
53
43
 
54
- # The start time of the top-most Sinatra middleware.
55
- def middleware_start_time(env)
56
- env[Ext::RACK_ENV_MIDDLEWARE_START_TIME]
57
- end
58
-
59
- def set_middleware_start_time(env, time = Time.now.utc)
60
- env[Ext::RACK_ENV_MIDDLEWARE_START_TIME] = time
44
+ _, path = env['sinatra.route'].split(' ', 2)
45
+ if use_script_names
46
+ env['SCRIPT_NAME'].to_s + path
47
+ else
48
+ path
49
+ end
61
50
  end
62
51
  end
63
52
  end
@@ -10,9 +10,7 @@ module Datadog
10
10
  ENV_ENABLED = 'DD_TRACE_SINATRA_ENABLED'.freeze
11
11
  ENV_ANALYTICS_ENABLED = 'DD_TRACE_SINATRA_ANALYTICS_ENABLED'.freeze
12
12
  ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_SINATRA_ANALYTICS_SAMPLE_RATE'.freeze
13
- RACK_ENV_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
14
- RACK_ENV_MIDDLEWARE_START_TIME = 'datadog.sinatra_middleware_start_time'.freeze
15
- RACK_ENV_MIDDLEWARE_TRACED = 'datadog.sinatra_middleware_traced'.freeze
13
+ RACK_ENV_SINATRA_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
16
14
  SPAN_RENDER_TEMPLATE = 'sinatra.render_template'.freeze
17
15
  SPAN_REQUEST = 'sinatra.request'.freeze
18
16
  SPAN_ROUTE = 'sinatra.route'.freeze
@@ -25,6 +23,12 @@ module Datadog
25
23
  TAG_SCRIPT_NAME = 'sinatra.script_name'.freeze
26
24
  TAG_TEMPLATE_ENGINE = 'sinatra.template_engine'.freeze
27
25
  TAG_TEMPLATE_NAME = 'sinatra.template_name'.freeze
26
+
27
+ # === Deprecated: To be removed ===
28
+ RACK_ENV_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
29
+ RACK_ENV_MIDDLEWARE_START_TIME = 'datadog.sinatra_middleware_start_time'.freeze
30
+ RACK_ENV_MIDDLEWARE_TRACED = 'datadog.sinatra_middleware_traced'.freeze
31
+ # === Deprecated: To be removed ===
28
32
  end
29
33
  end
30
34
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: false
2
2
 
3
3
  require_relative '../../../core/utils/only_once'
4
4
  require_relative '../patcher'
@@ -58,7 +58,7 @@ module Datadog
58
58
  end
59
59
 
60
60
  def register_tracer
61
- ::Sinatra.send(:register, Contrib::Sinatra::Tracer)
61
+ ::Sinatra::Base.register(Contrib::Sinatra::Tracer)
62
62
  ::Sinatra::Base.prepend(Sinatra::Tracer::Base)
63
63
  end
64
64