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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +6 -6
  3. data/.circleci/images/primary/Dockerfile-1.9.3 +6 -2
  4. data/.circleci/images/primary/Dockerfile-2.0.0 +6 -2
  5. data/.circleci/images/primary/Dockerfile-2.1.10 +6 -2
  6. data/.circleci/images/primary/Dockerfile-2.2.10 +6 -2
  7. data/.circleci/images/primary/{Dockerfile-2.4.4 → Dockerfile-2.3.8} +5 -3
  8. data/.circleci/images/primary/{Dockerfile-2.3.7 → Dockerfile-2.4.6} +2 -2
  9. data/CHANGELOG.md +36 -0
  10. data/docker-compose.yml +6 -6
  11. data/docs/DevelopmentGuide.md +63 -0
  12. data/docs/GettingStarted.md +73 -3
  13. data/lib/ddtrace/configuration.rb +20 -1
  14. data/lib/ddtrace/contrib/http/circuit_breaker.rb +39 -11
  15. data/lib/ddtrace/contrib/http/instrumentation.rb +2 -11
  16. data/lib/ddtrace/ext/forced_tracing.rb +18 -2
  17. data/lib/ddtrace/ext/manual_tracing.rb +9 -0
  18. data/lib/ddtrace/ext/metrics.rb +0 -1
  19. data/lib/ddtrace/ext/runtime.rb +0 -1
  20. data/lib/ddtrace/forced_tracing.rb +3 -3
  21. data/lib/ddtrace/metrics.rb +0 -3
  22. data/lib/ddtrace/runtime/metrics.rb +0 -1
  23. data/lib/ddtrace/sync_writer.rb +1 -1
  24. data/lib/ddtrace/tracer.rb +78 -17
  25. data/lib/ddtrace/transport.rb +9 -0
  26. data/lib/ddtrace/transport/http.rb +85 -0
  27. data/lib/ddtrace/transport/http/adapters/net.rb +112 -0
  28. data/lib/ddtrace/transport/http/adapters/registry.rb +24 -0
  29. data/lib/ddtrace/transport/http/adapters/test.rb +77 -0
  30. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +64 -0
  31. data/lib/ddtrace/transport/http/api.rb +46 -0
  32. data/lib/ddtrace/transport/http/api/endpoint.rb +27 -0
  33. data/lib/ddtrace/transport/http/api/fallbacks.rb +22 -0
  34. data/lib/ddtrace/transport/http/api/instance.rb +29 -0
  35. data/lib/ddtrace/transport/http/api/map.rb +14 -0
  36. data/lib/ddtrace/transport/http/api/spec.rb +15 -0
  37. data/lib/ddtrace/transport/http/builder.rb +165 -0
  38. data/lib/ddtrace/transport/http/client.rb +108 -0
  39. data/lib/ddtrace/transport/http/env.rb +48 -0
  40. data/lib/ddtrace/transport/http/response.rb +22 -0
  41. data/lib/ddtrace/transport/http/traces.rb +140 -0
  42. data/lib/ddtrace/transport/parcel.rb +13 -0
  43. data/lib/ddtrace/transport/request.rb +13 -0
  44. data/lib/ddtrace/transport/response.rb +49 -0
  45. data/lib/ddtrace/transport/statistics.rb +44 -0
  46. data/lib/ddtrace/transport/traces.rb +33 -0
  47. data/lib/ddtrace/version.rb +1 -1
  48. data/lib/ddtrace/workers.rb +6 -2
  49. data/lib/ddtrace/writer.rb +48 -21
  50. 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,13 @@
1
+ module Datadog
2
+ module Transport
3
+ # Data transfer object for generic data
4
+ module Parcel
5
+ attr_reader \
6
+ :data
7
+
8
+ def initialize(data)
9
+ @data = data
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Datadog
2
+ module Transport
3
+ # Defines request for transport operations
4
+ class Request
5
+ attr_reader \
6
+ :parcel
7
+
8
+ def initialize(parcel)
9
+ @parcel = parcel
10
+ end
11
+ end
12
+ end
13
+ 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