ddtrace 0.24.0 → 0.25.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +6 -6
- data/.circleci/images/primary/Dockerfile-1.9.3 +6 -2
- data/.circleci/images/primary/Dockerfile-2.0.0 +6 -2
- data/.circleci/images/primary/Dockerfile-2.1.10 +6 -2
- data/.circleci/images/primary/Dockerfile-2.2.10 +6 -2
- data/.circleci/images/primary/{Dockerfile-2.4.4 → Dockerfile-2.3.8} +5 -3
- data/.circleci/images/primary/{Dockerfile-2.3.7 → Dockerfile-2.4.6} +2 -2
- data/CHANGELOG.md +36 -0
- data/docker-compose.yml +6 -6
- data/docs/DevelopmentGuide.md +63 -0
- data/docs/GettingStarted.md +73 -3
- data/lib/ddtrace/configuration.rb +20 -1
- data/lib/ddtrace/contrib/http/circuit_breaker.rb +39 -11
- data/lib/ddtrace/contrib/http/instrumentation.rb +2 -11
- data/lib/ddtrace/ext/forced_tracing.rb +18 -2
- data/lib/ddtrace/ext/manual_tracing.rb +9 -0
- data/lib/ddtrace/ext/metrics.rb +0 -1
- data/lib/ddtrace/ext/runtime.rb +0 -1
- data/lib/ddtrace/forced_tracing.rb +3 -3
- data/lib/ddtrace/metrics.rb +0 -3
- data/lib/ddtrace/runtime/metrics.rb +0 -1
- data/lib/ddtrace/sync_writer.rb +1 -1
- data/lib/ddtrace/tracer.rb +78 -17
- data/lib/ddtrace/transport.rb +9 -0
- data/lib/ddtrace/transport/http.rb +85 -0
- data/lib/ddtrace/transport/http/adapters/net.rb +112 -0
- data/lib/ddtrace/transport/http/adapters/registry.rb +24 -0
- data/lib/ddtrace/transport/http/adapters/test.rb +77 -0
- data/lib/ddtrace/transport/http/adapters/unix_socket.rb +64 -0
- data/lib/ddtrace/transport/http/api.rb +46 -0
- data/lib/ddtrace/transport/http/api/endpoint.rb +27 -0
- data/lib/ddtrace/transport/http/api/fallbacks.rb +22 -0
- data/lib/ddtrace/transport/http/api/instance.rb +29 -0
- data/lib/ddtrace/transport/http/api/map.rb +14 -0
- data/lib/ddtrace/transport/http/api/spec.rb +15 -0
- data/lib/ddtrace/transport/http/builder.rb +165 -0
- data/lib/ddtrace/transport/http/client.rb +108 -0
- data/lib/ddtrace/transport/http/env.rb +48 -0
- data/lib/ddtrace/transport/http/response.rb +22 -0
- data/lib/ddtrace/transport/http/traces.rb +140 -0
- data/lib/ddtrace/transport/parcel.rb +13 -0
- data/lib/ddtrace/transport/request.rb +13 -0
- data/lib/ddtrace/transport/response.rb +49 -0
- data/lib/ddtrace/transport/statistics.rb +44 -0
- data/lib/ddtrace/transport/traces.rb +33 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers.rb +6 -2
- data/lib/ddtrace/writer.rb +48 -21
- metadata +26 -4
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'ddtrace/transport/statistics'
|
2
|
+
require 'ddtrace/transport/http/env'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Transport
|
6
|
+
module HTTP
|
7
|
+
# Routes, encodes, and sends tracer data to the trace agent via HTTP.
|
8
|
+
class Client
|
9
|
+
include Transport::Statistics
|
10
|
+
|
11
|
+
attr_reader \
|
12
|
+
:apis,
|
13
|
+
:current_api_id
|
14
|
+
|
15
|
+
def initialize(apis, current_api_id)
|
16
|
+
@apis = apis
|
17
|
+
|
18
|
+
# Activate initial API
|
19
|
+
change_api!(current_api_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_request(request, &block)
|
23
|
+
# Build request into env
|
24
|
+
env = build_env(request)
|
25
|
+
|
26
|
+
# Get response from API
|
27
|
+
response = yield(current_api, env)
|
28
|
+
|
29
|
+
# Update statistics
|
30
|
+
update_stats_from_response!(response)
|
31
|
+
|
32
|
+
# If API should be downgraded, downgrade and try again.
|
33
|
+
if downgrade?(response)
|
34
|
+
downgrade!
|
35
|
+
response = send_request(request, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
response
|
39
|
+
rescue StandardError => e
|
40
|
+
message = "Internal error during HTTP transport request. Cause: #{e.message} Location: #{e.backtrace.first}"
|
41
|
+
|
42
|
+
# Log error
|
43
|
+
if stats.consecutive_errors > 0
|
44
|
+
Datadog::Tracer.log.debug(message)
|
45
|
+
else
|
46
|
+
Datadog::Tracer.log.error(message)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Update statistics
|
50
|
+
stats.internal_error += 1
|
51
|
+
stats.consecutive_errors += 1
|
52
|
+
|
53
|
+
InternalErrorResponse.new(e)
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_env(request)
|
57
|
+
Env.new(request)
|
58
|
+
end
|
59
|
+
|
60
|
+
def downgrade?(response)
|
61
|
+
return false unless apis.fallbacks.key?(current_api_id)
|
62
|
+
response.not_found? || response.unsupported?
|
63
|
+
end
|
64
|
+
|
65
|
+
def current_api
|
66
|
+
apis[current_api_id]
|
67
|
+
end
|
68
|
+
|
69
|
+
def change_api!(api_id)
|
70
|
+
raise UnknownApiVersionError, api_id unless apis.key?(api_id)
|
71
|
+
@current_api_id = api_id
|
72
|
+
end
|
73
|
+
|
74
|
+
def downgrade!
|
75
|
+
downgrade_api_id = apis.fallbacks[current_api_id]
|
76
|
+
raise NoDowngradeAvailableError, current_api_id if downgrade_api_id.nil?
|
77
|
+
change_api!(downgrade_api_id)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Raised when configured with an unknown API version
|
81
|
+
class UnknownApiVersionError < StandardError
|
82
|
+
attr_reader :version
|
83
|
+
|
84
|
+
def initialize(version)
|
85
|
+
@version = version
|
86
|
+
end
|
87
|
+
|
88
|
+
def message
|
89
|
+
"No matching transport API for version #{version}!"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Raised when configured with an unknown API version
|
94
|
+
class NoDowngradeAvailableError < StandardError
|
95
|
+
attr_reader :version
|
96
|
+
|
97
|
+
def initialize(version)
|
98
|
+
@version = version
|
99
|
+
end
|
100
|
+
|
101
|
+
def message
|
102
|
+
"No downgrade from transport API version #{version} is available!"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Transport
|
3
|
+
module HTTP
|
4
|
+
# Data structure for an HTTP request
|
5
|
+
class Env < Hash
|
6
|
+
attr_reader \
|
7
|
+
:request
|
8
|
+
|
9
|
+
def initialize(request, options = nil)
|
10
|
+
@request = request
|
11
|
+
merge!(options) unless options.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def verb
|
15
|
+
self[:verb]
|
16
|
+
end
|
17
|
+
|
18
|
+
def verb=(value)
|
19
|
+
self[:verb] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def path
|
23
|
+
self[:path]
|
24
|
+
end
|
25
|
+
|
26
|
+
def path=(value)
|
27
|
+
self[:path] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def body
|
31
|
+
self[:body]
|
32
|
+
end
|
33
|
+
|
34
|
+
def body=(value)
|
35
|
+
self[:body] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
def headers
|
39
|
+
self[:headers] ||= {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def headers=(value)
|
43
|
+
self[:headers] = value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'ddtrace/transport/response'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Transport
|
6
|
+
module HTTP
|
7
|
+
# Wraps an HTTP response from an adapter.
|
8
|
+
#
|
9
|
+
# Used by endpoints to wrap responses from adapters with
|
10
|
+
# fields or behavior that's specific to that endpoint.
|
11
|
+
module Response
|
12
|
+
extend ::Forwardable
|
13
|
+
|
14
|
+
def initialize(http_response)
|
15
|
+
@http_response = http_response
|
16
|
+
end
|
17
|
+
|
18
|
+
def_delegators :@http_response, *Transport::Response.instance_methods
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'ddtrace/transport/traces'
|
4
|
+
require 'ddtrace/transport/http/response'
|
5
|
+
require 'ddtrace/transport/http/api/endpoint'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Transport
|
9
|
+
module HTTP
|
10
|
+
# HTTP transport behavior for traces
|
11
|
+
module Traces
|
12
|
+
# Response from HTTP transport for traces
|
13
|
+
class Response
|
14
|
+
include HTTP::Response
|
15
|
+
include Transport::Traces::Response
|
16
|
+
|
17
|
+
def initialize(http_response, options = {})
|
18
|
+
super(http_response)
|
19
|
+
@service_rates = options.fetch(:service_rates, nil)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Extensions for HTTP client
|
24
|
+
module Client
|
25
|
+
def send_traces(traces)
|
26
|
+
request = Transport::Traces::Request.new(traces)
|
27
|
+
|
28
|
+
send_request(request) do |api, env|
|
29
|
+
api.send_traces(env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module API
|
35
|
+
# Extensions for HTTP API Spec
|
36
|
+
module Spec
|
37
|
+
attr_reader :traces
|
38
|
+
|
39
|
+
def traces=(endpoint)
|
40
|
+
@traces = endpoint
|
41
|
+
end
|
42
|
+
|
43
|
+
def send_traces(env, &block)
|
44
|
+
raise NoTraceEndpointDefinedError, self if traces.nil?
|
45
|
+
traces.call(env, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Raised when traces sent but no traces endpoint is defined
|
49
|
+
class NoTraceEndpointDefinedError < StandardError
|
50
|
+
attr_reader :spec
|
51
|
+
|
52
|
+
def initialize(spec)
|
53
|
+
@spec = spec
|
54
|
+
end
|
55
|
+
|
56
|
+
def message
|
57
|
+
'No trace endpoint is defined for API specification!'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Extensions for HTTP API Instance
|
63
|
+
module Instance
|
64
|
+
def send_traces(env)
|
65
|
+
raise TracesNotSupportedError, spec unless spec.is_a?(Traces::API::Spec)
|
66
|
+
|
67
|
+
spec.send_traces(env) do |request_env|
|
68
|
+
call(request_env)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Raised when traces sent to API that does not support traces
|
73
|
+
class TracesNotSupportedError < StandardError
|
74
|
+
attr_reader :spec
|
75
|
+
|
76
|
+
def initialize(spec)
|
77
|
+
@spec = spec
|
78
|
+
end
|
79
|
+
|
80
|
+
def message
|
81
|
+
'Traces not supported for this API!'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Endpoint for submitting trace data
|
87
|
+
class Endpoint < HTTP::API::Endpoint
|
88
|
+
HEADER_CONTENT_TYPE = 'Content-Type'.freeze
|
89
|
+
HEADER_TRACE_COUNT = 'X-Datadog-Trace-Count'.freeze
|
90
|
+
SERVICE_RATE_KEY = 'rate_by_service'.freeze
|
91
|
+
|
92
|
+
attr_reader \
|
93
|
+
:encoder
|
94
|
+
|
95
|
+
def initialize(path, encoder, options = {})
|
96
|
+
super(:post, path)
|
97
|
+
@encoder = encoder
|
98
|
+
@service_rates = options.fetch(:service_rates, false)
|
99
|
+
end
|
100
|
+
|
101
|
+
def service_rates?
|
102
|
+
@service_rates == true
|
103
|
+
end
|
104
|
+
|
105
|
+
def call(env, &block)
|
106
|
+
# Add trace count header
|
107
|
+
env.headers[HEADER_TRACE_COUNT] = env.request.parcel.count.to_s
|
108
|
+
|
109
|
+
# Encode body & type
|
110
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
111
|
+
env.body = env.request.parcel.encode_with(encoder)
|
112
|
+
|
113
|
+
# Query for response
|
114
|
+
http_response = super(env, &block)
|
115
|
+
|
116
|
+
# Process the response
|
117
|
+
response_options = {}.tap do |options|
|
118
|
+
# Parse service rates, if configured to do so.
|
119
|
+
if service_rates? && !http_response.payload.to_s.empty?
|
120
|
+
body = JSON.parse(http_response.payload)
|
121
|
+
if body.is_a?(Hash) && body.key?(SERVICE_RATE_KEY)
|
122
|
+
options[:service_rates] = body[SERVICE_RATE_KEY]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Build and return a trace response
|
128
|
+
Traces::Response.new(http_response, response_options)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Add traces behavior to transport components
|
134
|
+
HTTP::Client.send(:include, Traces::Client)
|
135
|
+
HTTP::API::Spec.send(:include, Traces::API::Spec)
|
136
|
+
HTTP::API::Instance.send(:include, Traces::API::Instance)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Transport
|
3
|
+
# Defines abstract response for transport operations
|
4
|
+
module Response
|
5
|
+
def payload
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def ok?
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def unsupported?
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def not_found?
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def client_error?
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def server_error?
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def internal_error?
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# A generic error response for internal errors
|
35
|
+
class InternalErrorResponse
|
36
|
+
include Response
|
37
|
+
|
38
|
+
attr_reader :error
|
39
|
+
|
40
|
+
def initialize(error)
|
41
|
+
@error = error
|
42
|
+
end
|
43
|
+
|
44
|
+
def internal_error?
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Transport
|
3
|
+
# Tracks statistics for transports
|
4
|
+
module Statistics
|
5
|
+
def stats
|
6
|
+
@stats ||= Counts.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_stats_from_response!(response)
|
10
|
+
if response.ok?
|
11
|
+
stats.success += 1
|
12
|
+
stats.consecutive_errors = 0
|
13
|
+
else
|
14
|
+
stats.client_error += 1 if response.client_error?
|
15
|
+
stats.server_error += 1 if response.server_error?
|
16
|
+
stats.internal_error += 1 if response.internal_error?
|
17
|
+
stats.consecutive_errors += 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Stat counts
|
22
|
+
class Counts
|
23
|
+
attr_accessor \
|
24
|
+
:success,
|
25
|
+
:client_error,
|
26
|
+
:server_error,
|
27
|
+
:internal_error,
|
28
|
+
:consecutive_errors
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
reset!
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset!
|
35
|
+
@success = 0
|
36
|
+
@client_error = 0
|
37
|
+
@server_error = 0
|
38
|
+
@internal_error = 0
|
39
|
+
@consecutive_errors = 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'ddtrace/transport/parcel'
|
2
|
+
require 'ddtrace/transport/request'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Transport
|
6
|
+
module Traces
|
7
|
+
# Data transfer object for trace data
|
8
|
+
class Parcel
|
9
|
+
include Transport::Parcel
|
10
|
+
|
11
|
+
def count
|
12
|
+
data.length
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode_with(encoder)
|
16
|
+
encoder.encode_traces(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Traces request
|
21
|
+
class Request < Transport::Request
|
22
|
+
def initialize(traces)
|
23
|
+
super(Parcel.new(traces))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Traces response
|
28
|
+
module Response
|
29
|
+
attr_reader :service_rates
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|