ddtrace 0.12.1 → 0.13.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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