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,30 @@
|
|
1
|
+
require 'ddtrace/contrib/active_record/events/instantiation'
|
2
|
+
require 'ddtrace/contrib/active_record/events/sql'
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module Contrib
|
6
|
+
module ActiveRecord
|
7
|
+
# Defines collection of instrumented ActiveRecord events
|
8
|
+
module Events
|
9
|
+
ALL = [
|
10
|
+
Events::Instantiation,
|
11
|
+
Events::SQL
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def all
|
17
|
+
self::ALL
|
18
|
+
end
|
19
|
+
|
20
|
+
def subscriptions
|
21
|
+
all.collect(&:subscriptions).collect(&:to_a).flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
def subscribe!
|
25
|
+
all.each(&:subscribe!)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'ddtrace/contrib/active_record/event'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module ActiveRecord
|
6
|
+
module Events
|
7
|
+
# Defines instrumentation for instantiation.active_record event
|
8
|
+
module Instantiation
|
9
|
+
include ActiveRecord::Event
|
10
|
+
|
11
|
+
EVENT_NAME = 'instantiation.active_record'.freeze
|
12
|
+
SPAN_NAME = 'active_record.instantiation'.freeze
|
13
|
+
DEFAULT_SERVICE_NAME = 'active_record'.freeze
|
14
|
+
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def supported?
|
18
|
+
Gem.loaded_specs['activerecord'] \
|
19
|
+
&& Gem.loaded_specs['activerecord'].version >= Gem::Version.new('4.2')
|
20
|
+
end
|
21
|
+
|
22
|
+
def event_name
|
23
|
+
self::EVENT_NAME
|
24
|
+
end
|
25
|
+
|
26
|
+
def span_name
|
27
|
+
self::SPAN_NAME
|
28
|
+
end
|
29
|
+
|
30
|
+
def process(span, event, _id, payload)
|
31
|
+
# Inherit service name from parent, if available.
|
32
|
+
span.service = if configuration[:orm_service_name]
|
33
|
+
configuration[:orm_service_name]
|
34
|
+
elsif span.parent
|
35
|
+
span.parent.service
|
36
|
+
else
|
37
|
+
self::DEFAULT_SERVICE_NAME
|
38
|
+
end
|
39
|
+
|
40
|
+
span.resource = payload.fetch(:class_name)
|
41
|
+
span.span_type = 'custom'
|
42
|
+
span.set_tag('active_record.instantiation.class_name', payload.fetch(:class_name))
|
43
|
+
span.set_tag('active_record.instantiation.record_count', payload.fetch(:record_count))
|
44
|
+
rescue StandardError => e
|
45
|
+
Datadog::Tracer.log.debug(e.message)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ddtrace/contrib/active_record/event'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module ActiveRecord
|
6
|
+
module Events
|
7
|
+
# Defines instrumentation for sql.active_record event
|
8
|
+
module SQL
|
9
|
+
include ActiveRecord::Event
|
10
|
+
|
11
|
+
EVENT_NAME = 'sql.active_record'.freeze
|
12
|
+
SPAN_NAME = 'active_record.sql'.freeze
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def event_name
|
17
|
+
self::EVENT_NAME
|
18
|
+
end
|
19
|
+
|
20
|
+
def span_name
|
21
|
+
self::SPAN_NAME
|
22
|
+
end
|
23
|
+
|
24
|
+
def process(span, event, _id, payload)
|
25
|
+
connection_config = Utils.connection_config(payload[:connection_id])
|
26
|
+
span.name = "#{connection_config[:adapter_name]}.query"
|
27
|
+
span.service = configuration[:service_name]
|
28
|
+
span.resource = payload.fetch(:sql)
|
29
|
+
span.span_type = Datadog::Ext::SQL::TYPE
|
30
|
+
|
31
|
+
# Find out if the SQL query has been cached in this request. This meta is really
|
32
|
+
# helpful to users because some spans may have 0ns of duration because the query
|
33
|
+
# is simply cached from memory, so the notification is fired with start == finish.
|
34
|
+
cached = payload[:cached] || (payload[:name] == 'CACHE')
|
35
|
+
|
36
|
+
span.set_tag('active_record.db.vendor', connection_config[:adapter_name])
|
37
|
+
span.set_tag('active_record.db.name', connection_config[:database_name])
|
38
|
+
span.set_tag('active_record.db.cached', cached) if cached
|
39
|
+
span.set_tag('out.host', connection_config[:adapter_host])
|
40
|
+
span.set_tag('out.port', connection_config[:adapter_port])
|
41
|
+
rescue StandardError => e
|
42
|
+
Datadog::Tracer.log.debug(e.message)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'ddtrace/ext/sql'
|
2
2
|
require 'ddtrace/ext/app_types'
|
3
3
|
require 'ddtrace/contrib/active_record/utils'
|
4
|
-
require 'ddtrace/contrib/
|
4
|
+
require 'ddtrace/contrib/active_record/events'
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Contrib
|
@@ -9,10 +9,6 @@ module Datadog
|
|
9
9
|
# Patcher enables patching of 'active_record' module.
|
10
10
|
module Patcher
|
11
11
|
include Base
|
12
|
-
include ActiveSupport::Notifications::Subscriber
|
13
|
-
|
14
|
-
NAME_SQL = 'sql.active_record'.freeze
|
15
|
-
NAME_INSTANTIATION = 'instantiation.active_record'.freeze
|
16
12
|
|
17
13
|
register_as :active_record, auto_patch: false
|
18
14
|
option :service_name, depends_on: [:tracer] do |value|
|
@@ -24,7 +20,7 @@ module Datadog
|
|
24
20
|
option :tracer, default: Datadog.tracer do |value|
|
25
21
|
(value || Datadog.tracer).tap do |v|
|
26
22
|
# Make sure to update tracers of all subscriptions
|
27
|
-
subscriptions.each do |subscription|
|
23
|
+
Events.subscriptions.each do |subscription|
|
28
24
|
subscription.tracer = v
|
29
25
|
end
|
30
26
|
end
|
@@ -32,28 +28,6 @@ module Datadog
|
|
32
28
|
|
33
29
|
@patched = false
|
34
30
|
|
35
|
-
on_subscribe do
|
36
|
-
# sql.active_record
|
37
|
-
subscribe(
|
38
|
-
self::NAME_SQL, # Event name
|
39
|
-
'active_record.sql', # Span name
|
40
|
-
{ service: get_option(:service_name) }, # Span options
|
41
|
-
get_option(:tracer), # Tracer
|
42
|
-
&method(:sql) # Handler
|
43
|
-
)
|
44
|
-
|
45
|
-
# instantiation.active_record
|
46
|
-
if instantiation_tracing_supported?
|
47
|
-
subscribe(
|
48
|
-
self::NAME_INSTANTIATION, # Event name
|
49
|
-
'active_record.instantiation', # Span name
|
50
|
-
{ service: get_option(:service_name) }, # Span options
|
51
|
-
get_option(:tracer), # Tracer
|
52
|
-
&method(:instantiation) # Handler
|
53
|
-
)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
31
|
module_function
|
58
32
|
|
59
33
|
# patched? tells whether patch has been successfully applied
|
@@ -64,7 +38,7 @@ module Datadog
|
|
64
38
|
def patch
|
65
39
|
if !@patched && defined?(::ActiveRecord)
|
66
40
|
begin
|
67
|
-
subscribe!
|
41
|
+
Events.subscribe!
|
68
42
|
@patched = true
|
69
43
|
rescue StandardError => e
|
70
44
|
Datadog::Tracer.log.error("Unable to apply Active Record integration: #{e}")
|
@@ -73,50 +47,6 @@ module Datadog
|
|
73
47
|
|
74
48
|
@patched
|
75
49
|
end
|
76
|
-
|
77
|
-
def instantiation_tracing_supported?
|
78
|
-
Gem.loaded_specs['activerecord'] \
|
79
|
-
&& Gem.loaded_specs['activerecord'].version >= Gem::Version.new('4.2')
|
80
|
-
end
|
81
|
-
|
82
|
-
def sql(span, event, _id, payload)
|
83
|
-
connection_config = Utils.connection_config(payload[:connection_id])
|
84
|
-
span.name = "#{connection_config[:adapter_name]}.query"
|
85
|
-
span.service = get_option(:service_name)
|
86
|
-
span.resource = payload.fetch(:sql)
|
87
|
-
span.span_type = Datadog::Ext::SQL::TYPE
|
88
|
-
|
89
|
-
# Find out if the SQL query has been cached in this request. This meta is really
|
90
|
-
# helpful to users because some spans may have 0ns of duration because the query
|
91
|
-
# is simply cached from memory, so the notification is fired with start == finish.
|
92
|
-
cached = payload[:cached] || (payload[:name] == 'CACHE'.freeze)
|
93
|
-
|
94
|
-
span.set_tag('active_record.db.vendor'.freeze, connection_config[:adapter_name])
|
95
|
-
span.set_tag('active_record.db.name'.freeze, connection_config[:database_name])
|
96
|
-
span.set_tag('active_record.db.cached'.freeze, cached) if cached
|
97
|
-
span.set_tag('out.host'.freeze, connection_config[:adapter_host])
|
98
|
-
span.set_tag('out.port'.freeze, connection_config[:adapter_port])
|
99
|
-
rescue StandardError => e
|
100
|
-
Datadog::Tracer.log.debug(e.message)
|
101
|
-
end
|
102
|
-
|
103
|
-
def instantiation(span, event, _id, payload)
|
104
|
-
# Inherit service name from parent, if available.
|
105
|
-
span.service = if get_option(:orm_service_name)
|
106
|
-
get_option(:orm_service_name)
|
107
|
-
elsif span.parent
|
108
|
-
span.parent.service
|
109
|
-
else
|
110
|
-
'active_record'.freeze
|
111
|
-
end
|
112
|
-
|
113
|
-
span.resource = payload.fetch(:class_name)
|
114
|
-
span.span_type = 'custom'.freeze
|
115
|
-
span.set_tag('active_record.instantiation.class_name'.freeze, payload.fetch(:class_name))
|
116
|
-
span.set_tag('active_record.instantiation.record_count'.freeze, payload.fetch(:record_count))
|
117
|
-
rescue StandardError => e
|
118
|
-
Datadog::Tracer.log.debug(e.message)
|
119
|
-
end
|
120
50
|
end
|
121
51
|
end
|
122
52
|
end
|
@@ -3,20 +3,6 @@ module Datadog
|
|
3
3
|
module ActiveRecord
|
4
4
|
# Common utilities for Rails
|
5
5
|
module Utils
|
6
|
-
# Return a canonical name for a type of database
|
7
|
-
def self.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
|
-
|
20
6
|
def self.adapter_name
|
21
7
|
connection_config[:adapter_name]
|
22
8
|
end
|
@@ -36,7 +22,7 @@ module Datadog
|
|
36
22
|
def self.connection_config(object_id = nil)
|
37
23
|
config = object_id.nil? ? default_connection_config : connection_config_by_id(object_id)
|
38
24
|
{
|
39
|
-
adapter_name: normalize_vendor(config[:adapter]),
|
25
|
+
adapter_name: Datadog::Utils::Database.normalize_vendor(config[:adapter]),
|
40
26
|
adapter_host: config[:host],
|
41
27
|
adapter_port: config[:port],
|
42
28
|
database_name: config[:database]
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'ddtrace/contrib/active_support/notifications/subscriber'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Contrib
|
5
|
+
module ActiveSupport
|
6
|
+
module Notifications
|
7
|
+
# Defines behaviors for an ActiveSupport::Notifications event.
|
8
|
+
# Compose this into a module or class, then define
|
9
|
+
# #event_name, #span_name, and #process. You can then
|
10
|
+
# invoke Event.subscribe! to more easily subscribe to an event.
|
11
|
+
module Event
|
12
|
+
def self.included(base)
|
13
|
+
base.send(:include, Subscriber)
|
14
|
+
base.send(:extend, ClassMethods)
|
15
|
+
base.send(:on_subscribe) { base.subscribe }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Redefines some class behaviors for a Subscriber to make
|
19
|
+
# it a bit simpler for an Event.
|
20
|
+
module ClassMethods
|
21
|
+
def subscribe!
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def subscription(span_name = nil, options = nil, tracer = nil)
|
26
|
+
super(
|
27
|
+
span_name || self.span_name,
|
28
|
+
options || span_options,
|
29
|
+
tracer || self.tracer,
|
30
|
+
&method(:process)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def subscribe(pattern = nil, span_name = nil, options = nil, tracer = nil)
|
35
|
+
if supported?
|
36
|
+
super(
|
37
|
+
pattern || event_name,
|
38
|
+
span_name || self.span_name,
|
39
|
+
options || span_options,
|
40
|
+
tracer || self.tracer,
|
41
|
+
&method(:process)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def supported?
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def span_options
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
def tracer
|
55
|
+
Datadog.tracer
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -27,8 +27,8 @@ module Datadog
|
|
27
27
|
def annotate!(span, pin, context)
|
28
28
|
span.service = pin.service
|
29
29
|
span.span_type = pin.app_type
|
30
|
-
span.name =
|
31
|
-
span.resource =
|
30
|
+
span.name = context.safely(:resource)
|
31
|
+
span.resource = RESOURCE
|
32
32
|
span.set_tag('aws.agent', AGENT)
|
33
33
|
span.set_tag('aws.operation', context.safely(:operation))
|
34
34
|
span.set_tag('aws.region', context.safely(:region))
|
@@ -52,11 +52,11 @@ module Datadog
|
|
52
52
|
remove_method :initialize
|
53
53
|
end
|
54
54
|
|
55
|
-
def initialize(*args
|
55
|
+
def initialize(*args)
|
56
56
|
service = Datadog.configuration[:elasticsearch][:service_name]
|
57
57
|
pin = Datadog::Pin.new(service, app: 'elasticsearch', app_type: Datadog::Ext::AppTypes::DB)
|
58
58
|
pin.onto(self)
|
59
|
-
initialize_without_datadog(*args
|
59
|
+
initialize_without_datadog(*args)
|
60
60
|
end
|
61
61
|
|
62
62
|
alias_method :perform_request_without_datadog, :perform_request
|
@@ -6,7 +6,11 @@ module Datadog
|
|
6
6
|
PLACEHOLDER = '?'.freeze
|
7
7
|
EXCLUDE_KEYS = [].freeze
|
8
8
|
SHOW_KEYS = [:_index, :_type, :_id].freeze
|
9
|
-
DEFAULT_OPTIONS = {
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
exclude: EXCLUDE_KEYS,
|
11
|
+
show: SHOW_KEYS,
|
12
|
+
placeholder: PLACEHOLDER
|
13
|
+
}.freeze
|
10
14
|
|
11
15
|
ID_REGEXP = %r{\/([0-9]+)([\/\?]|$)}
|
12
16
|
ID_PLACEHOLDER = '/?\2'.freeze
|
@@ -25,7 +29,7 @@ module Datadog
|
|
25
29
|
def format_body(body, options = {})
|
26
30
|
format_body!(body, options)
|
27
31
|
rescue StandardError
|
28
|
-
PLACEHOLDER
|
32
|
+
options[:placeholder] || PLACEHOLDER
|
29
33
|
end
|
30
34
|
|
31
35
|
def format_body!(body, options = {})
|
@@ -36,48 +40,12 @@ module Datadog
|
|
36
40
|
|
37
41
|
# Parse each statement and quantize them.
|
38
42
|
statements.collect do |string|
|
39
|
-
reserialize_json(string) do |obj|
|
40
|
-
|
43
|
+
reserialize_json(string, options[:placeholder]) do |obj|
|
44
|
+
Datadog::Quantization::Hash.format(obj, options)
|
41
45
|
end
|
42
46
|
end.join("\n")
|
43
47
|
end
|
44
48
|
|
45
|
-
def format_statement(statement, options = {})
|
46
|
-
return statement if options[:show] == :all
|
47
|
-
|
48
|
-
case statement
|
49
|
-
when Hash
|
50
|
-
statement.each_with_object({}) do |(key, value), quantized|
|
51
|
-
if options[:show].include?(key.to_sym)
|
52
|
-
quantized[key] = value
|
53
|
-
elsif !options[:exclude].include?(key.to_sym)
|
54
|
-
quantized[key] = format_value(value, options)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
else
|
58
|
-
format_value(statement, options)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def format_value(value, options = {})
|
63
|
-
return value if options[:show] == :all
|
64
|
-
|
65
|
-
case value
|
66
|
-
when Hash
|
67
|
-
format_statement(value, options)
|
68
|
-
when Array
|
69
|
-
# If any are objects, format them.
|
70
|
-
if value.any? { |v| v.class <= Hash || v.class <= Array }
|
71
|
-
value.collect { |i| format_value(i, options) }
|
72
|
-
# Otherwise short-circuit and return single placeholder
|
73
|
-
else
|
74
|
-
PLACEHOLDER
|
75
|
-
end
|
76
|
-
else
|
77
|
-
PLACEHOLDER
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
49
|
def merge_options(original, additional)
|
82
50
|
{}.tap do |options|
|
83
51
|
# Show
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'excon'
|
2
|
+
require 'ddtrace/ext/http'
|
3
|
+
require 'ddtrace/ext/net'
|
4
|
+
require 'ddtrace/ext/distributed'
|
5
|
+
require 'ddtrace/propagation/http_propagator'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Contrib
|
9
|
+
module Excon
|
10
|
+
# Middleware implements an excon-middleware for ddtrace instrumentation
|
11
|
+
class Middleware < ::Excon::Middleware::Base
|
12
|
+
SPAN_NAME = 'excon.request'.freeze
|
13
|
+
DEFAULT_ERROR_HANDLER = lambda do |response|
|
14
|
+
Ext::HTTP::ERROR_RANGE.cover?(response[:status])
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(stack, options = {})
|
18
|
+
super(stack)
|
19
|
+
@options = Datadog.configuration[:excon].merge(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def request_call(datum)
|
23
|
+
begin
|
24
|
+
unless datum.key?(:datadog_span)
|
25
|
+
tracer.trace(SPAN_NAME).tap do |span|
|
26
|
+
datum[:datadog_span] = span
|
27
|
+
annotate!(span, datum)
|
28
|
+
propagate!(span, datum) if distributed_tracing?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
rescue StandardError => e
|
32
|
+
Datadog::Tracer.log.debug(e.message)
|
33
|
+
end
|
34
|
+
|
35
|
+
@stack.request_call(datum)
|
36
|
+
end
|
37
|
+
|
38
|
+
def response_call(datum)
|
39
|
+
@stack.response_call(datum).tap do |d|
|
40
|
+
handle_response(d)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def error_call(datum)
|
45
|
+
@stack.error_call(datum).tap do |d|
|
46
|
+
handle_response(d)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns a child class of this trace middleware
|
51
|
+
# With options given as defaults.
|
52
|
+
def self.with(options = {})
|
53
|
+
Class.new(self) do
|
54
|
+
@options = options
|
55
|
+
|
56
|
+
# rubocop:disable Style/TrivialAccessors
|
57
|
+
def self.options
|
58
|
+
@options
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(stack)
|
62
|
+
super(stack, self.class.options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a copy of the default stack with the trace middleware injected
|
68
|
+
def self.around_default_stack
|
69
|
+
::Excon.defaults[:middlewares].dup.tap do |default_stack|
|
70
|
+
# If the default stack contains a version of the trace middleware already...
|
71
|
+
existing_trace_middleware = default_stack.find { |m| m <= Middleware }
|
72
|
+
default_stack.delete(existing_trace_middleware) if existing_trace_middleware
|
73
|
+
|
74
|
+
# Inject after the ResponseParser middleware
|
75
|
+
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
|
76
|
+
default_stack.insert(response_middleware_index + 1, self)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def tracer
|
83
|
+
@options[:tracer]
|
84
|
+
end
|
85
|
+
|
86
|
+
def distributed_tracing?
|
87
|
+
@options[:distributed_tracing] == true && tracer.enabled
|
88
|
+
end
|
89
|
+
|
90
|
+
def error_handler
|
91
|
+
@options[:error_handler] || DEFAULT_ERROR_HANDLER
|
92
|
+
end
|
93
|
+
|
94
|
+
def split_by_domain?
|
95
|
+
@options[:split_by_domain] == true
|
96
|
+
end
|
97
|
+
|
98
|
+
def annotate!(span, datum)
|
99
|
+
span.resource = datum[:method].to_s.upcase
|
100
|
+
span.service = service_name(datum)
|
101
|
+
span.span_type = Ext::HTTP::TYPE
|
102
|
+
span.set_tag(Ext::HTTP::URL, datum[:path])
|
103
|
+
span.set_tag(Ext::HTTP::METHOD, datum[:method].to_s.upcase)
|
104
|
+
span.set_tag(Ext::NET::TARGET_HOST, datum[:host])
|
105
|
+
span.set_tag(Ext::NET::TARGET_PORT, datum[:port].to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def handle_response(datum)
|
109
|
+
if datum.key?(:datadog_span)
|
110
|
+
datum[:datadog_span].tap do |span|
|
111
|
+
return span if span.finished?
|
112
|
+
|
113
|
+
if datum.key?(:response)
|
114
|
+
response = datum[:response]
|
115
|
+
if error_handler.call(response)
|
116
|
+
span.set_error(["Error #{response[:status]}", response[:body]])
|
117
|
+
end
|
118
|
+
span.set_tag(Ext::HTTP::STATUS_CODE, response[:status])
|
119
|
+
end
|
120
|
+
span.set_error(datum[:error]) if datum.key?(:error)
|
121
|
+
span.finish
|
122
|
+
datum.delete(:datadog_span)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
rescue StandardError => e
|
126
|
+
Datadog::Tracer.log.debug(e.message)
|
127
|
+
end
|
128
|
+
|
129
|
+
def propagate!(span, datum)
|
130
|
+
Datadog::HTTPPropagator.inject!(span.context, datum[:headers])
|
131
|
+
end
|
132
|
+
|
133
|
+
def service_name(datum)
|
134
|
+
# TODO: Change this to implement more sensible multiplexing
|
135
|
+
split_by_domain? ? datum[:host] : @options[:service_name]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|