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
@@ -0,0 +1,59 @@
1
+ require 'ddtrace/ext/sql'
2
+ require 'ddtrace/ext/app_types'
3
+ require 'ddtrace/contrib/sequel/utils'
4
+
5
+ module Datadog
6
+ module Contrib
7
+ module Sequel
8
+ # Adds instrumentation to Sequel::Dataset
9
+ module Dataset
10
+ def self.included(base)
11
+ base.send(:prepend, InstanceMethods)
12
+ end
13
+
14
+ # Instance methods for instrumenting Sequel::Dataset
15
+ module InstanceMethods
16
+ def execute(sql, options = ::Sequel::OPTS, &block)
17
+ trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
18
+ end
19
+
20
+ def execute_ddl(sql, options = ::Sequel::OPTS, &block)
21
+ trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
22
+ end
23
+
24
+ def execute_dui(sql, options = ::Sequel::OPTS, &block)
25
+ trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
26
+ end
27
+
28
+ def execute_insert(sql, options = ::Sequel::OPTS, &block)
29
+ trace_execute(proc { super(sql, options, &block) }, sql, options, &block)
30
+ end
31
+
32
+ def datadog_pin
33
+ Datadog::Pin.get_from(db)
34
+ end
35
+
36
+ private
37
+
38
+ def trace_execute(super_method, sql, options, &block)
39
+ opts = Utils.parse_opts(sql, options, db.opts)
40
+ response = nil
41
+
42
+ datadog_pin.tracer.trace('sequel.query') do |span|
43
+ span.service = datadog_pin.service
44
+ span.resource = opts[:query]
45
+ span.span_type = Datadog::Ext::SQL::TYPE
46
+ span.set_tag('sequel.db.vendor', adapter_name)
47
+ response = super_method.call(sql, options, &block)
48
+ end
49
+ response
50
+ end
51
+
52
+ def adapter_name
53
+ Utils.adapter_name(db)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,56 @@
1
+ require 'ddtrace/contrib/sequel/database'
2
+ require 'ddtrace/contrib/sequel/dataset'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Sequel
7
+ # Patcher enables patching of 'sequel' module.
8
+ # This is used in monkey.rb to manually apply patches
9
+ module Patcher
10
+ include Base
11
+
12
+ APP = 'sequel'.freeze
13
+
14
+ register_as :sequel, auto_patch: false
15
+ option :service_name
16
+ option :tracer, default: Datadog.tracer
17
+
18
+ @patched = false
19
+
20
+ module_function
21
+
22
+ # patched? tells whether patch has been successfully applied
23
+ def patched?
24
+ @patched
25
+ end
26
+
27
+ def patch
28
+ if !@patched && compatible?
29
+ begin
30
+ patch_sequel_database
31
+ patch_sequel_dataset
32
+
33
+ @patched = true
34
+ rescue StandardError => e
35
+ Datadog::Tracer.log.error("Unable to apply Sequel integration: #{e}")
36
+ end
37
+ end
38
+
39
+ @patched
40
+ end
41
+
42
+ def compatible?
43
+ RUBY_VERSION >= '2.0.0' && defined?(::Sequel)
44
+ end
45
+
46
+ def patch_sequel_database
47
+ ::Sequel::Database.send(:include, Database)
48
+ end
49
+
50
+ def patch_sequel_dataset
51
+ ::Sequel::Dataset.send(:include, Dataset)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Sequel
4
+ # General purpose functions for Sequel
5
+ module Utils
6
+ module_function
7
+
8
+ def adapter_name(database)
9
+ Datadog::Utils::Database.normalize_vendor(database.adapter_scheme.to_s)
10
+ end
11
+
12
+ def parse_opts(sql, opts, db_opts)
13
+ if ::Sequel::VERSION >= '4.37.0' && !sql.is_a?(String)
14
+ # In 4.37.0, sql was converted to a prepared statement object
15
+ sql = sql.prepared_sql unless sql.is_a?(Symbol)
16
+ end
17
+
18
+ {
19
+ name: opts[:type],
20
+ query: sql,
21
+ database: db_opts[:database],
22
+ host: db_opts[:host]
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -32,6 +32,7 @@ module Datadog
32
32
  span.set_tag('sidekiq.job.retry', job['retry'])
33
33
  span.set_tag('sidekiq.job.queue', job['queue'])
34
34
  span.set_tag('sidekiq.job.wrapper', job['class']) if job['wrapped']
35
+ span.set_tag('sidekiq.job.delay', 1000.0 * (Time.now.utc.to_f - job['enqueued_at'].to_f))
35
36
 
36
37
  yield
37
38
  end
@@ -0,0 +1,39 @@
1
+ require 'ddtrace/ext/http'
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Sinatra
6
+ # Gets and sets trace information from a Rack Env
7
+ module Env
8
+ ENV_SPAN = 'datadog.sinatra_request_span'.freeze
9
+
10
+ module_function
11
+
12
+ def datadog_span(env)
13
+ env[ENV_SPAN]
14
+ end
15
+
16
+ def set_datadog_span(env, span)
17
+ env[ENV_SPAN] = span
18
+ end
19
+
20
+ def request_header_tags(env, headers)
21
+ headers ||= []
22
+
23
+ {}.tap do |result|
24
+ headers.each do |header|
25
+ rack_header = header_to_rack_header(header)
26
+ if env.key?(rack_header)
27
+ result[Datadog::Ext::HTTP::RequestHeaders.to_tag(header)] = env[rack_header]
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def header_to_rack_header(name)
34
+ "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ require 'ddtrace/ext/http'
2
+
3
+ module Datadog
4
+ module Contrib
5
+ module Sinatra
6
+ # Gets and sets trace information from a Rack headers Hash
7
+ module Headers
8
+ module_function
9
+
10
+ def response_header_tags(headers, target_headers)
11
+ target_headers ||= []
12
+
13
+ {}.tap do |result|
14
+ target_headers.each do |header|
15
+ if headers.key?(header)
16
+ result[Datadog::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[header]
17
+ else
18
+ # Try a case-insensitive lookup
19
+ uppercased_header = header.to_s.upcase
20
+ matching_header = headers.keys.find { |h| h.upcase == uppercased_header }
21
+ if matching_header
22
+ result[Datadog::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[matching_header]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,4 +1,3 @@
1
-
2
1
  require 'sinatra/base'
3
2
 
4
3
  require 'ddtrace/ext/app_types'
@@ -6,11 +5,14 @@ require 'ddtrace/ext/errors'
6
5
  require 'ddtrace/ext/http'
7
6
  require 'ddtrace/propagation/http_propagator'
8
7
 
8
+ require 'ddtrace/contrib/sinatra/tracer_middleware'
9
+ require 'ddtrace/contrib/sinatra/env'
10
+
9
11
  sinatra_vs = Gem::Version.new(Sinatra::VERSION)
10
12
  sinatra_min_vs = Gem::Version.new('1.4.0')
11
13
  if sinatra_vs < sinatra_min_vs
12
14
  raise "sinatra version #{sinatra_vs} is not supported yet " \
13
- + "(supporting versions >=#{sinatra_min_vs})"
15
+ + "(supporting versions >=#{sinatra_min_vs})"
14
16
  end
15
17
 
16
18
  Datadog::Tracer.log.info("activating instrumentation for sinatra #{sinatra_vs}")
@@ -21,6 +23,10 @@ module Datadog
21
23
  # Datadog::Contrib::Sinatra::Tracer is a Sinatra extension which traces
22
24
  # requests.
23
25
  module Tracer
26
+ DEFAULT_HEADERS = {
27
+ response: %w[Content-Type X-Request-ID]
28
+ }.freeze
29
+
24
30
  include Base
25
31
  register_as :sinatra
26
32
 
@@ -32,6 +38,7 @@ module Datadog
32
38
  option :tracer, default: Datadog.tracer
33
39
  option :resource_script_names, default: false
34
40
  option :distributed_tracing, default: false
41
+ option :headers, default: DEFAULT_HEADERS
35
42
 
36
43
  def route(verb, action, *)
37
44
  # Keep track of the route name when the app is instantiated for an
@@ -49,8 +56,6 @@ module Datadog
49
56
  super
50
57
  end
51
58
 
52
- # rubocop:disable Metrics/AbcSize
53
- # rubocop:disable Metrics/MethodLength
54
59
  def self.registered(app)
55
60
  ::Sinatra::Base.module_eval do
56
61
  def render(engine, data, *)
@@ -71,52 +76,30 @@ module Datadog
71
76
  end
72
77
  end
73
78
 
79
+ app.use TracerMiddleware
80
+
74
81
  app.before do
75
82
  return unless Datadog.configuration[:sinatra][:tracer].enabled
76
83
 
77
- if instance_variable_defined? :@datadog_request_span
78
- if @datadog_request_span
79
- Datadog::Tracer.log.error('request span active in :before hook')
80
- @datadog_request_span.finish()
81
- @datadog_request_span = nil
82
- end
83
- end
84
-
85
- tracer = Datadog.configuration[:sinatra][:tracer]
86
- distributed_tracing = Datadog.configuration[:sinatra][:distributed_tracing]
87
-
88
- if distributed_tracing && tracer.provider.context.trace_id.nil?
89
- context = HTTPPropagator.extract(request.env)
90
- tracer.provider.context = context if context.trace_id
91
- end
92
-
93
- span = tracer.trace('sinatra.request',
94
- service: Datadog.configuration[:sinatra][:service_name],
95
- span_type: Datadog::Ext::HTTP::TYPE)
84
+ span = Sinatra::Env.datadog_span(env)
96
85
  span.set_tag(Datadog::Ext::HTTP::URL, request.path)
97
86
  span.set_tag(Datadog::Ext::HTTP::METHOD, request.request_method)
98
-
99
- @datadog_request_span = span
100
87
  end
101
88
 
102
89
  app.after do
103
90
  return unless Datadog.configuration[:sinatra][:tracer].enabled
104
91
 
105
- span = @datadog_request_span
106
- begin
107
- unless span
108
- Datadog::Tracer.log.error('missing request span in :after hook')
109
- return
110
- end
92
+ span = Sinatra::Env.datadog_span(env)
111
93
 
112
- span.resource = "#{request.request_method} #{@datadog_route}"
113
- span.set_tag('sinatra.route.path', @datadog_route)
114
- span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
115
- span.set_error(env['sinatra.error']) if response.server_error?
116
- span.finish()
117
- ensure
118
- @datadog_request_span = nil
94
+ unless span
95
+ Datadog::Tracer.log.error('missing request span in :after hook')
96
+ return
119
97
  end
98
+
99
+ span.resource = "#{request.request_method} #{@datadog_route}"
100
+ span.set_tag('sinatra.route.path', @datadog_route)
101
+ span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status)
102
+ span.set_error(env['sinatra.error']) if response.server_error?
120
103
  end
121
104
  end
122
105
  end
@@ -0,0 +1,61 @@
1
+ require 'ddtrace/contrib/sinatra/env'
2
+ require 'ddtrace/contrib/sinatra/headers'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Sinatra
7
+ # Middleware used for automatically tagging configured headers and handle request span
8
+ class TracerMiddleware
9
+ REQUEST_TRACE_NAME = 'sinatra.request'.freeze
10
+
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ # Set the trace context (e.g. distributed tracing)
17
+ if configuration[:distributed_tracing] && tracer.provider.context.trace_id.nil?
18
+ context = HTTPPropagator.extract(env)
19
+ tracer.provider.context = context if context.trace_id
20
+ end
21
+
22
+ # Begin the trace
23
+ tracer.trace(
24
+ REQUEST_TRACE_NAME,
25
+ service: configuration[:service_name],
26
+ span_type: Datadog::Ext::HTTP::TYPE
27
+ ) do |span|
28
+ Sinatra::Env.set_datadog_span(env, span)
29
+
30
+ Sinatra::Env.request_header_tags(env, configuration[:headers][:request]).each do |name, value|
31
+ span.set_tag(name, value) if span.get_tag(name).nil?
32
+ end
33
+
34
+ # Run application stack
35
+ status, headers, response_body = @app.call(env)
36
+
37
+ Sinatra::Headers.response_header_tags(headers, configuration[:headers][:response]).each do |name, value|
38
+ span.set_tag(name, value) if span.get_tag(name).nil?
39
+ end
40
+
41
+ [status, headers, response_body]
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def tracer
48
+ configuration[:tracer]
49
+ end
50
+
51
+ def configuration
52
+ Datadog.configuration[:sinatra]
53
+ end
54
+
55
+ def header_to_rack_header(name)
56
+ "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -7,6 +7,11 @@ module Datadog
7
7
  HTTP_HEADER_PARENT_ID = 'x-datadog-parent-id'.freeze
8
8
  HTTP_HEADER_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
9
9
  SAMPLING_PRIORITY_KEY = '_sampling_priority_v1'.freeze
10
+
11
+ # gRPC metadata keys for distributed tracing. https://github.com/grpc/grpc-go/blob/v1.10.x/Documentation/grpc-metadata.md
12
+ GRPC_METADATA_TRACE_ID = 'x-datadog-trace-id'.freeze
13
+ GRPC_METADATA_PARENT_ID = 'x-datadog-parent-id'.freeze
14
+ GRPC_METADATA_SAMPLING_PRIORITY = 'x-datadog-sampling-priority'.freeze
10
15
  end
11
16
  end
12
17
  end
@@ -0,0 +1,7 @@
1
+ module Datadog
2
+ module Ext
3
+ module GRPC
4
+ TYPE = 'grpc'.freeze
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,44 @@
1
1
  module Datadog
2
2
  module Ext
3
3
  module HTTP
4
- TYPE = 'http'.freeze
5
- TEMPLATE = 'template'.freeze
6
- URL = 'http.url'.freeze
7
4
  BASE_URL = 'http.base_url'.freeze
5
+ ERROR_RANGE = 500...600
8
6
  METHOD = 'http.method'.freeze
9
- REQUEST_ID = 'http.request_id'.freeze
10
7
  STATUS_CODE = 'http.status_code'.freeze
11
- ERROR_RANGE = 500...600
8
+ TEMPLATE = 'template'.freeze
9
+ TYPE = 'http'.freeze
10
+ URL = 'http.url'.freeze
11
+
12
+ # General header functionality
13
+ module Headers
14
+ module_function
15
+
16
+ def to_tag(name)
17
+ name.to_s.downcase.gsub(/[-\s]/, '_')
18
+ end
19
+ end
20
+
21
+ # Request headers
22
+ module RequestHeaders
23
+ PREFIX = 'http.request.headers'.freeze
24
+
25
+ module_function
26
+
27
+ def to_tag(name)
28
+ "#{PREFIX}.#{Headers.to_tag(name)}"
29
+ end
30
+ end
31
+
32
+ # Response headers
33
+ module ResponseHeaders
34
+ PREFIX = 'http.response.headers'.freeze
35
+
36
+ module_function
37
+
38
+ def to_tag(name)
39
+ "#{PREFIX}.#{Headers.to_tag(name)}"
40
+ end
41
+ end
12
42
  end
13
43
  end
14
44
  end
@@ -0,0 +1,54 @@
1
+ require 'ddtrace/context'
2
+ require 'ddtrace/ext/distributed'
3
+
4
+ module Datadog
5
+ # opentracing.io compliant methods for distributing trace context
6
+ # between two or more distributed services. Note this is very close
7
+ # to the HTTPPropagator; the key difference is the way gRPC handles
8
+ # header information (called "metadata") as it operates over HTTP2
9
+ module GRPCPropagator
10
+ include Ext::DistributedTracing
11
+
12
+ def self.inject!(context, metadata)
13
+ metadata[GRPC_METADATA_TRACE_ID] = context.trace_id.to_s
14
+ metadata[GRPC_METADATA_PARENT_ID] = context.span_id.to_s
15
+ metadata[GRPC_METADATA_SAMPLING_PRIORITY] = context.sampling_priority.to_s if context.sampling_priority
16
+ end
17
+
18
+ def self.extract(metadata)
19
+ metadata = Carrier.new(metadata)
20
+ return Datadog::Context.new unless metadata.valid?
21
+ Datadog::Context.new(trace_id: metadata.trace_id,
22
+ span_id: metadata.parent_id,
23
+ sampling_priority: metadata.sampling_priority)
24
+ end
25
+
26
+ # opentracing.io compliant carrier object
27
+ class Carrier
28
+ include Ext::DistributedTracing
29
+
30
+ def initialize(metadata = {})
31
+ @metadata = metadata || {}
32
+ end
33
+
34
+ def valid?
35
+ trace_id && parent_id
36
+ end
37
+
38
+ def trace_id
39
+ value = @metadata[GRPC_METADATA_TRACE_ID].to_i
40
+ value if (1..Span::MAX_ID).cover? value
41
+ end
42
+
43
+ def parent_id
44
+ value = @metadata[GRPC_METADATA_PARENT_ID].to_i
45
+ value if (1..Span::MAX_ID).cover? value
46
+ end
47
+
48
+ def sampling_priority
49
+ value = @metadata[GRPC_METADATA_SAMPLING_PRIORITY]
50
+ value && value.to_i
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,103 @@
1
+ module Datadog
2
+ module Quantization
3
+ # Quantization for HTTP resources
4
+ module Hash
5
+ PLACEHOLDER = '?'.freeze
6
+ EXCLUDE_KEYS = [].freeze
7
+ SHOW_KEYS = [].freeze
8
+ DEFAULT_OPTIONS = {
9
+ exclude: EXCLUDE_KEYS,
10
+ show: SHOW_KEYS,
11
+ placeholder: PLACEHOLDER
12
+ }.freeze
13
+
14
+ module_function
15
+
16
+ def format(hash_obj, options = {})
17
+ options ||= {}
18
+ format!(hash_obj, options)
19
+ rescue StandardError
20
+ options[:placeholder] || PLACEHOLDER
21
+ end
22
+
23
+ def format!(hash_obj, options = {})
24
+ options ||= {}
25
+ options = merge_options(DEFAULT_OPTIONS, options)
26
+ format_hash(hash_obj, options)
27
+ end
28
+
29
+ def format_hash(hash_obj, options = {})
30
+ case hash_obj
31
+ when ::Hash
32
+ return {} if options[:exclude] == :all
33
+ return hash_obj if options[:show] == :all
34
+
35
+ hash_obj.each_with_object({}) do |(key, value), quantized|
36
+ if options[:show].any?(&indifferent_equals(key))
37
+ quantized[key] = value
38
+ elsif options[:exclude].none?(&indifferent_equals(key))
39
+ quantized[key] = format_value(value, options)
40
+ end
41
+ end
42
+ else
43
+ format_value(hash_obj, options)
44
+ end
45
+ end
46
+
47
+ def format_value(value, options = {})
48
+ return value if options[:show] == :all
49
+
50
+ case value
51
+ when ::Hash
52
+ format_hash(value, options)
53
+ when Array
54
+ # If any are objects, format them.
55
+ format_array(value, options)
56
+ else
57
+ options[:placeholder]
58
+ end
59
+ end
60
+
61
+ def format_array(value, options)
62
+ if value.any? { |v| v.class <= ::Hash || v.class <= Array }
63
+ first_entry = format_value(value.first, options)
64
+ value.size > 1 ? [first_entry, options[:placeholder]] : [first_entry]
65
+ # Otherwise short-circuit and return single placeholder
66
+ else
67
+ [options[:placeholder]]
68
+ end
69
+ end
70
+
71
+ def merge_options(original, additional)
72
+ {}.tap do |options|
73
+ # Show
74
+ # If either is :all, value becomes :all
75
+ options[:show] = if original[:show] == :all || additional[:show] == :all
76
+ :all
77
+ else
78
+ (original[:show] || []).dup.concat(additional[:show] || []).uniq
79
+ end
80
+
81
+ # Exclude
82
+ # If either is :all, value becomes :all
83
+ options[:exclude] = if original[:exclude] == :all || additional[:exclude] == :all
84
+ :all
85
+ else
86
+ (original[:exclude] || []).dup.concat(additional[:exclude] || []).uniq
87
+ end
88
+
89
+ options[:placeholder] = additional[:placeholder] || original[:placeholder]
90
+ end
91
+ end
92
+
93
+ def indifferent_equals(value)
94
+ value = convert_value(value)
95
+ ->(compared_value) { value == convert_value(compared_value) }
96
+ end
97
+
98
+ def convert_value(value)
99
+ value.is_a?(Symbol) ? value.to_s : value
100
+ end
101
+ end
102
+ end
103
+ end
@@ -23,6 +23,8 @@ module Datadog
23
23
  attr_accessor :enabled, :writer
24
24
  attr_writer :default_service
25
25
 
26
+ ALLOWED_SPAN_OPTIONS = [:service, :resource, :span_type].freeze
27
+
26
28
  # Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
27
29
  # namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
28
30
  def self.log
@@ -204,12 +206,13 @@ module Datadog
204
206
  # * +tags+: extra tags which should be added to the span.
205
207
  def start_span(name, options = {})
206
208
  start_time = options.fetch(:start_time, Time.now.utc)
209
+
207
210
  tags = options.fetch(:tags, {})
208
211
 
209
212
  opts = options.select do |k, _v|
210
213
  # Filter options, we want no side effects with unexpected args.
211
214
  # Plus, this documents the code (Ruby 2 named args would be better but we're Ruby 1.9 compatible)
212
- [:service, :resource, :span_type].include?(k)
215
+ ALLOWED_SPAN_OPTIONS.include?(k)
213
216
  end
214
217
 
215
218
  ctx, parent = guess_context_and_parent(options[:child_of])
@@ -0,0 +1,21 @@
1
+ module Datadog
2
+ module Utils
3
+ # Common database-related utility functions.
4
+ module Database
5
+ module_function
6
+
7
+ def normalize_vendor(vendor)
8
+ case vendor
9
+ when nil
10
+ 'defaultdb'
11
+ when 'postgresql'
12
+ 'postgres'
13
+ when 'sqlite3'
14
+ 'sqlite'
15
+ else
16
+ vendor
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end