ddtrace 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -2
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +0 -2
- data/lib/datadog/appsec/configuration/settings.rb +0 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +0 -2
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/ci/ext/environment.rb +16 -4
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +0 -3
- data/lib/datadog/core/configuration/components.rb +8 -2
- data/lib/datadog/core/configuration/settings.rb +69 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/header_collection.rb +41 -0
- data/lib/datadog/core/telemetry/collector.rb +0 -2
- data/lib/datadog/core/workers/async.rb +0 -2
- data/lib/datadog/profiling/collectors/old_stack.rb +1 -1
- data/lib/datadog/profiling.rb +1 -1
- data/lib/datadog/tracing/client_ip.rb +153 -0
- data/lib/datadog/tracing/configuration/ext.rb +12 -0
- data/lib/datadog/tracing/contrib/aws/services.rb +0 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +0 -2
- data/lib/datadog/tracing/contrib/ext.rb +19 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +1 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +0 -2
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +5 -4
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +35 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +92 -38
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +83 -9
- data/lib/datadog/tracing/flush.rb +57 -35
- data/lib/datadog/tracing/metadata/ext.rb +3 -9
- data/lib/datadog/tracing/metadata/tagging.rb +9 -0
- data/lib/datadog/tracing/sampling/rate_limiter.rb +3 -0
- data/lib/datadog/tracing/sampling/rate_sampler.rb +10 -0
- data/lib/datadog/tracing/sampling/span/ext.rb +29 -0
- data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
- data/lib/datadog/tracing/sampling/span/sampler.rb +64 -0
- data/lib/datadog/tracing/span_operation.rb +0 -2
- data/lib/datadog/tracing/trace_operation.rb +22 -3
- data/lib/datadog/tracing/trace_segment.rb +1 -2
- data/lib/datadog/tracing/tracer.rb +31 -5
- data/lib/ddtrace/version.rb +2 -2
- metadata +19 -5
@@ -3,7 +3,6 @@
|
|
3
3
|
module Datadog
|
4
4
|
module Tracing
|
5
5
|
module Contrib
|
6
|
-
# rubocop:disable Metrics/ModuleLength:
|
7
6
|
module Aws
|
8
7
|
SERVICES = %w[
|
9
8
|
ACM
|
@@ -117,7 +116,6 @@ module Datadog
|
|
117
116
|
XRay
|
118
117
|
].freeze
|
119
118
|
end
|
120
|
-
# rubocop:enable Metrics/ModuleLength:
|
121
119
|
end
|
122
120
|
end
|
123
121
|
end
|
@@ -18,7 +18,6 @@ module Datadog
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# InstanceMethods - implementing instrumentation
|
21
|
-
# rubocop:disable Metrics/ModuleLength
|
22
21
|
module InstanceMethods
|
23
22
|
include Contrib::HttpAnnotationHelper
|
24
23
|
|
@@ -168,7 +167,6 @@ module Datadog
|
|
168
167
|
datadog_configuration[:analytics_sample_rate]
|
169
168
|
end
|
170
169
|
end
|
171
|
-
# rubocop:enable Metrics/ModuleLength
|
172
170
|
end
|
173
171
|
end
|
174
172
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
# Contrib specific constants
|
7
|
+
module Ext
|
8
|
+
# @public_api
|
9
|
+
module DB
|
10
|
+
TAG_INSTANCE = 'db.instance'
|
11
|
+
TAG_USER = 'db.user'
|
12
|
+
TAG_SYSTEM = 'db.system'
|
13
|
+
TAG_STATEMENT = 'db.statement'
|
14
|
+
TAG_ROW_COUNT = 'db.row_count'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -39,8 +39,7 @@ module Datadog
|
|
39
39
|
|
40
40
|
def annotate!(span, env, options)
|
41
41
|
span.resource = resource_name(env)
|
42
|
-
service_name(env[:url].host, options)
|
43
|
-
span.service = options[:split_by_domain] ? env[:url].host : options[:service_name]
|
42
|
+
span.service = service_name(env[:url].host, options)
|
44
43
|
span.span_type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
45
44
|
|
46
45
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
@@ -9,7 +9,6 @@ module Datadog
|
|
9
9
|
module Tracing
|
10
10
|
module Contrib
|
11
11
|
module Grape
|
12
|
-
# rubocop:disable Metrics/ModuleLength
|
13
12
|
# Endpoint module includes a list of subscribers to create
|
14
13
|
# traces when a Grape endpoint is hit
|
15
14
|
module Endpoint
|
@@ -245,7 +244,6 @@ module Datadog
|
|
245
244
|
end
|
246
245
|
end
|
247
246
|
end
|
248
|
-
# rubocop:enable Metrics/ModuleLength
|
249
247
|
end
|
250
248
|
end
|
251
249
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../metadata/ext'
|
4
4
|
require_relative '../analytics'
|
5
|
+
require_relative '../ext'
|
5
6
|
require_relative 'ext'
|
6
7
|
|
7
8
|
module Datadog
|
@@ -95,9 +96,9 @@ module Datadog
|
|
95
96
|
span.set_tag(Tracing::Metadata::Ext::TAG_PEER_SERVICE, service)
|
96
97
|
span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host)
|
97
98
|
|
98
|
-
span.set_tag(
|
99
|
-
span.set_tag(
|
100
|
-
span.set_tag(
|
99
|
+
span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, db)
|
100
|
+
span.set_tag(Contrib::Ext::DB::TAG_USER, user)
|
101
|
+
span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::SPAN_SYSTEM)
|
101
102
|
|
102
103
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host)
|
103
104
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port)
|
@@ -106,7 +107,7 @@ module Datadog
|
|
106
107
|
end
|
107
108
|
|
108
109
|
def annotate_span_with_result!(span, result)
|
109
|
-
span.set_tag(
|
110
|
+
span.set_tag(Contrib::Ext::DB::TAG_ROW_COUNT, result.ntuples)
|
110
111
|
end
|
111
112
|
|
112
113
|
def datadog_configuration
|
@@ -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
|
@@ -121,20 +123,13 @@ module Datadog
|
|
121
123
|
# rubocop:disable Metrics/PerceivedComplexity
|
122
124
|
# rubocop:disable Metrics/MethodLength
|
123
125
|
def set_request_tags!(trace, request_span, env, status, headers, response, original_env)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
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 || {})
|
126
|
+
request_header_collection = Header::RequestHeaderCollection.new(env)
|
127
|
+
request_headers_tags = parse_request_headers(request_header_collection)
|
128
|
+
response_headers_tags = parse_response_headers(headers || {})
|
129
|
+
|
130
|
+
# request_headers is subject to filtering and configuration so we
|
131
|
+
# get the user agent separately
|
132
|
+
user_agent = parse_user_agent_header(request_header_collection)
|
138
133
|
|
139
134
|
# The priority
|
140
135
|
# 1. User overrides span.resource
|
@@ -169,8 +164,14 @@ module Datadog
|
|
169
164
|
request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, env['REQUEST_METHOD'])
|
170
165
|
end
|
171
166
|
|
167
|
+
url = parse_url(env, original_env)
|
168
|
+
|
172
169
|
if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_URL).nil?
|
173
|
-
options = configuration[:quantize]
|
170
|
+
options = configuration[:quantize] || {}
|
171
|
+
|
172
|
+
# Quantization::HTTP.url base defaults to :show, but we are transitioning
|
173
|
+
options[:base] ||= :exclude
|
174
|
+
|
174
175
|
request_span.set_tag(
|
175
176
|
Tracing::Metadata::Ext::HTTP::TAG_URL,
|
176
177
|
Contrib::Utils::Quantization::HTTP.url(url, options)
|
@@ -178,29 +179,43 @@ module Datadog
|
|
178
179
|
end
|
179
180
|
|
180
181
|
if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_BASE_URL).nil?
|
181
|
-
|
182
|
+
options = configuration[:quantize]
|
182
183
|
|
183
|
-
|
184
|
-
|
185
|
-
else
|
186
|
-
# Compatibility for older Rack versions
|
187
|
-
request_obj.url.chomp(request_obj.fullpath)
|
188
|
-
end
|
184
|
+
unless options[:base] == :show
|
185
|
+
base_url = Contrib::Utils::Quantization::HTTP.base_url(url)
|
189
186
|
|
190
|
-
|
187
|
+
unless base_url.empty?
|
188
|
+
request_span.set_tag(
|
189
|
+
Tracing::Metadata::Ext::HTTP::TAG_BASE_URL,
|
190
|
+
base_url
|
191
|
+
)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
|
197
|
+
Tracing::ClientIp.set_client_ip_tag(
|
198
|
+
request_span,
|
199
|
+
headers: request_header_collection,
|
200
|
+
remote_ip: env['REMOTE_ADDR']
|
201
|
+
)
|
191
202
|
end
|
192
203
|
|
193
204
|
if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE).nil? && status
|
194
205
|
request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE, status)
|
195
206
|
end
|
196
207
|
|
208
|
+
if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_USER_AGENT).nil? && user_agent
|
209
|
+
request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_USER_AGENT, user_agent)
|
210
|
+
end
|
211
|
+
|
197
212
|
# Request headers
|
198
|
-
|
213
|
+
request_headers_tags.each do |name, value|
|
199
214
|
request_span.set_tag(name, value) if request_span.get_tag(name).nil?
|
200
215
|
end
|
201
216
|
|
202
217
|
# Response headers
|
203
|
-
|
218
|
+
response_headers_tags.each do |name, value|
|
204
219
|
request_span.set_tag(name, value) if request_span.get_tag(name).nil?
|
205
220
|
end
|
206
221
|
|
@@ -219,14 +234,57 @@ module Datadog
|
|
219
234
|
Datadog.configuration.tracing[:rack]
|
220
235
|
end
|
221
236
|
|
222
|
-
def
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
237
|
+
def parse_url(env, original_env)
|
238
|
+
request_obj = ::Rack::Request.new(env)
|
239
|
+
|
240
|
+
# scheme, host, and port
|
241
|
+
base_url = if request_obj.respond_to?(:base_url)
|
242
|
+
request_obj.base_url
|
243
|
+
else
|
244
|
+
# Compatibility for older Rack versions
|
245
|
+
request_obj.url.chomp(request_obj.fullpath)
|
246
|
+
end
|
247
|
+
|
248
|
+
# https://github.com/rack/rack/blob/main/SPEC.rdoc
|
249
|
+
#
|
250
|
+
# The source of truth in Rack is the PATH_INFO key that holds the
|
251
|
+
# URL for the current request; but some frameworks may override that
|
252
|
+
# value, especially during exception handling.
|
253
|
+
#
|
254
|
+
# Because of this, we prefer to use REQUEST_URI, if available, which is the
|
255
|
+
# relative path + query string, and doesn't mutate.
|
256
|
+
#
|
257
|
+
# REQUEST_URI is only available depending on what web server is running though.
|
258
|
+
# So when its not available, we want the original, unmutated PATH_INFO, which
|
259
|
+
# is just the relative path without query strings.
|
260
|
+
#
|
261
|
+
# SCRIPT_NAME is the first part of the request URL path, so that
|
262
|
+
# the application can know its virtual location. It should be
|
263
|
+
# prepended to PATH_INFO to reflect the correct user visible path.
|
264
|
+
request_uri = env['REQUEST_URI'].to_s
|
265
|
+
fullpath = if request_uri.empty?
|
266
|
+
query_string = original_env['QUERY_STRING'].to_s
|
267
|
+
path = original_env['SCRIPT_NAME'].to_s + original_env['PATH_INFO'].to_s
|
268
|
+
|
269
|
+
query_string.empty? ? path : "#{path}?#{query_string}"
|
270
|
+
else
|
271
|
+
request_uri
|
272
|
+
end
|
273
|
+
|
274
|
+
base_url + fullpath
|
275
|
+
end
|
276
|
+
|
277
|
+
def parse_user_agent_header(headers)
|
278
|
+
headers.get(Tracing::Metadata::Ext::HTTP::HEADER_USER_AGENT)
|
279
|
+
end
|
280
|
+
|
281
|
+
def parse_request_headers(headers)
|
282
|
+
whitelist = configuration[:headers][:request] || []
|
283
|
+
whitelist.each_with_object({}) do |header, result|
|
284
|
+
header_value = headers.get(header)
|
285
|
+
unless header_value.nil?
|
286
|
+
header_tag = Tracing::Metadata::Ext::HTTP::RequestHeaders.to_tag(header)
|
287
|
+
result[header_tag] = header_value
|
230
288
|
end
|
231
289
|
end
|
232
290
|
end
|
@@ -248,10 +306,6 @@ module Datadog
|
|
248
306
|
end
|
249
307
|
end
|
250
308
|
end
|
251
|
-
|
252
|
-
def header_to_rack_header(name)
|
253
|
-
"HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
|
254
|
-
end
|
255
309
|
end
|
256
310
|
end
|
257
311
|
end
|
@@ -22,6 +22,14 @@ module Datadog
|
|
22
22
|
options[:placeholder] || PLACEHOLDER
|
23
23
|
end
|
24
24
|
|
25
|
+
def base_url(url, options = {})
|
26
|
+
URI.parse(url).tap do |uri|
|
27
|
+
uri.path = ''
|
28
|
+
uri.query = nil
|
29
|
+
uri.fragment = nil
|
30
|
+
end.to_s
|
31
|
+
end
|
32
|
+
|
25
33
|
def url!(url, options = {})
|
26
34
|
options ||= {}
|
27
35
|
|
@@ -32,8 +40,14 @@ module Datadog
|
|
32
40
|
uri.query = (!query.nil? && query.empty? ? nil : query)
|
33
41
|
end
|
34
42
|
|
35
|
-
# Remove any URI
|
43
|
+
# Remove any URI fragments
|
36
44
|
uri.fragment = nil unless options[:fragment] == :show
|
45
|
+
|
46
|
+
if options[:base] == :exclude
|
47
|
+
uri.host = nil
|
48
|
+
uri.port = nil
|
49
|
+
uri.scheme = nil
|
50
|
+
end
|
37
51
|
end.to_s
|
38
52
|
end
|
39
53
|
|
@@ -45,22 +59,26 @@ module Datadog
|
|
45
59
|
|
46
60
|
def query!(query, options = {})
|
47
61
|
options ||= {}
|
48
|
-
options[:
|
62
|
+
options[:obfuscate] = {} if options[:obfuscate] == :internal
|
63
|
+
options[:show] = options[:show] || (options[:obfuscate] ? :all : [])
|
49
64
|
options[:exclude] = options[:exclude] || []
|
50
65
|
|
51
66
|
# Short circuit if query string is meant to exclude everything
|
52
67
|
# or if the query string is meant to include everything
|
53
68
|
return '' if options[:exclude] == :all
|
54
|
-
return query if options[:show] == :all
|
55
69
|
|
56
|
-
|
57
|
-
|
58
|
-
[
|
59
|
-
|
60
|
-
|
61
|
-
|
70
|
+
unless options[:show] == :all && !(options[:obfuscate] && options[:exclude])
|
71
|
+
query = collect_query(query, uniq: true) do |key, value|
|
72
|
+
if options[:exclude].include?(key)
|
73
|
+
[nil, nil]
|
74
|
+
else
|
75
|
+
value = options[:show] == :all || options[:show].include?(key) ? value : nil
|
76
|
+
[key, value]
|
77
|
+
end
|
62
78
|
end
|
63
79
|
end
|
80
|
+
|
81
|
+
options[:obfuscate] ? obfuscate_query(query, options[:obfuscate]) : query
|
64
82
|
end
|
65
83
|
|
66
84
|
# Iterate over each key value pair, yielding to the block given.
|
@@ -91,6 +109,62 @@ module Datadog
|
|
91
109
|
end
|
92
110
|
|
93
111
|
private_class_method :collect_query
|
112
|
+
|
113
|
+
# Scans over the query string and obfuscates sensitive data by
|
114
|
+
# replacing matches with an opaque value
|
115
|
+
def obfuscate_query(query, options = {})
|
116
|
+
options[:regex] = nil if options[:regex] == :internal
|
117
|
+
re = options[:regex] || OBFUSCATOR_REGEX
|
118
|
+
with = options[:with] || OBFUSCATOR_WITH
|
119
|
+
|
120
|
+
query.gsub(re, with)
|
121
|
+
end
|
122
|
+
|
123
|
+
private_class_method :obfuscate_query
|
124
|
+
|
125
|
+
OBFUSCATOR_WITH = '<redacted>'.freeze
|
126
|
+
|
127
|
+
# rubocop:disable Layout/LineLength
|
128
|
+
OBFUSCATOR_REGEX = %r{
|
129
|
+
(?: # JSON-ish leading quote
|
130
|
+
(?:"|%22)?
|
131
|
+
)
|
132
|
+
(?: # common keys
|
133
|
+
(?:old_?|new_?)?p(?:ass)?w(?:or)?d(?:1|2)? # pw, password variants
|
134
|
+
|pass(?:_?phrase)? # pass, passphrase variants
|
135
|
+
|secret
|
136
|
+
|(?: # key, key_id variants
|
137
|
+
api_?
|
138
|
+
|private_?
|
139
|
+
|public_?
|
140
|
+
|access_?
|
141
|
+
|secret_?
|
142
|
+
)key(?:_?id)?
|
143
|
+
|token
|
144
|
+
|consumer_?(?:id|key|secret)
|
145
|
+
|sign(?:ed|ature)?
|
146
|
+
|auth(?:entication|orization)?
|
147
|
+
)
|
148
|
+
(?:
|
149
|
+
# '=' query string separator, plus value til next '&' separator
|
150
|
+
(?:\s|%20)*(?:=|%3D)[^&]+
|
151
|
+
# JSON-ish '": "somevalue"', key being handled with case above, without the opening '"'
|
152
|
+
|(?:"|%22) # closing '"' at end of key
|
153
|
+
(?:\s|%20)*(?::|%3A)(?:\s|%20)* # ':' key-value spearator, with surrounding spaces
|
154
|
+
(?:"|%22) # opening '"' at start of value
|
155
|
+
(?:%2[^2]|%[^2]|[^"%])+ # value
|
156
|
+
(?:"|%22) # closing '"' at end of value
|
157
|
+
)
|
158
|
+
|(?: # other common secret values
|
159
|
+
bearer(?:\s|%20)+[a-z0-9._\-]+
|
160
|
+
|token(?::|%3A)[a-z0-9]{13}
|
161
|
+
|gh[opsu]_[0-9a-zA-Z]{36}
|
162
|
+
|ey[I-L](?:[\w=-]|%3D)+\.ey[I-L](?:[\w=-]|%3D)+(?:\.(?:[\w.+/=-]|%3D|%2F|%2B)+)?
|
163
|
+
|-{5}BEGIN(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY-{5}[^\-]+-{5}END(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY(?:-{5})?(?:\n|%0A)?
|
164
|
+
|(?:ssh-(?:rsa|dss)|ecdsa-[a-z0-9]+-[a-z0-9]+)(?:\s|%20)*(?:[a-z0-9/.+]|%2F|%5C|%2B){100,}(?:=|%3D)*(?:(?:\s+)[a-z0-9._-]+)?
|
165
|
+
)
|
166
|
+
}ix.freeze
|
167
|
+
# rubocop:enable Layout/LineLength
|
94
168
|
end
|
95
169
|
end
|
96
170
|
end
|
@@ -3,71 +3,93 @@
|
|
3
3
|
module Datadog
|
4
4
|
module Tracing
|
5
5
|
module Flush
|
6
|
-
# Consumes
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
# Consumes and returns a {TraceSegment} to be flushed, from
|
7
|
+
# the provided {TraceSegment}.
|
8
|
+
#
|
9
|
+
# Only finished spans are consumed. Any spans consumed are
|
10
|
+
# removed from +trace_op+ as a side effect. Unfinished spans are
|
11
|
+
# unaffected.
|
12
|
+
#
|
13
|
+
# @abstract
|
14
|
+
class Base
|
15
|
+
# Consumes and returns a {TraceSegment} to be flushed, from
|
16
|
+
# the provided {TraceSegment}.
|
10
17
|
#
|
11
|
-
#
|
18
|
+
# Only finished spans are consumed. Any spans consumed are
|
19
|
+
# removed from +trace_op+ as a side effect. Unfinished spans are
|
20
|
+
# unaffected.
|
12
21
|
#
|
22
|
+
# @param [TraceOperation] trace_op
|
13
23
|
# @return [TraceSegment] trace to be flushed, or +nil+ if the trace is not finished
|
14
24
|
def consume!(trace_op)
|
15
|
-
return unless
|
25
|
+
return unless flush?(trace_op)
|
16
26
|
|
17
27
|
get_trace(trace_op)
|
18
28
|
end
|
19
29
|
|
20
|
-
|
21
|
-
|
30
|
+
# Should we consume spans from the +trace_op+?
|
31
|
+
# @abstract
|
32
|
+
def flush?(trace_op)
|
33
|
+
raise NotImplementedError
|
22
34
|
end
|
23
35
|
|
24
36
|
protected
|
25
37
|
|
38
|
+
# Consumes all finished spans from trace.
|
39
|
+
# @return [TraceSegment]
|
26
40
|
def get_trace(trace_op)
|
27
|
-
trace_op.flush!
|
41
|
+
trace_op.flush! do |spans|
|
42
|
+
spans.select! { |span| single_sampled?(span) } unless trace_op.sampled?
|
43
|
+
|
44
|
+
spans
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Single Span Sampling has chosen to keep this span
|
49
|
+
# regardless of the trace-level sampling decision
|
50
|
+
def single_sampled?(span)
|
51
|
+
span.get_metric(Sampling::Span::Ext::TAG_MECHANISM) == Sampling::Span::Ext::MECHANISM_SPAN_SAMPLING_RATE
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Consumes and returns completed traces (where all spans have finished),
|
56
|
+
# if any, from the provided +trace_op+.
|
57
|
+
#
|
58
|
+
# Spans consumed are removed from +trace_op+ as a side effect.
|
59
|
+
class Finished < Base
|
60
|
+
# Are all spans finished?
|
61
|
+
def flush?(trace_op)
|
62
|
+
trace_op && trace_op.finished?
|
28
63
|
end
|
29
64
|
end
|
30
65
|
|
31
|
-
#
|
32
|
-
|
66
|
+
# Consumes and returns completed or partially completed
|
67
|
+
# traces from the provided +trace_op+, if any.
|
68
|
+
#
|
69
|
+
# Partial trace flushing avoids large traces residing in memory for too long.
|
70
|
+
#
|
71
|
+
# Partially completed traces, where not all spans have finished,
|
72
|
+
# will only be returned if there are at least
|
73
|
+
# +@min_spans_for_partial+ finished spans.
|
74
|
+
#
|
75
|
+
# Spans consumed are removed from +trace_op+ as a side effect.
|
76
|
+
class Partial < Base
|
33
77
|
# Start flushing partial trace after this many active spans in one trace
|
34
78
|
DEFAULT_MIN_SPANS_FOR_PARTIAL_FLUSH = 500
|
35
79
|
|
36
80
|
attr_reader :min_spans_for_partial
|
37
81
|
|
38
82
|
def initialize(options = {})
|
83
|
+
super()
|
39
84
|
@min_spans_for_partial = options.fetch(:min_spans_before_partial_flush, DEFAULT_MIN_SPANS_FOR_PARTIAL_FLUSH)
|
40
85
|
end
|
41
86
|
|
42
|
-
|
43
|
-
# traces from the provided +trace_op+, if any.
|
44
|
-
#
|
45
|
-
# Partially completed traces, where not all spans have finished,
|
46
|
-
# will only be returned if there are at least
|
47
|
-
# +@min_spans_for_partial+ finished spans.
|
48
|
-
#
|
49
|
-
# Any spans consumed are removed from +trace_op+ as a side effect.
|
50
|
-
#
|
51
|
-
# @return [TraceSegment] partial or complete trace to be flushed, or +nil+ if no spans are finished
|
52
|
-
def consume!(trace_op)
|
53
|
-
return unless partial_flush?(trace_op)
|
54
|
-
|
55
|
-
get_trace(trace_op)
|
56
|
-
end
|
57
|
-
|
58
|
-
def partial_flush?(trace_op)
|
59
|
-
return false unless trace_op.sampled?
|
87
|
+
def flush?(trace_op)
|
60
88
|
return true if trace_op.finished?
|
61
89
|
return false if trace_op.finished_span_count < @min_spans_for_partial
|
62
90
|
|
63
91
|
true
|
64
92
|
end
|
65
|
-
|
66
|
-
protected
|
67
|
-
|
68
|
-
def get_trace(trace_op)
|
69
|
-
trace_op.flush!
|
70
|
-
end
|
71
93
|
end
|
72
94
|
end
|
73
95
|
end
|
@@ -63,11 +63,14 @@ module Datadog
|
|
63
63
|
TAG_BASE_URL = 'http.base_url'
|
64
64
|
TAG_METHOD = 'http.method'
|
65
65
|
TAG_STATUS_CODE = 'http.status_code'
|
66
|
+
TAG_USER_AGENT = 'http.useragent'
|
66
67
|
TAG_URL = 'http.url'
|
67
68
|
TYPE_INBOUND = AppTypes::TYPE_WEB.freeze
|
68
69
|
TYPE_OUTBOUND = 'http'
|
69
70
|
TYPE_PROXY = 'proxy'
|
70
71
|
TYPE_TEMPLATE = 'template'
|
72
|
+
TAG_CLIENT_IP = 'http.client_ip'
|
73
|
+
HEADER_USER_AGENT = 'User-Agent'
|
71
74
|
|
72
75
|
# General header functionality
|
73
76
|
module Headers
|
@@ -153,15 +156,6 @@ module Datadog
|
|
153
156
|
TAG_QUERY = 'sql.query'
|
154
157
|
end
|
155
158
|
|
156
|
-
# @public_api
|
157
|
-
module DB
|
158
|
-
TAG_INSTANCE = 'db.instance'
|
159
|
-
TAG_USER = 'db.user'
|
160
|
-
TAG_SYSTEM = 'db.system'
|
161
|
-
TAG_STATEMENT = 'db.statement'
|
162
|
-
TAG_ROW_COUNT = 'db.row_count'
|
163
|
-
end
|
164
|
-
|
165
159
|
# @public_api
|
166
160
|
module SpanKind
|
167
161
|
TAG_SERVER = 'server'
|
@@ -65,6 +65,15 @@ module Datadog
|
|
65
65
|
tags.each { |k, v| set_tag(k, v) }
|
66
66
|
end
|
67
67
|
|
68
|
+
# Returns true if the provided `tag` was set to a non-nil value.
|
69
|
+
# False otherwise.
|
70
|
+
#
|
71
|
+
# @param [String] tag the tag or metric to check for presence
|
72
|
+
# @return [Boolean] if the tag is present and not nil
|
73
|
+
def has_tag?(tag) # rubocop:disable Naming/PredicateName
|
74
|
+
!get_tag(tag).nil? # nil is considered not present, thus we can't use `Hash#has_key?`
|
75
|
+
end
|
76
|
+
|
68
77
|
# This method removes a tag for the given key.
|
69
78
|
def clear_tag(key)
|
70
79
|
meta.delete(key)
|
@@ -39,6 +39,9 @@ module Datadog
|
|
39
39
|
def initialize(rate, max_tokens = rate)
|
40
40
|
super()
|
41
41
|
|
42
|
+
raise ArgumentError, "rate must be a number: #{rate}" unless rate.is_a?(Numeric)
|
43
|
+
raise ArgumentError, "max_tokens must be a number: #{max_tokens}" unless max_tokens.is_a?(Numeric)
|
44
|
+
|
42
45
|
@rate = rate
|
43
46
|
@max_tokens = max_tokens
|
44
47
|
|