ddtrace 0.12.1 → 0.13.0.beta1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.env +11 -21
  3. data/.rubocop.yml +1 -4
  4. data/Appraisals +75 -439
  5. data/CHANGELOG.md +16 -19
  6. data/Rakefile +89 -259
  7. data/circle.yml +69 -0
  8. data/ddtrace.gemspec +6 -6
  9. data/docker-compose.yml +37 -222
  10. data/docs/GettingStarted.md +260 -19
  11. data/gemfiles/contrib.gemfile +5 -0
  12. data/gemfiles/contrib_old.gemfile +4 -1
  13. data/gemfiles/rails30_postgres.gemfile +0 -1
  14. data/gemfiles/rails30_postgres_sidekiq.gemfile +0 -1
  15. data/gemfiles/rails32_mysql2.gemfile +0 -1
  16. data/gemfiles/rails32_postgres.gemfile +0 -1
  17. data/gemfiles/rails32_postgres_redis.gemfile +0 -1
  18. data/gemfiles/rails32_postgres_sidekiq.gemfile +0 -1
  19. data/gemfiles/rails5_mysql2.gemfile +1 -1
  20. data/gemfiles/rails5_postgres.gemfile +1 -1
  21. data/gemfiles/rails5_postgres_redis.gemfile +1 -1
  22. data/gemfiles/rails5_postgres_sidekiq.gemfile +1 -1
  23. data/lib/ddtrace.rb +6 -0
  24. data/lib/ddtrace/configuration.rb +2 -2
  25. data/lib/ddtrace/contrib/active_model_serializers/event.rb +57 -0
  26. data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
  27. data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
  28. data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
  29. data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +62 -0
  30. data/lib/ddtrace/contrib/active_record/event.rb +30 -0
  31. data/lib/ddtrace/contrib/active_record/events.rb +30 -0
  32. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +51 -0
  33. data/lib/ddtrace/contrib/active_record/events/sql.rb +48 -0
  34. data/lib/ddtrace/contrib/active_record/patcher.rb +3 -73
  35. data/lib/ddtrace/contrib/active_record/utils.rb +1 -15
  36. data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
  37. data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -2
  38. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -2
  39. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +8 -40
  40. data/lib/ddtrace/contrib/excon/middleware.rb +140 -0
  41. data/lib/ddtrace/contrib/excon/patcher.rb +50 -0
  42. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +65 -0
  43. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +49 -0
  44. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +66 -0
  45. data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
  46. data/lib/ddtrace/contrib/grpc/patcher.rb +62 -0
  47. data/lib/ddtrace/contrib/http/patcher.rb +16 -18
  48. data/lib/ddtrace/contrib/racecar/event.rb +61 -0
  49. data/lib/ddtrace/contrib/racecar/events.rb +30 -0
  50. data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
  51. data/lib/ddtrace/contrib/racecar/events/message.rb +27 -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_view.rb +65 -0
  57. data/lib/ddtrace/contrib/rails/active_support.rb +8 -9
  58. data/lib/ddtrace/contrib/rails/core_extensions.rb +115 -74
  59. data/lib/ddtrace/contrib/rake/instrumentation.rb +70 -0
  60. data/lib/ddtrace/contrib/rake/patcher.rb +53 -0
  61. data/lib/ddtrace/contrib/sequel/database.rb +58 -0
  62. data/lib/ddtrace/contrib/sequel/dataset.rb +59 -0
  63. data/lib/ddtrace/contrib/sequel/patcher.rb +56 -0
  64. data/lib/ddtrace/contrib/sequel/utils.rb +28 -0
  65. data/lib/ddtrace/ext/distributed.rb +5 -0
  66. data/lib/ddtrace/ext/grpc.rb +7 -0
  67. data/lib/ddtrace/ext/http.rb +35 -5
  68. data/lib/ddtrace/propagation/grpc_propagator.rb +54 -0
  69. data/lib/ddtrace/quantization/hash.rb +89 -0
  70. data/lib/ddtrace/tracer.rb +1 -4
  71. data/lib/ddtrace/utils.rb +4 -10
  72. data/lib/ddtrace/utils/database.rb +21 -0
  73. data/lib/ddtrace/version.rb +3 -3
  74. metadata +38 -13
  75. data/.circleci/config.yml +0 -456
  76. data/.circleci/images/primary/Dockerfile-1.9.3 +0 -69
  77. data/.circleci/images/primary/Dockerfile-2.0.0 +0 -69
  78. data/.circleci/images/primary/Dockerfile-2.1.10 +0 -69
  79. data/.circleci/images/primary/Dockerfile-2.2.10 +0 -69
  80. data/.circleci/images/primary/Dockerfile-2.3.7 +0 -73
  81. data/.circleci/images/primary/Dockerfile-2.4.4 +0 -73
  82. data/lib/ddtrace/contrib/rails/action_controller_patch.rb +0 -77
@@ -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
@@ -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,89 @@
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].include?(key.to_sym)
37
+ quantized[key] = value
38
+ elsif !options[:exclude].include?(key.to_sym)
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
+ if value.any? { |v| v.class <= ::Hash || v.class <= Array }
56
+ value.collect { |i| format_value(i, options) }
57
+ # Otherwise short-circuit and return single placeholder
58
+ else
59
+ [options[:placeholder]]
60
+ end
61
+ else
62
+ options[:placeholder]
63
+ end
64
+ end
65
+
66
+ def merge_options(original, additional)
67
+ {}.tap do |options|
68
+ # Show
69
+ # If either is :all, value becomes :all
70
+ options[:show] = if original[:show] == :all || additional[:show] == :all
71
+ :all
72
+ else
73
+ (original[:show] || []).dup.concat(additional[:show] || []).uniq
74
+ end
75
+
76
+ # Exclude
77
+ # If either is :all, value becomes :all
78
+ options[:exclude] = if original[:exclude] == :all || additional[:exclude] == :all
79
+ :all
80
+ else
81
+ (original[:exclude] || []).dup.concat(additional[:exclude] || []).uniq
82
+ end
83
+
84
+ options[:placeholder] = additional[:placeholder] || original[:placeholder]
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -23,8 +23,6 @@ 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
-
28
26
  # Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
29
27
  # namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
30
28
  def self.log
@@ -206,13 +204,12 @@ module Datadog
206
204
  # * +tags+: extra tags which should be added to the span.
207
205
  def start_span(name, options = {})
208
206
  start_time = options.fetch(:start_time, Time.now.utc)
209
-
210
207
  tags = options.fetch(:tags, {})
211
208
 
212
209
  opts = options.select do |k, _v|
213
210
  # Filter options, we want no side effects with unexpected args.
214
211
  # Plus, this documents the code (Ruby 2 named args would be better but we're Ruby 1.9 compatible)
215
- ALLOWED_SPAN_OPTIONS.include?(k)
212
+ [:service, :resource, :span_type].include?(k)
216
213
  end
217
214
 
218
215
  ctx, parent = guess_context_and_parent(options[:child_of])
data/lib/ddtrace/utils.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ddtrace/utils/database'
2
+
1
3
  module Datadog
2
4
  # Utils contains low-level utilities, typically to provide pseudo-random trace IDs.
3
5
  module Utils
@@ -26,20 +28,12 @@ module Datadog
26
28
 
27
29
  reset!
28
30
 
29
- def self.truncate(value, size, omission = '...'.freeze)
31
+ def self.truncate(value, size, omission = '...')
30
32
  string = value.to_s
31
33
 
32
34
  return string if string.size <= size
33
35
 
34
- string = string.slice(0, size - 1)
35
-
36
- if size < omission.size
37
- string[0, size] = omission
38
- else
39
- string[size - omission.size, size] = omission
40
- end
41
-
42
- string
36
+ string.slice(0, size - omission.size) + omission
43
37
  end
44
38
 
45
39
  def self.utf8_encode(str, options = {})
@@ -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
@@ -1,9 +1,9 @@
1
1
  module Datadog
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 12
5
- PATCH = 1
6
- PRE = nil
4
+ MINOR = 13
5
+ PATCH = 0
6
+ PRE = 'beta1'.freeze
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
9
9
  end