ddtrace 0.15.0.beta1 → 0.15.0.internaltracinfeature1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/Appraisals +14 -8
- data/CHANGELOG.md +39 -6
- data/Rakefile +7 -0
- data/docs/GettingStarted.md +63 -26
- data/lib/ddtrace.rb +14 -13
- data/lib/ddtrace/buffer.rb +20 -8
- data/lib/ddtrace/context.rb +104 -60
- data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +13 -0
- data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +35 -0
- data/lib/ddtrace/contrib/concurrent_ruby/future_patch.rb +23 -0
- data/lib/ddtrace/contrib/concurrent_ruby/integration.rb +28 -0
- data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +34 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +1 -0
- data/lib/ddtrace/contrib/graphql/patcher.rb +10 -2
- data/lib/ddtrace/contrib/http/patcher.rb +20 -7
- data/lib/ddtrace/propagation/distributed_headers.rb +8 -6
- data/lib/ddtrace/registry.rb +4 -2
- data/lib/ddtrace/sampler.rb +24 -6
- data/lib/ddtrace/tracer.rb +4 -1
- data/lib/ddtrace/transport.rb +105 -33
- data/lib/ddtrace/utils.rb +1 -0
- data/lib/ddtrace/utils/internal_traces.rb +53 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +9 -3
@@ -16,15 +16,11 @@ module Datadog
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def trace_id
|
19
|
-
|
20
|
-
return if value <= 0 || value >= Span::MAX_ID
|
21
|
-
value
|
19
|
+
id HTTP_HEADER_TRACE_ID
|
22
20
|
end
|
23
21
|
|
24
22
|
def parent_id
|
25
|
-
|
26
|
-
return if value <= 0 || value >= Span::MAX_ID
|
27
|
-
value
|
23
|
+
id HTTP_HEADER_PARENT_ID
|
28
24
|
end
|
29
25
|
|
30
26
|
def sampling_priority
|
@@ -44,5 +40,11 @@ module Datadog
|
|
44
40
|
|
45
41
|
@env[rack_header]
|
46
42
|
end
|
43
|
+
|
44
|
+
def id(header)
|
45
|
+
value = header(header).to_i
|
46
|
+
return if value.zero? || value >= Span::MAX_ID
|
47
|
+
value < 0 ? value + 0x1_0000_0000_0000_0000 : value
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
data/lib/ddtrace/registry.rb
CHANGED
data/lib/ddtrace/sampler.rb
CHANGED
@@ -98,14 +98,32 @@ module Datadog
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def sample(span)
|
101
|
-
span
|
102
|
-
return
|
103
|
-
|
104
|
-
span.
|
105
|
-
|
106
|
-
|
101
|
+
return perform_sampling(span) unless span.context
|
102
|
+
return sampled_by_upstream(span) if span.context.sampling_priority
|
103
|
+
|
104
|
+
perform_sampling(span).tap do |sampled|
|
105
|
+
span.context.sampling_priority = if sampled
|
106
|
+
Datadog::Ext::Priority::AUTO_KEEP
|
107
|
+
else
|
108
|
+
Datadog::Ext::Priority::AUTO_REJECT
|
109
|
+
end
|
110
|
+
end
|
107
111
|
end
|
108
112
|
|
109
113
|
def_delegators :@post_sampler, :update
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def sampled_by_upstream(span)
|
118
|
+
span.sampled = priority_keep?(span.context.sampling_priority)
|
119
|
+
end
|
120
|
+
|
121
|
+
def priority_keep?(sampling_priority)
|
122
|
+
sampling_priority == Datadog::Ext::Priority::USER_KEEP || sampling_priority == Datadog::Ext::Priority::AUTO_KEEP
|
123
|
+
end
|
124
|
+
|
125
|
+
def perform_sampling(span)
|
126
|
+
@base_sampler.sample(span) && @post_sampler.sample(span)
|
127
|
+
end
|
110
128
|
end
|
111
129
|
end
|
data/lib/ddtrace/tracer.rb
CHANGED
@@ -20,7 +20,7 @@ module Datadog
|
|
20
20
|
# rubocop:disable Metrics/ClassLength
|
21
21
|
class Tracer
|
22
22
|
attr_reader :sampler, :services, :tags, :provider
|
23
|
-
attr_accessor :enabled, :writer
|
23
|
+
attr_accessor :enabled, :writer, :internal_traces
|
24
24
|
attr_writer :default_service
|
25
25
|
|
26
26
|
ALLOWED_SPAN_OPTIONS = [:service, :resource, :span_type].freeze
|
@@ -102,7 +102,9 @@ module Datadog
|
|
102
102
|
@provider ||= Datadog::DefaultContextProvider.new # @provider should never be nil
|
103
103
|
|
104
104
|
@context_flush = options[:partial_flush] ? Datadog::ContextFlush.new(options) : nil
|
105
|
+
@internal_traces = options[:internal_traces] || false
|
105
106
|
|
107
|
+
@mutex = Mutex.new
|
106
108
|
@services = {}
|
107
109
|
@tags = {}
|
108
110
|
end
|
@@ -122,6 +124,7 @@ module Datadog
|
|
122
124
|
enabled = options.fetch(:enabled, nil)
|
123
125
|
hostname = options.fetch(:hostname, nil)
|
124
126
|
port = options.fetch(:port, nil)
|
127
|
+
@internal_traces = options.fetch(:internal_traces, false)
|
125
128
|
|
126
129
|
# Those are rare "power-user" options.
|
127
130
|
sampler = options.fetch(:sampler, nil)
|
data/lib/ddtrace/transport.rb
CHANGED
@@ -3,6 +3,7 @@ require 'net/http'
|
|
3
3
|
|
4
4
|
require 'ddtrace/encoding'
|
5
5
|
require 'ddtrace/version'
|
6
|
+
require 'ddtrace/utils'
|
6
7
|
|
7
8
|
module Datadog
|
8
9
|
# Transport class that handles the spans delivery to the
|
@@ -10,6 +11,9 @@ module Datadog
|
|
10
11
|
# so that the Transport is thread-safe.
|
11
12
|
# rubocop:disable Metrics/ClassLength
|
12
13
|
class HTTPTransport
|
14
|
+
include Datadog::Utils::InternalTraces
|
15
|
+
self.internal_trace_service = 'datadog.transport'.freeze
|
16
|
+
|
13
17
|
attr_accessor :hostname, :port
|
14
18
|
attr_reader :traces_endpoint, :services_endpoint
|
15
19
|
|
@@ -45,6 +49,12 @@ module Datadog
|
|
45
49
|
|
46
50
|
private_constant :API
|
47
51
|
|
52
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
53
|
+
DATADOG_META_LANG = 'Datadog-Meta-Lang'.freeze
|
54
|
+
DATADOG_META_LANG_VERSION = 'Datadog-Meta-Lang-Version'.freeze
|
55
|
+
DATADOG_META_LANG_INTERPRETER = 'Datadog-Meta-Lang-Interpreter'.freeze
|
56
|
+
DATADOG_META_TRACER_VERSION = 'Datadog-Meta-Tracer-Version'.freeze
|
57
|
+
|
48
58
|
def initialize(hostname, port, options = {})
|
49
59
|
api_version = options.fetch(:api_version, V3)
|
50
60
|
|
@@ -56,11 +66,11 @@ module Datadog
|
|
56
66
|
|
57
67
|
# overwrite the Content-type with the one chosen in the Encoder
|
58
68
|
@headers = options.fetch(:headers, {})
|
59
|
-
@headers[
|
60
|
-
@headers[
|
61
|
-
@headers[
|
62
|
-
@headers[
|
63
|
-
@headers[
|
69
|
+
@headers[CONTENT_TYPE] = @encoder.content_type
|
70
|
+
@headers[DATADOG_META_LANG] = 'ruby'.freeze
|
71
|
+
@headers[DATADOG_META_LANG_VERSION] = RUBY_VERSION
|
72
|
+
@headers[DATADOG_META_LANG_INTERPRETER] = RUBY_INTERPRETER
|
73
|
+
@headers[DATADOG_META_TRACER_VERSION] = Datadog::VERSION::STRING
|
64
74
|
|
65
75
|
# stats
|
66
76
|
@mutex = Mutex.new
|
@@ -68,32 +78,32 @@ module Datadog
|
|
68
78
|
@count_client_error = 0
|
69
79
|
@count_server_error = 0
|
70
80
|
@count_internal_error = 0
|
81
|
+
@count_consecutive_errors = 0
|
71
82
|
end
|
72
83
|
|
73
84
|
# route the send to the right endpoint
|
74
85
|
def send(endpoint, data)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
internal_span_when(-> { do_trace?(data) }, 'datadog.send'.freeze) do
|
87
|
+
case endpoint
|
88
|
+
when :services
|
89
|
+
status_code = send_services(data)
|
90
|
+
when :traces
|
91
|
+
status_code = send_traces(data)
|
92
|
+
else
|
93
|
+
with_active_internal_span { |s| s.set_error(RuntimeError.new("Unsupported endpoint: #{endpoint}")) }
|
94
|
+
|
95
|
+
Datadog::Tracer.log.error("Unsupported endpoint: #{endpoint}")
|
96
|
+
return nil
|
86
97
|
end
|
87
|
-
else
|
88
|
-
Datadog::Tracer.log.error("Unsupported endpoint: #{endpoint}")
|
89
|
-
return nil
|
90
|
-
end
|
91
98
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
99
|
+
if downgrade?(status_code)
|
100
|
+
internal_child_span('datadog.send.downgrade'.freeze) do
|
101
|
+
downgrade!
|
102
|
+
send(endpoint, data)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
status_code
|
106
|
+
end
|
97
107
|
end
|
98
108
|
end
|
99
109
|
|
@@ -105,11 +115,12 @@ module Datadog
|
|
105
115
|
headers = headers.merge(@headers)
|
106
116
|
request = Net::HTTP::Post.new(url, headers)
|
107
117
|
request.body = data
|
108
|
-
|
109
118
|
response = Net::HTTP.start(@hostname, @port, read_timeout: TIMEOUT) { |http| http.request(request) }
|
110
119
|
handle_response(response)
|
111
120
|
rescue StandardError => e
|
112
|
-
|
121
|
+
with_active_internal_span { |s| s.set_error(e) }
|
122
|
+
|
123
|
+
log_error_once(e.message)
|
113
124
|
500
|
114
125
|
end.tap do
|
115
126
|
yield(response) if block_given?
|
@@ -125,7 +136,7 @@ module Datadog
|
|
125
136
|
|
126
137
|
@api = API.fetch(fallback_version)
|
127
138
|
@encoder = @api[:encoder].new
|
128
|
-
@headers[
|
139
|
+
@headers[CONTENT_TYPE] = @encoder.content_type
|
129
140
|
end
|
130
141
|
end
|
131
142
|
|
@@ -167,24 +178,27 @@ module Datadog
|
|
167
178
|
# function is handled within the HTTP mutex.synchronize so it's thread-safe.
|
168
179
|
def handle_response(response)
|
169
180
|
status_code = response.code.to_i
|
181
|
+
with_active_internal_span { |s| s.set_tag('response.code', status_code) }
|
170
182
|
|
171
183
|
if success?(status_code)
|
172
|
-
Datadog::Tracer.log.debug('Payload correctly sent to the trace agent.')
|
184
|
+
Datadog::Tracer.log.debug('Payload correctly sent to the trace agent.'.freeze)
|
185
|
+
@mutex.synchronize { @count_consecutive_errors = 0 }
|
173
186
|
@mutex.synchronize { @count_success += 1 }
|
174
187
|
elsif downgrade?(status_code)
|
175
188
|
Datadog::Tracer.log.debug("calling the endpoint but received #{status_code}; downgrading the API")
|
176
189
|
elsif client_error?(status_code)
|
177
|
-
|
190
|
+
log_error_once("Client error: #{response.message}")
|
178
191
|
@mutex.synchronize { @count_client_error += 1 }
|
179
192
|
elsif server_error?(status_code)
|
180
|
-
|
181
|
-
@mutex.synchronize { @count_server_error += 1 }
|
193
|
+
log_error_once("Server error: #{response.message}")
|
182
194
|
end
|
183
195
|
|
184
196
|
status_code
|
185
197
|
rescue StandardError => e
|
186
|
-
|
198
|
+
log_error_once(e.message)
|
187
199
|
@mutex.synchronize { @count_internal_error += 1 }
|
200
|
+
with_active_internal_span { |s| s.set_error(e) }
|
201
|
+
|
188
202
|
500
|
189
203
|
end
|
190
204
|
|
@@ -201,6 +215,64 @@ module Datadog
|
|
201
215
|
|
202
216
|
private
|
203
217
|
|
218
|
+
def do_trace?(data)
|
219
|
+
# Create the span if we already are traced
|
220
|
+
return true if Datadog.tracer.active_span
|
221
|
+
# Don't trace empty data
|
222
|
+
return false unless data
|
223
|
+
|
224
|
+
# over 3 traces means that we most certainly send more than only internal traces
|
225
|
+
return true if data.length > 3
|
226
|
+
|
227
|
+
# all spans in all traces shouldn't be only 'datadog.internal' spans
|
228
|
+
!data.respond_to?(:all?) || data.all? do |trace|
|
229
|
+
!trace.respond_to?(:none?) || trace.none? do |span|
|
230
|
+
span.respond_to?(:get_tag) && span.get_tag(Utils::InternalTraces::INTERNAL_TAG)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def send_traces(data)
|
236
|
+
count = data.length
|
237
|
+
|
238
|
+
payload = internal_child_span('datadog.encode.traces'.freeze) do
|
239
|
+
with_active_internal_span { |s| s.set_tag('traces.count'.freeze, count) }
|
240
|
+
@encoder.encode_traces(data)
|
241
|
+
end
|
242
|
+
|
243
|
+
internal_child_span('datadog.traces.post'.freeze) do
|
244
|
+
post(@api[:traces_endpoint], payload, count) do |response|
|
245
|
+
internal_child_span('datadog.traces.response_callback'.freeze) do
|
246
|
+
process_callback(:traces, response)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def send_services(data)
|
253
|
+
payload = internal_child_span('datadog.services.encode'.freeze) do
|
254
|
+
@encoder.encode_services(data)
|
255
|
+
end
|
256
|
+
|
257
|
+
internal_child_span('datadog.services.post'.freeze) do
|
258
|
+
post(@api[:services_endpoint], payload) do |response|
|
259
|
+
internal_child_span('datadog.services.response_callback'.freeze) do
|
260
|
+
process_callback(:services, response)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def log_error_once(*args)
|
267
|
+
if @count_consecutive_errors > 0
|
268
|
+
Datadog::Tracer.log.debug(*args)
|
269
|
+
else
|
270
|
+
Datadog::Tracer.log.error(*args)
|
271
|
+
end
|
272
|
+
|
273
|
+
@mutex.synchronize { @count_consecutive_errors += 1 }
|
274
|
+
end
|
275
|
+
|
204
276
|
def process_callback(action, response)
|
205
277
|
return unless @response_callback && @response_callback.respond_to?(:call)
|
206
278
|
|
data/lib/ddtrace/utils.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Utils
|
3
|
+
# Traces generated by the client internals
|
4
|
+
module InternalTraces
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
# ClassMethods
|
10
|
+
module ClassMethods
|
11
|
+
attr_writer :internal_trace_service
|
12
|
+
|
13
|
+
def internal_trace_service
|
14
|
+
@internal_trace_service ||= 'datadog.unknown'.freeze
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
INTERNAL_TAG = 'datadog.internal'.freeze
|
19
|
+
|
20
|
+
def internal_span(name, *args)
|
21
|
+
return yield unless Datadog.tracer.internal_traces
|
22
|
+
|
23
|
+
Datadog.tracer.trace(name, *args) do |span|
|
24
|
+
span.set_tag(INTERNAL_TAG, true)
|
25
|
+
span.service = self.class.internal_trace_service
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def internal_span_when(condition, name, *args, &block)
|
31
|
+
return yield unless Datadog.tracer.internal_traces
|
32
|
+
|
33
|
+
condition = condition.call if condition.respond_to?(:send)
|
34
|
+
return yield unless condition
|
35
|
+
|
36
|
+
internal_span(name, *args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def internal_child_span(name, *args, &block)
|
40
|
+
return yield unless Datadog.tracer.internal_traces
|
41
|
+
|
42
|
+
internal_span_when(-> { Datadog.tracer.active_span }, name, *args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_active_internal_span
|
46
|
+
return unless Datadog.tracer.internal_traces
|
47
|
+
|
48
|
+
span = Datadog.tracer.active_span
|
49
|
+
yield(span) if span && span.get_tag(INTERNAL_TAG)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/ddtrace/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.15.0.
|
4
|
+
version: 0.15.0.internaltracinfeature1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -299,6 +299,11 @@ files:
|
|
299
299
|
- lib/ddtrace/contrib/aws/patcher.rb
|
300
300
|
- lib/ddtrace/contrib/aws/services.rb
|
301
301
|
- lib/ddtrace/contrib/base.rb
|
302
|
+
- lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb
|
303
|
+
- lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb
|
304
|
+
- lib/ddtrace/contrib/concurrent_ruby/future_patch.rb
|
305
|
+
- lib/ddtrace/contrib/concurrent_ruby/integration.rb
|
306
|
+
- lib/ddtrace/contrib/concurrent_ruby/patcher.rb
|
302
307
|
- lib/ddtrace/contrib/configurable.rb
|
303
308
|
- lib/ddtrace/contrib/configuration/option.rb
|
304
309
|
- lib/ddtrace/contrib/configuration/option_definition.rb
|
@@ -415,6 +420,7 @@ files:
|
|
415
420
|
- lib/ddtrace/transport.rb
|
416
421
|
- lib/ddtrace/utils.rb
|
417
422
|
- lib/ddtrace/utils/database.rb
|
423
|
+
- lib/ddtrace/utils/internal_traces.rb
|
418
424
|
- lib/ddtrace/vendor/active_record/connection_specification.rb
|
419
425
|
- lib/ddtrace/version.rb
|
420
426
|
- lib/ddtrace/workers.rb
|
@@ -440,7 +446,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
440
446
|
version: 1.3.1
|
441
447
|
requirements: []
|
442
448
|
rubyforge_project:
|
443
|
-
rubygems_version: 2.
|
449
|
+
rubygems_version: 2.7.7
|
444
450
|
signing_key:
|
445
451
|
specification_version: 4
|
446
452
|
summary: Datadog tracing code for your Ruby applications
|