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.
- checksums.yaml +4 -4
- data/.env +11 -21
- data/.rubocop.yml +1 -4
- data/Appraisals +75 -439
- data/CHANGELOG.md +16 -19
- data/Rakefile +89 -259
- data/circle.yml +69 -0
- data/ddtrace.gemspec +6 -6
- data/docker-compose.yml +37 -222
- data/docs/GettingStarted.md +260 -19
- data/gemfiles/contrib.gemfile +5 -0
- data/gemfiles/contrib_old.gemfile +4 -1
- data/gemfiles/rails30_postgres.gemfile +0 -1
- data/gemfiles/rails30_postgres_sidekiq.gemfile +0 -1
- data/gemfiles/rails32_mysql2.gemfile +0 -1
- data/gemfiles/rails32_postgres.gemfile +0 -1
- data/gemfiles/rails32_postgres_redis.gemfile +0 -1
- data/gemfiles/rails32_postgres_sidekiq.gemfile +0 -1
- data/gemfiles/rails5_mysql2.gemfile +1 -1
- data/gemfiles/rails5_postgres.gemfile +1 -1
- data/gemfiles/rails5_postgres_redis.gemfile +1 -1
- data/gemfiles/rails5_postgres_sidekiq.gemfile +1 -1
- data/lib/ddtrace.rb +6 -0
- data/lib/ddtrace/configuration.rb +2 -2
- data/lib/ddtrace/contrib/active_model_serializers/event.rb +57 -0
- data/lib/ddtrace/contrib/active_model_serializers/events.rb +30 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +32 -0
- data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +35 -0
- data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +62 -0
- data/lib/ddtrace/contrib/active_record/event.rb +30 -0
- data/lib/ddtrace/contrib/active_record/events.rb +30 -0
- data/lib/ddtrace/contrib/active_record/events/instantiation.rb +51 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +48 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +3 -73
- data/lib/ddtrace/contrib/active_record/utils.rb +1 -15
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +62 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +2 -2
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -2
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +8 -40
- data/lib/ddtrace/contrib/excon/middleware.rb +140 -0
- data/lib/ddtrace/contrib/excon/patcher.rb +50 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +65 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +49 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +66 -0
- data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +49 -0
- data/lib/ddtrace/contrib/grpc/patcher.rb +62 -0
- data/lib/ddtrace/contrib/http/patcher.rb +16 -18
- data/lib/ddtrace/contrib/racecar/event.rb +61 -0
- data/lib/ddtrace/contrib/racecar/events.rb +30 -0
- data/lib/ddtrace/contrib/racecar/events/batch.rb +27 -0
- data/lib/ddtrace/contrib/racecar/events/message.rb +27 -0
- data/lib/ddtrace/contrib/racecar/patcher.rb +6 -52
- data/lib/ddtrace/contrib/rack/middlewares.rb +65 -11
- data/lib/ddtrace/contrib/rack/patcher.rb +16 -0
- data/lib/ddtrace/contrib/rack/request_queue.rb +34 -0
- data/lib/ddtrace/contrib/rails/action_view.rb +65 -0
- data/lib/ddtrace/contrib/rails/active_support.rb +8 -9
- data/lib/ddtrace/contrib/rails/core_extensions.rb +115 -74
- data/lib/ddtrace/contrib/rake/instrumentation.rb +70 -0
- data/lib/ddtrace/contrib/rake/patcher.rb +53 -0
- data/lib/ddtrace/contrib/sequel/database.rb +58 -0
- data/lib/ddtrace/contrib/sequel/dataset.rb +59 -0
- data/lib/ddtrace/contrib/sequel/patcher.rb +56 -0
- data/lib/ddtrace/contrib/sequel/utils.rb +28 -0
- data/lib/ddtrace/ext/distributed.rb +5 -0
- data/lib/ddtrace/ext/grpc.rb +7 -0
- data/lib/ddtrace/ext/http.rb +35 -5
- data/lib/ddtrace/propagation/grpc_propagator.rb +54 -0
- data/lib/ddtrace/quantization/hash.rb +89 -0
- data/lib/ddtrace/tracer.rb +1 -4
- data/lib/ddtrace/utils.rb +4 -10
- data/lib/ddtrace/utils/database.rb +21 -0
- data/lib/ddtrace/version.rb +3 -3
- metadata +38 -13
- data/.circleci/config.yml +0 -456
- data/.circleci/images/primary/Dockerfile-1.9.3 +0 -69
- data/.circleci/images/primary/Dockerfile-2.0.0 +0 -69
- data/.circleci/images/primary/Dockerfile-2.1.10 +0 -69
- data/.circleci/images/primary/Dockerfile-2.2.10 +0 -69
- data/.circleci/images/primary/Dockerfile-2.3.7 +0 -73
- data/.circleci/images/primary/Dockerfile-2.4.4 +0 -73
- 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
|
data/lib/ddtrace/ext/http.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/ddtrace/tracer.rb
CHANGED
@@ -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
|
-
|
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 = '...'
|
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
|
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
|