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.
- 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
|