ddtrace 0.12.0.beta2 → 0.12.0.rc1
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/Appraisals +8 -8
- data/CHANGELOG.md +293 -0
- data/README.md +11 -114
- data/Rakefile +26 -18
- data/docs/GettingStarted.md +704 -453
- data/gemfiles/contrib.gemfile +2 -2
- data/gemfiles/rails4_mysql2.gemfile +1 -1
- data/gemfiles/rails5_mysql2.gemfile +2 -2
- 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 +1 -0
- data/lib/ddtrace/context.rb +96 -34
- data/lib/ddtrace/context_flush.rb +132 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +55 -70
- data/lib/ddtrace/contrib/active_record/utils.rb +83 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +66 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +155 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +89 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +1 -1
- data/lib/ddtrace/contrib/racecar/patcher.rb +43 -19
- data/lib/ddtrace/contrib/rack/middlewares.rb +58 -11
- data/lib/ddtrace/contrib/rack/patcher.rb +18 -11
- data/lib/ddtrace/contrib/rails/action_controller.rb +9 -11
- data/lib/ddtrace/contrib/rails/action_view.rb +5 -1
- data/lib/ddtrace/contrib/rails/active_support.rb +6 -2
- data/lib/ddtrace/contrib/rails/core_extensions.rb +280 -215
- data/lib/ddtrace/contrib/rails/framework.rb +38 -23
- data/lib/ddtrace/contrib/rails/middlewares.rb +7 -2
- data/lib/ddtrace/contrib/rails/patcher.rb +9 -6
- data/lib/ddtrace/contrib/rails/railtie.rb +4 -2
- data/lib/ddtrace/contrib/rails/utils.rb +9 -40
- data/lib/ddtrace/patcher.rb +32 -10
- data/lib/ddtrace/quantization/http.rb +86 -0
- data/lib/ddtrace/tracer.rb +29 -2
- data/lib/ddtrace/transport.rb +33 -20
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/writer.rb +11 -5
- metadata +8 -3
- data/lib/ddtrace/contrib/rails/active_record.rb +0 -80
data/gemfiles/contrib.gemfile
CHANGED
@@ -13,13 +13,13 @@ gem "redis", "< 4.0"
|
|
13
13
|
gem "hiredis"
|
14
14
|
gem "sinatra"
|
15
15
|
gem "sqlite3"
|
16
|
-
gem "activerecord"
|
16
|
+
gem "activerecord", "< 5.1.5"
|
17
17
|
gem "sidekiq"
|
18
18
|
gem "aws-sdk"
|
19
19
|
gem "sucker_punch"
|
20
20
|
gem "dalli"
|
21
21
|
gem "resque", "< 2.0"
|
22
22
|
gem "racecar", ">= 0.3.5"
|
23
|
-
gem "mysql2", platform: :ruby
|
23
|
+
gem "mysql2", "< 0.5", platform: :ruby
|
24
24
|
|
25
25
|
gemspec path: "../"
|
@@ -4,7 +4,7 @@ source "https://rubygems.org"
|
|
4
4
|
|
5
5
|
gem "pry-nav", git: "https://github.com/nixme/pry-nav.git", branch: "master"
|
6
6
|
gem "rails", "4.2.7.1"
|
7
|
-
gem "mysql2", platform: :ruby
|
7
|
+
gem "mysql2", "< 0.5", platform: :ruby
|
8
8
|
gem "activerecord-jdbcmysql-adapter", platform: :jruby
|
9
9
|
|
10
10
|
gemspec path: "../"
|
data/lib/ddtrace.rb
CHANGED
data/lib/ddtrace/context.rb
CHANGED
@@ -13,23 +13,22 @@ module Datadog
|
|
13
13
|
# \Context, it will be related to the original trace.
|
14
14
|
#
|
15
15
|
# This data structure is thread-safe.
|
16
|
+
# rubocop:disable Metrics/ClassLength
|
16
17
|
class Context
|
18
|
+
# 100k spans is about a 100Mb footprint
|
19
|
+
DEFAULT_MAX_LENGTH = 100_000
|
20
|
+
|
21
|
+
attr_reader :max_length
|
22
|
+
|
17
23
|
# Initialize a new thread-safe \Context.
|
18
24
|
def initialize(options = {})
|
19
25
|
@mutex = Mutex.new
|
26
|
+
# max_length is the amount of spans above which, for a given trace,
|
27
|
+
# the context will simply drop and ignore spans, avoiding high memory usage.
|
28
|
+
@max_length = options.fetch(:max_length, DEFAULT_MAX_LENGTH)
|
20
29
|
reset(options)
|
21
30
|
end
|
22
31
|
|
23
|
-
def reset(options = {})
|
24
|
-
@trace = []
|
25
|
-
@parent_trace_id = options.fetch(:trace_id, nil)
|
26
|
-
@parent_span_id = options.fetch(:span_id, nil)
|
27
|
-
@sampled = options.fetch(:sampled, false)
|
28
|
-
@sampling_priority = options.fetch(:sampling_priority, nil)
|
29
|
-
@finished_spans = 0
|
30
|
-
@current_span = nil
|
31
|
-
end
|
32
|
-
|
33
32
|
def trace_id
|
34
33
|
@mutex.synchronize do
|
35
34
|
@parent_trace_id
|
@@ -64,20 +63,19 @@ module Datadog
|
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
67
|
-
def set_current_span(span)
|
68
|
-
@current_span = span
|
69
|
-
if span
|
70
|
-
@parent_trace_id = span.trace_id
|
71
|
-
@parent_span_id = span.span_id
|
72
|
-
@sampled = span.sampled
|
73
|
-
else
|
74
|
-
@parent_span_id = nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
66
|
# Add a span to the context trace list, keeping it as the last active span.
|
79
67
|
def add_span(span)
|
80
68
|
@mutex.synchronize do
|
69
|
+
# If hitting the hard limit, just drop spans. This is really a rare case
|
70
|
+
# as it means despite the soft limit, the hard limit is reached, so the trace
|
71
|
+
# by default has 10000 spans, all of which belong to unfinished parts of a
|
72
|
+
# larger trace. This is a catch-all to reduce global memory usage.
|
73
|
+
if @max_length > 0 && @trace.length >= @max_length
|
74
|
+
Datadog::Tracer.log.debug("context full, ignoring span #{span.name}")
|
75
|
+
# Detach the span from any context, it's being dropped and ignored.
|
76
|
+
span.context = nil
|
77
|
+
return
|
78
|
+
end
|
81
79
|
set_current_span(span)
|
82
80
|
@trace << span
|
83
81
|
span.context = self
|
@@ -105,12 +103,6 @@ module Datadog
|
|
105
103
|
end
|
106
104
|
end
|
107
105
|
|
108
|
-
# Returns if the trace for the current Context is finished or not.
|
109
|
-
# Low-level internal function, not thread-safe.
|
110
|
-
def check_finished_spans
|
111
|
-
@finished_spans > 0 && @trace.length == @finished_spans
|
112
|
-
end
|
113
|
-
|
114
106
|
# Returns if the trace for the current Context is finished or not. A \Context
|
115
107
|
# is considered finished if all spans in this context are finished.
|
116
108
|
def finished?
|
@@ -135,14 +127,16 @@ module Datadog
|
|
135
127
|
# This operation is thread-safe.
|
136
128
|
def get
|
137
129
|
@mutex.synchronize do
|
138
|
-
return nil, nil unless check_finished_spans
|
139
|
-
|
140
130
|
trace = @trace
|
141
131
|
sampled = @sampled
|
132
|
+
|
142
133
|
attach_sampling_priority if sampled && @sampling_priority
|
143
134
|
|
135
|
+
# still return sampled attribute, even if context is not finished
|
136
|
+
return nil, sampled unless check_finished_spans()
|
137
|
+
|
144
138
|
reset
|
145
|
-
|
139
|
+
[trace, sampled]
|
146
140
|
end
|
147
141
|
end
|
148
142
|
|
@@ -154,6 +148,35 @@ module Datadog
|
|
154
148
|
end
|
155
149
|
end
|
156
150
|
|
151
|
+
private
|
152
|
+
|
153
|
+
def reset(options = {})
|
154
|
+
@trace = []
|
155
|
+
@parent_trace_id = options.fetch(:trace_id, nil)
|
156
|
+
@parent_span_id = options.fetch(:span_id, nil)
|
157
|
+
@sampled = options.fetch(:sampled, false)
|
158
|
+
@sampling_priority = options.fetch(:sampling_priority, nil)
|
159
|
+
@finished_spans = 0
|
160
|
+
@current_span = nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def set_current_span(span)
|
164
|
+
@current_span = span
|
165
|
+
if span
|
166
|
+
@parent_trace_id = span.trace_id
|
167
|
+
@parent_span_id = span.span_id
|
168
|
+
@sampled = span.sampled
|
169
|
+
else
|
170
|
+
@parent_span_id = nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns if the trace for the current Context is finished or not.
|
175
|
+
# Low-level internal function, not thread-safe.
|
176
|
+
def check_finished_spans
|
177
|
+
@finished_spans > 0 && @trace.length == @finished_spans
|
178
|
+
end
|
179
|
+
|
157
180
|
def attach_sampling_priority
|
158
181
|
@trace.first.set_metric(
|
159
182
|
Ext::DistributedTracing::SAMPLING_PRIORITY_KEY,
|
@@ -161,10 +184,49 @@ module Datadog
|
|
161
184
|
)
|
162
185
|
end
|
163
186
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
187
|
+
# Return the start time of the root span, or nil if there are no spans or this is undefined.
|
188
|
+
def start_time
|
189
|
+
@mutex.synchronize do
|
190
|
+
return nil if @trace.empty?
|
191
|
+
@trace[0].start_time
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Return the length of the current trace held by this context.
|
196
|
+
def length
|
197
|
+
@mutex.synchronize do
|
198
|
+
@trace.length
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Iterate on each span within the trace. This is thread safe.
|
203
|
+
def each_span
|
204
|
+
@mutex.synchronize do
|
205
|
+
@trace.each do |span|
|
206
|
+
yield span
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Delete any span matching the condition. This is thread safe.
|
212
|
+
def delete_span_if
|
213
|
+
@mutex.synchronize do
|
214
|
+
@trace.delete_if do |span|
|
215
|
+
finished = span.finished?
|
216
|
+
delete_span = yield span
|
217
|
+
if delete_span
|
218
|
+
# We need to detach the span from the context, else, some code
|
219
|
+
# finishing it afterwards would mess up with the number of
|
220
|
+
# finished_spans and possibly cause other side effects.
|
221
|
+
span.context = nil
|
222
|
+
# Acknowledge there's one span less to finish, if needed.
|
223
|
+
# It's very important to keep this balanced.
|
224
|
+
@finished_spans -= 1 if finished
|
225
|
+
end
|
226
|
+
delete_span
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
168
230
|
end
|
169
231
|
|
170
232
|
# ThreadLocalContext can be used as a tracer global reference to create
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'ddtrace/context'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
# \ContextFlush is used to cap context size and avoid it using too much memory.
|
7
|
+
# It performs memory flushes when required.
|
8
|
+
class ContextFlush
|
9
|
+
# by default, soft and hard limits are the same
|
10
|
+
DEFAULT_MAX_SPANS_BEFORE_PARTIAL_FLUSH = Datadog::Context::DEFAULT_MAX_LENGTH
|
11
|
+
# by default, never do a partial flush
|
12
|
+
DEFAULT_MIN_SPANS_BEFORE_PARTIAL_FLUSH = Datadog::Context::DEFAULT_MAX_LENGTH
|
13
|
+
# timeout should be lower than the trace agent window
|
14
|
+
DEFAULT_PARTIAL_FLUSH_TIMEOUT = 10
|
15
|
+
|
16
|
+
private_constant :DEFAULT_MAX_SPANS_BEFORE_PARTIAL_FLUSH
|
17
|
+
private_constant :DEFAULT_MIN_SPANS_BEFORE_PARTIAL_FLUSH
|
18
|
+
private_constant :DEFAULT_PARTIAL_FLUSH_TIMEOUT
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
# max_spans_before_partial_flush is the amount of spans collected before
|
22
|
+
# the context starts to partially flush parts of traces. With a setting of 10k,
|
23
|
+
# the memory overhead is about 10Mb per thread/context (depends on spans metadata,
|
24
|
+
# this is just an order of magnitude).
|
25
|
+
@max_spans_before_partial_flush = options.fetch(:max_spans_before_partial_flush,
|
26
|
+
DEFAULT_MAX_SPANS_BEFORE_PARTIAL_FLUSH)
|
27
|
+
# min_spans_before_partial_flush is the minimum number of spans required
|
28
|
+
# for a partial flush to happen on a timeout. This is to prevent partial flush
|
29
|
+
# of traces which last a very long time but yet have few spans.
|
30
|
+
@min_spans_before_partial_flush = options.fetch(:min_spans_before_partial_flush,
|
31
|
+
DEFAULT_MIN_SPANS_BEFORE_PARTIAL_FLUSH)
|
32
|
+
# partial_flush_timeout is the limit (in seconds) above which the context
|
33
|
+
# considers flushing parts of the trace. Partial flushes should not be done too
|
34
|
+
# late else the agent rejects them with a "too far in the past" error.
|
35
|
+
@partial_flush_timeout = options.fetch(:partial_flush_timeout,
|
36
|
+
DEFAULT_PARTIAL_FLUSH_TIMEOUT)
|
37
|
+
@partial_traces = []
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_children(m, spans, ids, leaf)
|
41
|
+
spans << leaf
|
42
|
+
ids.add(leaf.span_id)
|
43
|
+
|
44
|
+
if m[leaf.span_id]
|
45
|
+
m[leaf.span_id].each do |sub|
|
46
|
+
add_children(m, spans, ids, sub)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def partial_traces(context)
|
52
|
+
# 1st step, taint all parents of an unfinished span as unflushable
|
53
|
+
unflushable_ids = Set.new
|
54
|
+
|
55
|
+
context.send(:each_span) do |span|
|
56
|
+
next if span.finished? || unflushable_ids.include?(span.span_id)
|
57
|
+
unflushable_ids.add span.span_id
|
58
|
+
while span.parent
|
59
|
+
span = span.parent
|
60
|
+
unflushable_ids.add span.span_id
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# 2nd step, find all spans which are at the border between flushable and unflushable
|
65
|
+
# Along the road, collect a reverse-tree which allows direct walking from parents to
|
66
|
+
# children but only for the ones we're interested it.
|
67
|
+
roots = []
|
68
|
+
children_map = {}
|
69
|
+
context.send(:each_span) do |span|
|
70
|
+
# There's no point in trying to put the real root in those partial roots, if
|
71
|
+
# it's flushable, the default algorithm would figure way more quickly.
|
72
|
+
if span.parent && !unflushable_ids.include?(span.span_id)
|
73
|
+
if unflushable_ids.include?(span.parent.span_id)
|
74
|
+
# span is flushable but is parent is not
|
75
|
+
roots << span
|
76
|
+
else
|
77
|
+
# span is flushable and its parent is too, build the reverse
|
78
|
+
# parent to child map for this one, it will be useful
|
79
|
+
children_map[span.parent.span_id] ||= []
|
80
|
+
children_map[span.parent.span_id] << span
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# 3rd step, find all children, as this can be costly, only perform it for partial roots
|
86
|
+
partial_traces = []
|
87
|
+
all_ids = Set.new
|
88
|
+
roots.each do |root|
|
89
|
+
spans = []
|
90
|
+
add_children(children_map, spans, all_ids, root)
|
91
|
+
partial_traces << spans
|
92
|
+
end
|
93
|
+
|
94
|
+
return [nil, nil] if partial_traces.empty?
|
95
|
+
[partial_traces, all_ids]
|
96
|
+
end
|
97
|
+
|
98
|
+
def partial_flush(context)
|
99
|
+
traces, flushed_ids = partial_traces(context)
|
100
|
+
return nil unless traces && flushed_ids
|
101
|
+
|
102
|
+
# We need to reject by span ID and not by value, because a span
|
103
|
+
# value may be altered (typical example: it's finished by some other thread)
|
104
|
+
# since we lock only the context, not all the spans which belong to it.
|
105
|
+
context.send(:delete_span_if) { |span| flushed_ids.include? span.span_id }
|
106
|
+
traces
|
107
|
+
end
|
108
|
+
|
109
|
+
# Performs an operation which each partial trace it can get from the context.
|
110
|
+
def each_partial_trace(context)
|
111
|
+
start_time = context.send(:start_time)
|
112
|
+
length = context.send(:length)
|
113
|
+
# Stop and do not flush anything if there are not enough spans.
|
114
|
+
return if length <= @min_spans_before_partial_flush
|
115
|
+
# If there are enough spans, but not too many, check for start time.
|
116
|
+
# If timeout is not given or 0, then wait
|
117
|
+
return if length <= @max_spans_before_partial_flush &&
|
118
|
+
(@partial_flush_timeout.nil? || @partial_flush_timeout <= 0 ||
|
119
|
+
(start_time && start_time > Time.now.utc - @partial_flush_timeout))
|
120
|
+
# Here, either the trace is old or we have too many spans, flush it.
|
121
|
+
traces = partial_flush(context)
|
122
|
+
return unless traces
|
123
|
+
traces.each do |trace|
|
124
|
+
yield trace
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private :add_children
|
129
|
+
private :partial_traces
|
130
|
+
private :partial_flush
|
131
|
+
end
|
132
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'ddtrace/ext/sql'
|
2
2
|
require 'ddtrace/ext/app_types'
|
3
|
+
require 'ddtrace/contrib/active_record/utils'
|
4
|
+
require 'ddtrace/contrib/active_support/notifications/subscriber'
|
3
5
|
|
4
6
|
module Datadog
|
5
7
|
module Contrib
|
@@ -7,15 +9,51 @@ module Datadog
|
|
7
9
|
# Patcher enables patching of 'active_record' module.
|
8
10
|
module Patcher
|
9
11
|
include Base
|
12
|
+
include ActiveSupport::Notifications::Subscriber
|
13
|
+
|
14
|
+
NAME_SQL = 'sql.active_record'.freeze
|
15
|
+
NAME_INSTANTIATION = 'instantiation.active_record'.freeze
|
16
|
+
|
10
17
|
register_as :active_record, auto_patch: false
|
11
|
-
option :service_name do |value|
|
12
|
-
value.tap
|
18
|
+
option :service_name, depends_on: [:tracer] do |value|
|
19
|
+
(value || Utils.adapter_name).tap do |v|
|
20
|
+
get_option(:tracer).set_service_info(v, 'active_record', Ext::AppTypes::DB)
|
21
|
+
end
|
13
22
|
end
|
14
23
|
option :orm_service_name
|
15
|
-
option :tracer, default: Datadog.tracer
|
24
|
+
option :tracer, default: Datadog.tracer do |value|
|
25
|
+
(value || Datadog.tracer).tap do |v|
|
26
|
+
# Make sure to update tracers of all subscriptions
|
27
|
+
subscriptions.each do |subscription|
|
28
|
+
subscription.tracer = v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
16
32
|
|
17
33
|
@patched = false
|
18
34
|
|
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
|
+
|
19
57
|
module_function
|
20
58
|
|
21
59
|
# patched? tells whether patch has been successfully applied
|
@@ -26,9 +64,7 @@ module Datadog
|
|
26
64
|
def patch
|
27
65
|
if !@patched && defined?(::ActiveRecord)
|
28
66
|
begin
|
29
|
-
|
30
|
-
|
31
|
-
patch_active_record
|
67
|
+
subscribe!
|
32
68
|
@patched = true
|
33
69
|
rescue StandardError => e
|
34
70
|
Datadog::Tracer.log.error("Unable to apply Active Record integration: #{e}")
|
@@ -38,84 +74,33 @@ module Datadog
|
|
38
74
|
@patched
|
39
75
|
end
|
40
76
|
|
41
|
-
def patch_active_record
|
42
|
-
# subscribe when the active record query has been processed
|
43
|
-
::ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
|
44
|
-
sql(*args)
|
45
|
-
end
|
46
|
-
|
47
|
-
if instantiation_tracing_supported?
|
48
|
-
# subscribe when the active record instantiates objects
|
49
|
-
::ActiveSupport::Notifications.subscribe('instantiation.active_record') do |*args|
|
50
|
-
instantiation(*args)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
77
|
def instantiation_tracing_supported?
|
56
78
|
Gem.loaded_specs['activerecord'] \
|
57
79
|
&& Gem.loaded_specs['activerecord'].version >= Gem::Version.new('4.2')
|
58
80
|
end
|
59
81
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.adapter_name
|
70
|
-
@adapter_name ||= Datadog::Contrib::Rails::Utils.adapter_name
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.database_name
|
74
|
-
@database_name ||= Datadog::Contrib::Rails::Utils.database_name
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.adapter_host
|
78
|
-
@adapter_host ||= Datadog::Contrib::Rails::Utils.adapter_host
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.adapter_port
|
82
|
-
@adapter_port ||= Datadog::Contrib::Rails::Utils.adapter_port
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.sql(_name, start, finish, _id, payload)
|
86
|
-
span = get_option(:tracer).trace(
|
87
|
-
"#{adapter_name}.query",
|
88
|
-
resource: payload.fetch(:sql),
|
89
|
-
service: database_service_name,
|
90
|
-
span_type: Datadog::Ext::SQL::TYPE
|
91
|
-
)
|
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
|
92
88
|
|
93
89
|
# Find out if the SQL query has been cached in this request. This meta is really
|
94
90
|
# helpful to users because some spans may have 0ns of duration because the query
|
95
91
|
# is simply cached from memory, so the notification is fired with start == finish.
|
96
92
|
cached = payload[:cached] || (payload[:name] == 'CACHE')
|
97
93
|
|
98
|
-
|
99
|
-
|
100
|
-
# obfuscated version
|
101
|
-
span.set_tag('active_record.db.vendor', adapter_name)
|
102
|
-
span.set_tag('active_record.db.name', database_name)
|
94
|
+
span.set_tag('active_record.db.vendor', connection_config[:adapter_name])
|
95
|
+
span.set_tag('active_record.db.name', connection_config[:database_name])
|
103
96
|
span.set_tag('active_record.db.cached', cached) if cached
|
104
|
-
span.set_tag('out.host', adapter_host)
|
105
|
-
span.set_tag('out.port', adapter_port)
|
106
|
-
span.start_time = start
|
107
|
-
span.finish(finish)
|
97
|
+
span.set_tag('out.host', connection_config[:adapter_host])
|
98
|
+
span.set_tag('out.port', connection_config[:adapter_port])
|
108
99
|
rescue StandardError => e
|
109
100
|
Datadog::Tracer.log.debug(e.message)
|
110
101
|
end
|
111
102
|
|
112
|
-
def
|
113
|
-
span = get_option(:tracer).trace(
|
114
|
-
'active_record.instantiation',
|
115
|
-
resource: payload.fetch(:class_name),
|
116
|
-
span_type: 'custom'
|
117
|
-
)
|
118
|
-
|
103
|
+
def instantiation(span, event, _id, payload)
|
119
104
|
# Inherit service name from parent, if available.
|
120
105
|
span.service = if get_option(:orm_service_name)
|
121
106
|
get_option(:orm_service_name)
|
@@ -125,10 +110,10 @@ module Datadog
|
|
125
110
|
'active_record'
|
126
111
|
end
|
127
112
|
|
113
|
+
span.resource = payload.fetch(:class_name)
|
114
|
+
span.span_type = 'custom'
|
128
115
|
span.set_tag('active_record.instantiation.class_name', payload.fetch(:class_name))
|
129
116
|
span.set_tag('active_record.instantiation.record_count', payload.fetch(:record_count))
|
130
|
-
span.start_time = start
|
131
|
-
span.finish(finish)
|
132
117
|
rescue StandardError => e
|
133
118
|
Datadog::Tracer.log.debug(e.message)
|
134
119
|
end
|