ddtrace 0.12.0 → 0.13.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +468 -0
  3. data/.circleci/images/primary/Dockerfile-1.9.3 +69 -0
  4. data/.circleci/images/primary/Dockerfile-2.0.0 +69 -0
  5. data/.circleci/images/primary/Dockerfile-2.1.10 +69 -0
  6. data/.circleci/images/primary/Dockerfile-2.2.10 +69 -0
  7. data/.circleci/images/primary/Dockerfile-2.3.7 +73 -0
  8. data/.circleci/images/primary/Dockerfile-2.4.4 +73 -0
  9. data/.dockerignore +1 -0
  10. data/.env +21 -11
  11. data/.gitignore +1 -1
  12. data/.rubocop.yml +4 -1
  13. data/Appraisals +471 -66
  14. data/CHANGELOG.md +80 -2
  15. data/Rakefile +304 -80
  16. data/ddtrace.gemspec +7 -7
  17. data/docker-compose.yml +240 -37
  18. data/docs/GettingStarted.md +273 -7
  19. data/lib/ddtrace/configuration.rb +2 -2
  20. data/lib/ddtrace/contrib/active_model_serializers/event.rb +57 -0
  21. data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
  22. data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
  23. data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
  24. data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +62 -0
  25. data/lib/ddtrace/contrib/active_record/event.rb +30 -0
  26. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +51 -0
  27. data/lib/ddtrace/contrib/active_record/events/sql.rb +48 -0
  28. data/lib/ddtrace/contrib/active_record/events.rb +30 -0
  29. data/lib/ddtrace/contrib/active_record/patcher.rb +3 -73
  30. data/lib/ddtrace/contrib/active_record/utils.rb +1 -15
  31. data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
  32. data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -2
  33. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -2
  34. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +18 -49
  35. data/lib/ddtrace/contrib/excon/middleware.rb +139 -0
  36. data/lib/ddtrace/contrib/excon/patcher.rb +50 -0
  37. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +49 -0
  38. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +66 -0
  39. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +65 -0
  40. data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
  41. data/lib/ddtrace/contrib/grpc/patcher.rb +62 -0
  42. data/lib/ddtrace/contrib/http/patcher.rb +18 -16
  43. data/lib/ddtrace/contrib/mongodb/parsers.rb +24 -13
  44. data/lib/ddtrace/contrib/mongodb/patcher.rb +1 -0
  45. data/lib/ddtrace/contrib/mongodb/subscribers.rb +5 -4
  46. data/lib/ddtrace/contrib/mysql2/client.rb +60 -0
  47. data/lib/ddtrace/contrib/mysql2/patcher.rb +43 -0
  48. data/lib/ddtrace/contrib/racecar/event.rb +61 -0
  49. data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
  50. data/lib/ddtrace/contrib/racecar/events/message.rb +27 -0
  51. data/lib/ddtrace/contrib/racecar/events.rb +30 -0
  52. data/lib/ddtrace/contrib/racecar/patcher.rb +6 -52
  53. data/lib/ddtrace/contrib/rack/middlewares.rb +65 -11
  54. data/lib/ddtrace/contrib/rack/patcher.rb +16 -0
  55. data/lib/ddtrace/contrib/rack/request_queue.rb +34 -0
  56. data/lib/ddtrace/contrib/rails/action_controller_patch.rb +77 -0
  57. data/lib/ddtrace/contrib/rails/action_view.rb +0 -65
  58. data/lib/ddtrace/contrib/rails/active_support.rb +9 -8
  59. data/lib/ddtrace/contrib/rails/core_extensions.rb +74 -115
  60. data/lib/ddtrace/contrib/rake/instrumentation.rb +70 -0
  61. data/lib/ddtrace/contrib/rake/patcher.rb +53 -0
  62. data/lib/ddtrace/contrib/sequel/database.rb +58 -0
  63. data/lib/ddtrace/contrib/sequel/dataset.rb +59 -0
  64. data/lib/ddtrace/contrib/sequel/patcher.rb +56 -0
  65. data/lib/ddtrace/contrib/sequel/utils.rb +28 -0
  66. data/lib/ddtrace/contrib/sidekiq/tracer.rb +1 -0
  67. data/lib/ddtrace/contrib/sinatra/env.rb +39 -0
  68. data/lib/ddtrace/contrib/sinatra/headers.rb +31 -0
  69. data/lib/ddtrace/contrib/sinatra/tracer.rb +21 -38
  70. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +61 -0
  71. data/lib/ddtrace/ext/distributed.rb +5 -0
  72. data/lib/ddtrace/ext/grpc.rb +7 -0
  73. data/lib/ddtrace/ext/http.rb +35 -5
  74. data/lib/ddtrace/propagation/grpc_propagator.rb +54 -0
  75. data/lib/ddtrace/quantization/hash.rb +103 -0
  76. data/lib/ddtrace/tracer.rb +4 -1
  77. data/lib/ddtrace/utils/database.rb +21 -0
  78. data/lib/ddtrace/utils.rb +12 -2
  79. data/lib/ddtrace/version.rb +1 -1
  80. data/lib/ddtrace.rb +7 -0
  81. metadata +50 -21
  82. data/circle.yml +0 -69
  83. data/gemfiles/contrib.gemfile +0 -25
  84. data/gemfiles/contrib_old.gemfile +0 -23
  85. data/gemfiles/rails30_postgres.gemfile +0 -11
  86. data/gemfiles/rails30_postgres_sidekiq.gemfile +0 -12
  87. data/gemfiles/rails32_mysql2.gemfile +0 -12
  88. data/gemfiles/rails32_postgres.gemfile +0 -11
  89. data/gemfiles/rails32_postgres_redis.gemfile +0 -13
  90. data/gemfiles/rails32_postgres_sidekiq.gemfile +0 -12
  91. data/gemfiles/rails4_mysql2.gemfile +0 -10
  92. data/gemfiles/rails4_postgres.gemfile +0 -10
  93. data/gemfiles/rails4_postgres_redis.gemfile +0 -12
  94. data/gemfiles/rails4_postgres_sidekiq.gemfile +0 -12
  95. data/gemfiles/rails5_mysql2.gemfile +0 -9
  96. data/gemfiles/rails5_postgres.gemfile +0 -9
  97. data/gemfiles/rails5_postgres_redis.gemfile +0 -11
  98. data/gemfiles/rails5_postgres_sidekiq.gemfile +0 -11
@@ -4,28 +4,26 @@ module Datadog
4
4
  # Quantize contains ES-specific resource quantization tools.
5
5
  module Quantize
6
6
  PLACEHOLDER = '?'.freeze
7
+ ID_PLACEHOLDER = '\1?'.freeze
7
8
  EXCLUDE_KEYS = [].freeze
8
9
  SHOW_KEYS = [:_index, :_type, :_id].freeze
9
- DEFAULT_OPTIONS = { exclude: EXCLUDE_KEYS, show: SHOW_KEYS }.freeze
10
-
11
- ID_REGEXP = %r{\/([0-9]+)([\/\?]|$)}
12
- ID_PLACEHOLDER = '/?\2'.freeze
13
-
14
- INDEX_REGEXP = /[0-9]{2,}/
15
- INDEX_PLACEHOLDER = '?'.freeze
10
+ DEFAULT_OPTIONS = {
11
+ exclude: EXCLUDE_KEYS,
12
+ show: SHOW_KEYS,
13
+ placeholder: PLACEHOLDER
14
+ }.freeze
16
15
 
17
16
  module_function
18
17
 
19
- # Very basic quantization, complex processing should be done in the agent
20
18
  def format_url(url)
21
- quantized_url = url.gsub(ID_REGEXP, ID_PLACEHOLDER)
22
- quantized_url.gsub(INDEX_REGEXP, INDEX_PLACEHOLDER)
19
+ sanitize_fragment_with_id(url)
20
+ .gsub(/(?:[\d]+)/, PLACEHOLDER)
23
21
  end
24
22
 
25
23
  def format_body(body, options = {})
26
24
  format_body!(body, options)
27
25
  rescue StandardError
28
- PLACEHOLDER
26
+ options[:placeholder] || PLACEHOLDER
29
27
  end
30
28
 
31
29
  def format_body!(body, options = {})
@@ -36,48 +34,12 @@ module Datadog
36
34
 
37
35
  # Parse each statement and quantize them.
38
36
  statements.collect do |string|
39
- reserialize_json(string) do |obj|
40
- format_statement(obj, options)
37
+ reserialize_json(string, options[:placeholder]) do |obj|
38
+ Datadog::Quantization::Hash.format(obj, options)
41
39
  end
42
40
  end.join("\n")
43
41
  end
44
42
 
45
- def format_statement(statement, options = {})
46
- return statement if options[:show] == :all
47
-
48
- case statement
49
- when Hash
50
- statement.each_with_object({}) do |(key, value), quantized|
51
- if options[:show].include?(key.to_sym)
52
- quantized[key] = value
53
- elsif !options[:exclude].include?(key.to_sym)
54
- quantized[key] = format_value(value, options)
55
- end
56
- end
57
- else
58
- format_value(statement, options)
59
- end
60
- end
61
-
62
- def format_value(value, options = {})
63
- return value if options[:show] == :all
64
-
65
- case value
66
- when Hash
67
- format_statement(value, options)
68
- when Array
69
- # If any are objects, format them.
70
- if value.any? { |v| v.class <= Hash || v.class <= Array }
71
- value.collect { |i| format_value(i, options) }
72
- # Otherwise short-circuit and return single placeholder
73
- else
74
- PLACEHOLDER
75
- end
76
- else
77
- PLACEHOLDER
78
- end
79
- end
80
-
81
43
  def merge_options(original, additional)
82
44
  {}.tap do |options|
83
45
  # Show
@@ -105,6 +67,13 @@ module Datadog
105
67
  fail_value
106
68
  end
107
69
  end
70
+
71
+ # Sanitizes URL fragment by changing it to ? whenever a number is detected
72
+ # This is meant as simple heuristic that attempts to detect if particular fragment
73
+ # represents document Id. This is meant to reduce the cardinality in most frequent cases.
74
+ def sanitize_fragment_with_id(url)
75
+ url.gsub(%r{^(/?[^/]*/[^/]*/)(?:[^\?/\d]*[\d]+[^\?/]*)}, ID_PLACEHOLDER)
76
+ end
108
77
  end
109
78
  end
110
79
  end
@@ -0,0 +1,139 @@
1
+ require 'excon'
2
+ require 'ddtrace/ext/http'
3
+ require 'ddtrace/ext/net'
4
+ require 'ddtrace/ext/distributed'
5
+ require 'ddtrace/propagation/http_propagator'
6
+
7
+ module Datadog
8
+ module Contrib
9
+ module Excon
10
+ # Middleware implements an excon-middleware for ddtrace instrumentation
11
+ class Middleware < ::Excon::Middleware::Base
12
+ SPAN_NAME = 'excon.request'.freeze
13
+ DEFAULT_ERROR_HANDLER = lambda do |response|
14
+ Ext::HTTP::ERROR_RANGE.cover?(response[:status])
15
+ end
16
+
17
+ def initialize(stack, options = {})
18
+ super(stack)
19
+ @options = Datadog.configuration[:excon].merge(options)
20
+ end
21
+
22
+ def request_call(datum)
23
+ begin
24
+ unless datum.key?(:datadog_span)
25
+ tracer.trace(SPAN_NAME).tap do |span|
26
+ datum[:datadog_span] = span
27
+ annotate!(span, datum)
28
+ propagate!(span, datum) if distributed_tracing?
29
+ end
30
+ end
31
+ rescue StandardError => e
32
+ Datadog::Tracer.log.debug(e.message)
33
+ end
34
+
35
+ @stack.request_call(datum)
36
+ end
37
+
38
+ def response_call(datum)
39
+ @stack.response_call(datum).tap do |d|
40
+ handle_response(d)
41
+ end
42
+ end
43
+
44
+ def error_call(datum)
45
+ handle_response(datum)
46
+ @stack.error_call(datum)
47
+ end
48
+
49
+ # Returns a child class of this trace middleware
50
+ # With options given as defaults.
51
+ def self.with(options = {})
52
+ Class.new(self) do
53
+ @options = options
54
+
55
+ # rubocop:disable Style/TrivialAccessors
56
+ def self.options
57
+ @options
58
+ end
59
+
60
+ def initialize(stack)
61
+ super(stack, self.class.options)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Returns a copy of the default stack with the trace middleware injected
67
+ def self.around_default_stack
68
+ ::Excon.defaults[:middlewares].dup.tap do |default_stack|
69
+ # If the default stack contains a version of the trace middleware already...
70
+ existing_trace_middleware = default_stack.find { |m| m <= Middleware }
71
+ default_stack.delete(existing_trace_middleware) if existing_trace_middleware
72
+
73
+ # Inject after the ResponseParser middleware
74
+ response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
75
+ default_stack.insert(response_middleware_index + 1, self)
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def tracer
82
+ @options[:tracer]
83
+ end
84
+
85
+ def distributed_tracing?
86
+ @options[:distributed_tracing] == true && tracer.enabled
87
+ end
88
+
89
+ def error_handler
90
+ @options[:error_handler] || DEFAULT_ERROR_HANDLER
91
+ end
92
+
93
+ def split_by_domain?
94
+ @options[:split_by_domain] == true
95
+ end
96
+
97
+ def annotate!(span, datum)
98
+ span.resource = datum[:method].to_s.upcase
99
+ span.service = service_name(datum)
100
+ span.span_type = Ext::HTTP::TYPE
101
+ span.set_tag(Ext::HTTP::URL, datum[:path])
102
+ span.set_tag(Ext::HTTP::METHOD, datum[:method].to_s.upcase)
103
+ span.set_tag(Ext::NET::TARGET_HOST, datum[:host])
104
+ span.set_tag(Ext::NET::TARGET_PORT, datum[:port].to_s)
105
+ end
106
+
107
+ def handle_response(datum)
108
+ if datum.key?(:datadog_span)
109
+ datum[:datadog_span].tap do |span|
110
+ return span if span.finished?
111
+
112
+ if datum.key?(:response)
113
+ response = datum[:response]
114
+ if error_handler.call(response)
115
+ span.set_error(["Error #{response[:status]}", response[:body]])
116
+ end
117
+ span.set_tag(Ext::HTTP::STATUS_CODE, response[:status])
118
+ end
119
+ span.set_error(datum[:error]) if datum.key?(:error)
120
+ span.finish
121
+ datum.delete(:datadog_span)
122
+ end
123
+ end
124
+ rescue StandardError => e
125
+ Datadog::Tracer.log.debug(e.message)
126
+ end
127
+
128
+ def propagate!(span, datum)
129
+ Datadog::HTTPPropagator.inject!(span.context, datum[:headers])
130
+ end
131
+
132
+ def service_name(datum)
133
+ # TODO: Change this to implement more sensible multiplexing
134
+ split_by_domain? ? datum[:host] : @options[:service_name]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,50 @@
1
+ require 'ddtrace/ext/app_types'
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Excon
6
+ # Responsible for hooking the instrumentation into Excon
7
+ module Patcher
8
+ include Base
9
+
10
+ DEFAULT_SERVICE = 'excon'.freeze
11
+
12
+ register_as :excon
13
+ option :tracer, default: Datadog.tracer
14
+ option :service_name, default: DEFAULT_SERVICE
15
+ option :distributed_tracing, default: false
16
+ option :split_by_domain, default: false
17
+ option :error_handler, default: nil
18
+
19
+ @patched = false
20
+
21
+ module_function
22
+
23
+ def patch
24
+ return @patched if patched? || !compatible?
25
+
26
+ require 'ddtrace/contrib/excon/middleware'
27
+
28
+ add_middleware
29
+
30
+ @patched = true
31
+ rescue => e
32
+ Tracer.log.error("Unable to apply Excon integration: #{e}")
33
+ @patched
34
+ end
35
+
36
+ def patched?
37
+ @patched
38
+ end
39
+
40
+ def compatible?
41
+ defined?(::Excon)
42
+ end
43
+
44
+ def add_middleware
45
+ ::Excon.defaults[:middlewares] = Middleware.around_default_stack
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,49 @@
1
+ module Datadog
2
+ module Contrib
3
+ module GRPC
4
+ module DatadogInterceptor
5
+ # The DatadogInterceptor::Client implements the tracing strategy
6
+ # for gRPC client-side endpoitns. This middleware compoent will
7
+ # inject trace context information into gRPC metadata prior to
8
+ # sending the request to the server.
9
+ class Client < Base
10
+ def trace(keywords)
11
+ keywords[:metadata] ||= {}
12
+
13
+ options = {
14
+ span_type: Datadog::Ext::GRPC::TYPE,
15
+ service: datadog_pin.service_name,
16
+ resource: format_resource(keywords[:method])
17
+ }
18
+
19
+ tracer.trace('grpc.client', options) do |span|
20
+ annotate!(span, keywords[:metadata])
21
+
22
+ yield
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def annotate!(span, metadata)
29
+ metadata.each do |header, value|
30
+ span.set_tag(header, value)
31
+ end
32
+
33
+ Datadog::GRPCPropagator
34
+ .inject!(span.context, metadata)
35
+ rescue StandardError => e
36
+ Datadog::Tracer.log.debug("GRPC client trace failed: #{e}")
37
+ end
38
+
39
+ def format_resource(proto_method)
40
+ proto_method.downcase
41
+ .split('/')
42
+ .reject(&:empty?)
43
+ .join('.')
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,66 @@
1
+ module Datadog
2
+ module Contrib
3
+ module GRPC
4
+ module DatadogInterceptor
5
+ # The DatadogInterceptor::Server implements the tracing strategy
6
+ # for gRPC server-side endpoints. When the datadog fields have been
7
+ # added to the gRPC call metadata, this middleware component will
8
+ # extract any client-side tracing information, attempting to associate
9
+ # its tracing context with a parent client-side context
10
+ class Server < Base
11
+ def trace(keywords)
12
+ options = {
13
+ span_type: Datadog::Ext::GRPC::TYPE,
14
+ service: datadog_pin.service_name,
15
+ resource: format_resource(keywords[:method])
16
+ }
17
+ metadata = keywords[:call].metadata
18
+
19
+ set_distributed_context!(tracer, metadata)
20
+
21
+ tracer.trace('grpc.service', options) do |span|
22
+ annotate!(span, metadata)
23
+
24
+ yield
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def set_distributed_context!(tracer, metadata)
31
+ tracer.provider.context = Datadog::GRPCPropagator
32
+ .extract(metadata)
33
+ rescue StandardError => e
34
+ Datadog::Tracer.log.debug(
35
+ "unable to propagate GRPC metadata to context: #{e}"
36
+ )
37
+ end
38
+
39
+ def annotate!(span, metadata)
40
+ metadata.each do |header, value|
41
+ next if reserved_headers.include?(header)
42
+ span.set_tag(header, value)
43
+ end
44
+ rescue StandardError => e
45
+ Datadog::Tracer.log.debug("GRPC client trace failed: #{e}")
46
+ end
47
+
48
+ def reserved_headers
49
+ [Datadog::Ext::DistributedTracing::GRPC_METADATA_TRACE_ID,
50
+ Datadog::Ext::DistributedTracing::GRPC_METADATA_PARENT_ID,
51
+ Datadog::Ext::DistributedTracing::GRPC_METADATA_SAMPLING_PRIORITY]
52
+ end
53
+
54
+ def format_resource(proto_method)
55
+ proto_method.owner
56
+ .to_s
57
+ .downcase
58
+ .split('::')
59
+ .<<(proto_method.name)
60
+ .join('.')
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,65 @@
1
+ module Datadog
2
+ module Contrib
3
+ module GRPC
4
+ # :nodoc:
5
+ module DatadogInterceptor
6
+ # :nodoc:
7
+ class Base < ::GRPC::Interceptor
8
+ attr_accessor :datadog_pin
9
+
10
+ def initialize(options = {})
11
+ datadog_pin_configuration { |c| yield(c) if block_given? }
12
+ end
13
+
14
+ def request_response(**keywords)
15
+ trace(keywords) { yield }
16
+ end
17
+
18
+ def client_streamer(**keywords)
19
+ trace(keywords) { yield }
20
+ end
21
+
22
+ def server_streamer(**keywords)
23
+ trace(keywords) { yield }
24
+ end
25
+
26
+ def bidi_streamer(**keywords)
27
+ trace(keywords) { yield }
28
+ end
29
+
30
+ private
31
+
32
+ def datadog_pin_configuration
33
+ pin = default_datadog_pin
34
+
35
+ if block_given?
36
+ pin = Pin.new(
37
+ pin.service_name,
38
+ app: pin.app,
39
+ app_type: pin.app_type,
40
+ tracer: pin.tracer
41
+ )
42
+
43
+ yield(pin)
44
+ end
45
+
46
+ pin.onto(self)
47
+
48
+ pin
49
+ end
50
+
51
+ def default_datadog_pin
52
+ Pin.get_from(::GRPC)
53
+ end
54
+
55
+ def tracer
56
+ datadog_pin.tracer
57
+ end
58
+ end
59
+
60
+ require_relative 'datadog_interceptor/client'
61
+ require_relative 'datadog_interceptor/server'
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ require_relative 'datadog_interceptor'
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module GRPC
6
+ # :nodoc:
7
+ # The `#intercept!` method is implemented in gRPC; this module
8
+ # will be prepended to the original class, effectively injecting
9
+ # our tracing middleware into the head of the call chain.
10
+ module InterceptWithDatadog
11
+ def intercept!(type, args = {})
12
+ if should_prepend?
13
+ datadog_interceptor = choose_datadog_interceptor(args)
14
+
15
+ @interceptors.unshift(datadog_interceptor.new) if datadog_interceptor
16
+
17
+ @trace_started = true
18
+ end
19
+
20
+ super
21
+ end
22
+
23
+ private
24
+
25
+ def should_prepend?
26
+ !trace_started? && !already_prepended?
27
+ end
28
+
29
+ def trace_started?
30
+ defined?(@trace_started) && @trace_started
31
+ end
32
+
33
+ def already_prepended?
34
+ @interceptors.any? do |interceptor|
35
+ interceptor.class.ancestors.include?(Datadog::Contrib::GRPC::DatadogInterceptor::Base)
36
+ end
37
+ end
38
+
39
+ def choose_datadog_interceptor(args)
40
+ if args.key?(:metadata)
41
+ Datadog::Contrib::GRPC::DatadogInterceptor::Client
42
+ elsif args.key?(:call)
43
+ Datadog::Contrib::GRPC::DatadogInterceptor::Server
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,62 @@
1
+ # requirements should be kept minimal as Patcher is a shared requirement.
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module GRPC
6
+ SERVICE = 'grpc'.freeze
7
+
8
+ # Patcher enables patching of 'grpc' module.
9
+ module Patcher
10
+ include Base
11
+ register_as :grpc, auto_patch: true
12
+ option :tracer, default: Datadog.tracer
13
+ option :service_name, default: SERVICE
14
+
15
+ @patched = false
16
+
17
+ module_function
18
+
19
+ def patch
20
+ return false unless compatible?
21
+ return @patched if @patched
22
+
23
+ require 'ddtrace/ext/grpc'
24
+ require 'ddtrace/propagation/grpc_propagator'
25
+ require 'ddtrace/contrib/grpc/datadog_interceptor'
26
+ require 'ddtrace/contrib/grpc/intercept_with_datadog'
27
+
28
+ add_pin
29
+ prepend_interceptor
30
+
31
+ @patched = true
32
+ rescue StandardError => e
33
+ Datadog::Tracer.log.error("Unable to apply gRPC integration: #{e}")
34
+ ensure
35
+ @patched
36
+ end
37
+
38
+ def compatible?
39
+ defined?(::GRPC::VERSION) && Gem::Version.new(::GRPC::VERSION) >= Gem::Version.new('0.10.0')
40
+ end
41
+
42
+ def patched?
43
+ @patched
44
+ end
45
+
46
+ def add_pin
47
+ Pin.new(
48
+ get_option(:service_name),
49
+ app: 'grpc',
50
+ app_type: 'grpc',
51
+ tracer: get_option(:tracer)
52
+ ).onto(::GRPC)
53
+ end
54
+
55
+ def prepend_interceptor
56
+ ::GRPC::InterceptionContext
57
+ .prepend(Datadog::Contrib::GRPC::InterceptWithDatadog)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -48,6 +48,8 @@ module Datadog
48
48
  include Base
49
49
  register_as :http, auto_patch: true
50
50
  option :distributed_tracing, default: false
51
+ option :service_name, default: SERVICE
52
+ option :tracer, default: Datadog.tracer
51
53
 
52
54
  @patched = false
53
55
 
@@ -64,7 +66,7 @@ module Datadog
64
66
  require 'ddtrace/ext/net'
65
67
  require 'ddtrace/ext/distributed'
66
68
 
67
- patch_http()
69
+ patch_http
68
70
 
69
71
  @patched = true
70
72
  rescue StandardError => e
@@ -74,7 +76,7 @@ module Datadog
74
76
  @patched
75
77
  end
76
78
 
77
- # patched? tells wether patch has been successfully applied
79
+ # patched? tells whether patch has been successfully applied
78
80
  def patched?
79
81
  @patched
80
82
  end
@@ -84,27 +86,27 @@ module Datadog
84
86
  # rubocop:disable Metrics/AbcSize
85
87
  def patch_http
86
88
  ::Net::HTTP.class_eval do
87
- alias_method :initialize_without_datadog, :initialize
88
- Datadog::Patcher.without_warnings do
89
- remove_method :initialize
90
- end
91
-
92
- def initialize(*args)
93
- pin = Datadog::Pin.new(SERVICE, app: APP, app_type: Datadog::Ext::AppTypes::WEB)
94
- pin.onto(self)
95
- initialize_without_datadog(*args)
96
- end
97
-
98
89
  alias_method :request_without_datadog, :request
99
90
  remove_method :request
100
91
 
92
+ def datadog_pin
93
+ @datadog_pindatadog_pin ||= begin
94
+ service = Datadog.configuration[:http][:service_name]
95
+ tracer = Datadog.configuration[:http][:tracer]
96
+
97
+ Datadog::Pin.new(service, app: APP, app_type: Datadog::Ext::AppTypes::WEB, tracer: tracer)
98
+ end
99
+ end
100
+
101
101
  def request(req, body = nil, &block) # :yield: +response+
102
- pin = Datadog::Pin.get_from(self)
102
+ pin = datadog_pin
103
103
  return request_without_datadog(req, body, &block) unless pin && pin.tracer
104
104
 
105
105
  transport = pin.tracer.writer.transport
106
- return request_without_datadog(req, body, &block) if
107
- Datadog::Contrib::HTTP.should_skip_tracing?(req, @address, @port, transport, pin)
106
+
107
+ if Datadog::Contrib::HTTP.should_skip_tracing?(req, @address, @port, transport, pin)
108
+ return request_without_datadog(req, body, &block)
109
+ end
108
110
 
109
111
  pin.tracer.trace(NAME) do |span|
110
112
  begin