ddtrace 0.13.0 → 0.14.0
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 +5 -5
- data/.circleci/config.yml +88 -6
- data/.rubocop.yml +10 -0
- data/Appraisals +24 -0
- data/CHANGELOG.md +108 -2
- data/Gemfile +1 -0
- data/Rakefile +32 -2
- data/benchmarks/postgres_database.yml +9 -0
- data/benchmarks/sidekiq_test.rb +154 -0
- data/ddtrace.gemspec +3 -0
- data/docs/GettingStarted.md +127 -6
- data/lib/ddtrace/configuration.rb +19 -7
- data/lib/ddtrace/context.rb +8 -0
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +46 -0
- data/lib/ddtrace/contrib/active_record/configuration/settings.rb +28 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +11 -7
- data/lib/ddtrace/contrib/active_record/integration.rb +44 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +4 -28
- data/lib/ddtrace/contrib/active_record/utils.rb +5 -11
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -1
- data/lib/ddtrace/contrib/base.rb +4 -3
- data/lib/ddtrace/contrib/configurable.rb +55 -0
- data/lib/ddtrace/contrib/configuration/option.rb +33 -0
- data/lib/ddtrace/contrib/configuration/option_definition.rb +29 -0
- data/lib/ddtrace/contrib/configuration/option_definition_set.rb +20 -0
- data/lib/ddtrace/contrib/configuration/option_set.rb +8 -0
- data/lib/ddtrace/contrib/configuration/options.rb +95 -0
- data/lib/ddtrace/contrib/configuration/resolver.rb +12 -0
- data/lib/ddtrace/contrib/configuration/settings.rb +35 -0
- data/lib/ddtrace/contrib/delayed_job/patcher.rb +41 -0
- data/lib/ddtrace/contrib/delayed_job/plugin.rb +43 -0
- data/lib/ddtrace/contrib/integration.rb +16 -0
- data/lib/ddtrace/contrib/patchable.rb +38 -0
- data/lib/ddtrace/contrib/patcher.rb +28 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +34 -15
- data/lib/ddtrace/contrib/rake/instrumentation.rb +15 -3
- data/lib/ddtrace/contrib/registerable.rb +33 -0
- data/lib/ddtrace/contrib/resque/resque_job.rb +2 -10
- data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +22 -0
- data/lib/ddtrace/contrib/rest_client/integration.rb +27 -0
- data/lib/ddtrace/contrib/rest_client/patcher.rb +25 -0
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +90 -0
- data/lib/ddtrace/contrib/sequel/configuration/settings.rb +13 -0
- data/lib/ddtrace/contrib/sequel/database.rb +1 -1
- data/lib/ddtrace/contrib/sequel/integration.rb +38 -0
- data/lib/ddtrace/contrib/sequel/patcher.rb +4 -20
- data/lib/ddtrace/monkey.rb +0 -7
- data/lib/ddtrace/patcher.rb +5 -0
- data/lib/ddtrace/pin.rb +1 -1
- data/lib/ddtrace/propagation/http_propagator.rb +6 -0
- data/lib/ddtrace/span.rb +0 -1
- data/lib/ddtrace/tracer.rb +22 -5
- data/lib/ddtrace/vendor/active_record/connection_specification.rb +301 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers.rb +6 -4
- data/lib/ddtrace/writer.rb +4 -5
- data/lib/ddtrace.rb +7 -15
- metadata +57 -3
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
ENV['RAILS_ENV'] = 'production'
|
|
2
|
+
require 'English'
|
|
3
|
+
|
|
4
|
+
# Benchmark Configuration container
|
|
5
|
+
module TestConfiguration
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def sidekiq
|
|
9
|
+
Sidekiq.options.tap do |options|
|
|
10
|
+
options[:tag] = 'test'
|
|
11
|
+
options[:queues] << 'default'
|
|
12
|
+
options[:concurrency] = 20
|
|
13
|
+
options[:timeout] = 2
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def redis
|
|
18
|
+
{ pool_size: 30, timeout: 3 }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def iteration_count
|
|
22
|
+
1000
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require 'bundler/setup'
|
|
27
|
+
require 'rails/all'
|
|
28
|
+
Bundler.require(*Rails.groups)
|
|
29
|
+
|
|
30
|
+
# Example Rails App
|
|
31
|
+
module SampleApp
|
|
32
|
+
class Application < Rails::Application; end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Overrides rails configueration locations
|
|
36
|
+
module OverrideConfiguration
|
|
37
|
+
def paths
|
|
38
|
+
super.tap { |path| path.add 'config/database', with: 'benchmarks/postgres_database.yml' }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Rails::Application::Configuration.prepend(OverrideConfiguration)
|
|
43
|
+
|
|
44
|
+
Rails.application.configure do
|
|
45
|
+
config.cache_classes = true
|
|
46
|
+
config.eager_load = true
|
|
47
|
+
config.active_job.queue_adapter = :sidekiq
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
|
|
51
|
+
Rails.application.initialize!
|
|
52
|
+
|
|
53
|
+
ActiveRecord::Schema.define do
|
|
54
|
+
drop_table(:samples) if connection.table_exists?(:samples)
|
|
55
|
+
|
|
56
|
+
create_table :samples do |t|
|
|
57
|
+
t.string :name
|
|
58
|
+
t.timestamps
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Sample < ActiveRecord::Base; end
|
|
63
|
+
|
|
64
|
+
require 'sidekiq/launcher'
|
|
65
|
+
require 'sidekiq/cli'
|
|
66
|
+
require 'concurrent/atomic/atomic_fixnum'
|
|
67
|
+
|
|
68
|
+
Sidekiq.configure_server do |config|
|
|
69
|
+
redis_conn = proc do
|
|
70
|
+
Redis.new(
|
|
71
|
+
host: ENV.fetch('TEST_REDIS_HOST', '127.0.0.1'),
|
|
72
|
+
port: ENV.fetch('TEST_REDIS_PORT', 6379)
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
config.redis = ConnectionPool.new(size: TestConfiguration.redis[:pool_size],
|
|
76
|
+
timeout: TestConfiguration.redis[:timeout],
|
|
77
|
+
&redis_conn)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Simple Sidekiq worker performing the real benchmark
|
|
81
|
+
class Worker
|
|
82
|
+
class << self
|
|
83
|
+
attr_reader :iterations, :conditional_variable
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
@iterations = Concurrent::AtomicFixnum.new(0)
|
|
87
|
+
@conditional_variable = ConditionVariable.new
|
|
88
|
+
|
|
89
|
+
include Sidekiq::Worker
|
|
90
|
+
def perform(iter, max_iterations)
|
|
91
|
+
self.class.iterations.increment
|
|
92
|
+
self.class.conditional_variable.broadcast if self.class.iterations.value > max_iterations
|
|
93
|
+
|
|
94
|
+
Sample.create!(name: iter.to_s).save
|
|
95
|
+
|
|
96
|
+
100.times do
|
|
97
|
+
Sample.last.name
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Sample.last(100).to_a
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if Datadog.respond_to?(:configure)
|
|
105
|
+
Datadog.configure do |d|
|
|
106
|
+
d.use :rails, enabled: true, tags: { 'tag' => 'value' }
|
|
107
|
+
d.use :http
|
|
108
|
+
d.use :sidekiq, service_name: 'service'
|
|
109
|
+
d.use :redis
|
|
110
|
+
d.use :dalli
|
|
111
|
+
d.use :resque, workers: [Worker]
|
|
112
|
+
|
|
113
|
+
processor = Datadog::Pipeline::SpanProcessor.new do |span|
|
|
114
|
+
true if span.service == 'B'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
Datadog::Pipeline.before_flush(processor)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def current_memory
|
|
122
|
+
`ps -o rss #{$PROCESS_ID}`.split("\n")[1].to_f / 1024
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def time
|
|
126
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def launch(iterations, options)
|
|
130
|
+
iterations.times do |i|
|
|
131
|
+
Worker.perform_async(i, iterations)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
launcher = Sidekiq::Launcher.new(options)
|
|
135
|
+
launcher.run
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def wait_and_measure(iterations)
|
|
139
|
+
start = time
|
|
140
|
+
|
|
141
|
+
STDERR.puts "#{time - start}, #{current_memory}"
|
|
142
|
+
|
|
143
|
+
mutex = Mutex.new
|
|
144
|
+
|
|
145
|
+
while Worker.iterations.value < iterations
|
|
146
|
+
mutex.synchronize do
|
|
147
|
+
Worker.conditional_variable.wait(mutex, 1)
|
|
148
|
+
STDERR.puts "#{time - start}, #{current_memory}"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
launch(TestConfiguration.iteration_count, TestConfiguration.sidekiq)
|
|
154
|
+
wait_and_measure(TestConfiguration.iteration_count)
|
data/ddtrace.gemspec
CHANGED
|
@@ -43,6 +43,9 @@ Gem::Specification.new do |spec|
|
|
|
43
43
|
spec.add_development_dependency 'yard', '~> 0.9'
|
|
44
44
|
spec.add_development_dependency 'webmock', '~> 2.0'
|
|
45
45
|
spec.add_development_dependency 'builder'
|
|
46
|
+
spec.add_development_dependency 'ruby-prof'
|
|
47
|
+
spec.add_development_dependency 'sqlite3'
|
|
48
|
+
|
|
46
49
|
# locking transitive dependency of webmock
|
|
47
50
|
spec.add_development_dependency 'addressable', '~> 2.4.0'
|
|
48
51
|
spec.add_development_dependency 'redcarpet', '~> 3.4' if RUBY_PLATFORM != 'java'
|
data/docs/GettingStarted.md
CHANGED
|
@@ -26,6 +26,7 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
26
26
|
- [Active Record](#active-record)
|
|
27
27
|
- [AWS](#aws)
|
|
28
28
|
- [Dalli](#dalli)
|
|
29
|
+
- [DelayedJob](#delayedjob)
|
|
29
30
|
- [Elastic Search](#elastic-search)
|
|
30
31
|
- [Excon](#excon)
|
|
31
32
|
- [Faraday](#faraday)
|
|
@@ -33,12 +34,14 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
33
34
|
- [Grape](#grape)
|
|
34
35
|
- [GraphQL](#graphql)
|
|
35
36
|
- [MongoDB](#mongodb)
|
|
37
|
+
- [MySQL2](#mysql2)
|
|
36
38
|
- [Net/HTTP](#nethttp)
|
|
37
39
|
- [Racecar](#racecar)
|
|
38
40
|
- [Rack](#rack)
|
|
39
41
|
- [Rails](#rails)
|
|
40
42
|
- [Rake](#rake)
|
|
41
43
|
- [Redis](#redis)
|
|
44
|
+
- [Rest Client](#restclient)
|
|
42
45
|
- [Resque](#resque)
|
|
43
46
|
- [Sequel](#sequel)
|
|
44
47
|
- [Sidekiq](#sidekiq)
|
|
@@ -96,7 +99,7 @@ The Ruby APM tracer sends trace data through the Datadog Agent.
|
|
|
96
99
|
### Quickstart for Rails applications
|
|
97
100
|
|
|
98
101
|
1. Add the `ddtrace` gem to your Gemfile:
|
|
99
|
-
|
|
102
|
+
|
|
100
103
|
```ruby
|
|
101
104
|
source 'https://rubygems.org'
|
|
102
105
|
gem 'ddtrace'
|
|
@@ -162,6 +165,7 @@ And `options` is an optional `Hash` that accepts the following parameters:
|
|
|
162
165
|
| ``child_of`` | `Datadog::Span` / `Datadog::Context` | Parent for this span. If not provided, will automatically become current active span. | `nil` |
|
|
163
166
|
| ``start_time`` | `Integer` | When the span actually starts. Useful when tracing events that have already happened. | `Time.now.utc` |
|
|
164
167
|
| ``tags`` | `Hash` | Extra tags which should be added to the span. | `{}` |
|
|
168
|
+
| ``on_error`` | `Proc` | Handler invoked when a block is provided to trace, and it raises an error. Provided `span` and `error` as arguments. Sets error on the span by default. | `proc { |span, error| span.set_error(error) unless span.nil? }` |
|
|
165
169
|
|
|
166
170
|
It's highly recommended you set both `service` and `resource` at a minimum. Spans without a `service` or `resource` as `nil` will be discarded by the Datadog agent.
|
|
167
171
|
|
|
@@ -226,17 +230,26 @@ def finish(name, id, payload)
|
|
|
226
230
|
end
|
|
227
231
|
end
|
|
228
232
|
```
|
|
229
|
-
#####Enriching traces from nested methods
|
|
233
|
+
##### Enriching traces from nested methods
|
|
230
234
|
|
|
231
|
-
You can tag additional information to current active span from any method. Note however that if the method is called and there is no span currently active `active_span` will be nil.
|
|
235
|
+
You can tag additional information to current active span from any method. Note however that if the method is called and there is no span currently active `active_span` will be nil.
|
|
232
236
|
|
|
233
237
|
```ruby
|
|
234
238
|
# e.g. adding tag to active span
|
|
235
|
-
|
|
239
|
+
|
|
236
240
|
current_span = Datadog.tracer.active_span
|
|
237
241
|
current_span.set_tag('my_tag', 'my_value') unless current_span.nil?
|
|
238
242
|
```
|
|
239
243
|
|
|
244
|
+
You can also get the root span of the current active trace using the `active_root_span` method. This method will return `nil` if there is no active trace.
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
# e.g. adding tag to active root span
|
|
248
|
+
|
|
249
|
+
current_root_span = Datadog.tracer.active_root_span
|
|
250
|
+
current_root_span.set_tag('my_tag', 'my_value') unless current_root_span.nil?
|
|
251
|
+
```
|
|
252
|
+
|
|
240
253
|
## Integration instrumentation
|
|
241
254
|
|
|
242
255
|
Many popular libraries and frameworks are supported out-of-the-box, which can be auto-instrumented. Although they are not activated automatically, they can be easily activated and configured by using the `Datadog.configure` API:
|
|
@@ -257,6 +270,7 @@ For a list of available integrations, and their configuration options, please re
|
|
|
257
270
|
| Active Record | `active_record` | `>= 3.2, < 5.2` | *[Link](#active-record)* | *[Link](https://github.com/rails/rails/tree/master/activerecord)* |
|
|
258
271
|
| AWS | `aws` | `>= 2.0` | *[Link](#aws)* | *[Link](https://github.com/aws/aws-sdk-ruby)* |
|
|
259
272
|
| Dalli | `dalli` | `>= 2.7` | *[Link](#dalli)* | *[Link](https://github.com/petergoldstein/dalli)* |
|
|
273
|
+
| DelayedJob | `delayed_job` | `>= 4.1` | *[Link](#delayedjob)* | *[Link](https://github.com/collectiveidea/delayed_job)* |
|
|
260
274
|
| Elastic Search | `elasticsearch` | `>= 6.0` | *[Link](#elastic-search)* | *[Link](https://github.com/elastic/elasticsearch-ruby)* |
|
|
261
275
|
| Excon | `excon` | `>= 0.62` | *[Link](#excon)* | *[Link](https://github.com/excon/excon)* |
|
|
262
276
|
| Faraday | `faraday` | `>= 0.14` | *[Link](#faraday)* | *[Link](https://github.com/lostisland/faraday)* |
|
|
@@ -264,12 +278,14 @@ For a list of available integrations, and their configuration options, please re
|
|
|
264
278
|
| Grape | `grape` | `>= 1.0` | *[Link](#grape)* | *[Link](https://github.com/ruby-grape/grape)* |
|
|
265
279
|
| GraphQL | `graphql` | `>= 1.7.9` | *[Link](#graphql)* | *[Link](https://github.com/rmosolgo/graphql-ruby)* |
|
|
266
280
|
| MongoDB | `mongo` | `>= 2.0, < 2.5` | *[Link](#mongodb)* | *[Link](https://github.com/mongodb/mongo-ruby-driver)* |
|
|
281
|
+
| MySQL2 | `mysql2` | `>= 0.5` | *[Link](#mysql2)* | *[Link](https://github.com/brianmario/mysql2)* |
|
|
267
282
|
| Net/HTTP | `http` | *(Any supported Ruby)* | *[Link](#nethttp)* | *[Link](https://ruby-doc.org/stdlib-2.4.0/libdoc/net/http/rdoc/Net/HTTP.html)* |
|
|
268
283
|
| Racecar | `racecar` | `>= 0.3.5` | *[Link](#racecar)* | *[Link](https://github.com/zendesk/racecar)* |
|
|
269
284
|
| Rack | `rack` | `>= 1.4.7` | *[Link](#rack)* | *[Link](https://github.com/rack/rack)* |
|
|
270
285
|
| Rails | `rails` | `>= 3.2, < 5.2` | *[Link](#rails)* | *[Link](https://github.com/rails/rails)* |
|
|
271
286
|
| Rake | `rake` | `>= 12.0` | *[Link](#rake)* | *[Link](https://github.com/ruby/rake)* |
|
|
272
287
|
| Redis | `redis` | `>= 3.2, < 4.0` | *[Link](#redis)* | *[Link](https://github.com/redis/redis-rb)* |
|
|
288
|
+
| Rest Client | `rest-client` | `>= 1.8` | *[Link](#restclient)* | *[Link](https://github.com/rest-client/rest-client)* |
|
|
273
289
|
| Resque | `resque` | `>= 1.0, < 2.0` | *[Link](#resque)* | *[Link](https://github.com/resque/resque)* |
|
|
274
290
|
| Sequel | `sequel` | `>= 3.41` | *[Link](#sequel)* | *[Link](https://github.com/jeremyevans/sequel)* |
|
|
275
291
|
| Sidekiq | `sidekiq` | `>= 4.0` | *[Link](#sidekiq)* | *[Link](https://github.com/mperham/sidekiq)* |
|
|
@@ -304,6 +320,44 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
304
320
|
| ``service_name`` | Service name used for database portion of `active_record` instrumentation. | Name of database adapter (e.g. `mysql2`) |
|
|
305
321
|
| ``orm_service_name`` | Service name used for the Ruby ORM portion of `active_record` instrumentation. Overrides service name for ORM spans if explicitly set, which otherwise inherit their service from their parent. | ``active_record`` |
|
|
306
322
|
|
|
323
|
+
**Configuring trace settings per database**
|
|
324
|
+
|
|
325
|
+
You can provide the `databases` option to configure trace settings by database connection:
|
|
326
|
+
|
|
327
|
+
```ruby
|
|
328
|
+
# Provide a `:describes` option with a connection key.
|
|
329
|
+
# Any of the following keys are acceptable, and equivalent to one another.
|
|
330
|
+
# If a block is provided, it yields a Settings object that
|
|
331
|
+
# accepts any of the configuration options listed above.
|
|
332
|
+
|
|
333
|
+
Datadog.configure do |c|
|
|
334
|
+
# Symbol matching your database connection in config/database.yml
|
|
335
|
+
# Only available if you are using Rails with ActiveRecord.
|
|
336
|
+
c.use :active_record, describes: :secondary_database, service_name: 'secondary-db'
|
|
337
|
+
|
|
338
|
+
c.use :active_record, describes: :secondary_database do |second_db|
|
|
339
|
+
second_db.service_name = 'secondary-db'
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Connection string with the following connection settings:
|
|
343
|
+
# Adapter, user, host, port, database
|
|
344
|
+
c.use :active_record, describes: 'mysql2://root@127.0.0.1:3306/mysql', service_name: 'secondary-db'
|
|
345
|
+
|
|
346
|
+
# Hash with following connection settings
|
|
347
|
+
# Adapter, user, host, port, database
|
|
348
|
+
c.use :active_record, describes: {
|
|
349
|
+
adapter: 'mysql2',
|
|
350
|
+
host: '127.0.0.1',
|
|
351
|
+
port: '3306',
|
|
352
|
+
database: 'mysql',
|
|
353
|
+
username: 'root'
|
|
354
|
+
},
|
|
355
|
+
service_name: 'secondary-db'
|
|
356
|
+
end
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
If ActiveRecord traces an event that uses a connection described within `databases`, it will use the trace settings assigned to that connection. If the connection does not match any in the `databases` option, it will use settings defined by `c.use :active_record` instead.
|
|
360
|
+
|
|
307
361
|
### AWS
|
|
308
362
|
|
|
309
363
|
The AWS integration will trace every interaction (e.g. API calls) with AWS services (S3, ElastiCache etc.).
|
|
@@ -455,7 +509,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
455
509
|
|
|
456
510
|
### gRPC
|
|
457
511
|
|
|
458
|
-
The `grpc` integration adds both client and server interceptors, which run as middleware prior to executing the service's remote procedure call. As gRPC applications are often distributed, the integration shares trace information between client and server.
|
|
512
|
+
The `grpc` integration adds both client and server interceptors, which run as middleware prior to executing the service's remote procedure call. As gRPC applications are often distributed, the integration shares trace information between client and server.
|
|
459
513
|
|
|
460
514
|
To setup your integration, use the ``Datadog.configure`` method like so:
|
|
461
515
|
|
|
@@ -613,6 +667,29 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
613
667
|
| ``service_name`` | Service name used for `mongo` instrumentation | mongodb |
|
|
614
668
|
| ``quantize`` | Hash containing options for quantization. May include `:show` with an Array of keys to not quantize (or `:all` to skip quantization), or `:exclude` with Array of keys to exclude entirely. | ```{ show: [:collection, :database, :operation] }``` |
|
|
615
669
|
|
|
670
|
+
### MySQL2
|
|
671
|
+
|
|
672
|
+
The MySQL2 integration traces any SQL command sent through `mysql2` gem.
|
|
673
|
+
|
|
674
|
+
```ruby
|
|
675
|
+
require 'mysql2'
|
|
676
|
+
require 'ddtrace'
|
|
677
|
+
|
|
678
|
+
Datadog.configure do |c|
|
|
679
|
+
c.use :mysql2, options
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
client = Mysql2::Client.new(:host => "localhost", :username => "root")
|
|
683
|
+
client.query("SELECT * FROM users WHERE group='x'")
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
Where `options` is an optional `Hash` that accepts the following parameters:
|
|
687
|
+
|
|
688
|
+
| Key | Description | Default |
|
|
689
|
+
| --- | --- | --- |
|
|
690
|
+
| ``service_name`` | Service name used for MySQL2 instrumentation | `mysql2` |
|
|
691
|
+
| ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
|
|
692
|
+
|
|
616
693
|
### Net/HTTP
|
|
617
694
|
|
|
618
695
|
The Net/HTTP integration will trace any HTTP call using the standard lib Net::HTTP module.
|
|
@@ -759,7 +836,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
759
836
|
| Key | Description | Default |
|
|
760
837
|
| --- | --- | --- |
|
|
761
838
|
| ``service_name`` | Service name used when tracing application requests (on the `rack` level) | ``<app_name>`` (inferred from your Rails application namespace) |
|
|
762
|
-
| ``controller_service`` | Service name used when tracing a Rails action controller | ``<app_name
|
|
839
|
+
| ``controller_service`` | Service name used when tracing a Rails action controller | ``<app_name>`` |
|
|
763
840
|
| ``cache_service`` | Cache service name used when tracing cache activity | ``<app_name>-cache`` |
|
|
764
841
|
| ``database_service`` | Database service name used when tracing database activity | ``<app_name>-<adapter_name>`` |
|
|
765
842
|
| ``exception_controller`` | Class or Module which identifies a custom exception controller class. Tracer provides improved error behavior when it can identify custom exception controllers. By default, without this option, it 'guesses' what a custom exception controller looks like. Providing this option aids this identification. | ``nil`` |
|
|
@@ -767,6 +844,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
767
844
|
| ``middleware_names`` | Enables any short-circuited middleware requests to display the middleware name as resource for the trace. | `false` |
|
|
768
845
|
| ``template_base_path`` | Used when the template name is parsed. If you don't store your templates in the ``views/`` folder, you may need to change this value | ``views/`` |
|
|
769
846
|
| ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
|
|
847
|
+
| ``databases`` | Hash of tracer settings to use for each database connection. See [ActiveRecord](#activerecord) for more details. | ``{}`` |
|
|
770
848
|
|
|
771
849
|
### Rake
|
|
772
850
|
|
|
@@ -869,6 +947,27 @@ customer_cache.get(...) # traced call will belong to `customer-cache` service
|
|
|
869
947
|
invoice_cache.get(...) # traced call will belong to `invoice-cache` service
|
|
870
948
|
```
|
|
871
949
|
|
|
950
|
+
### Rest Client
|
|
951
|
+
|
|
952
|
+
The `rest-client` integration is available through the `ddtrace` middleware:
|
|
953
|
+
|
|
954
|
+
```ruby
|
|
955
|
+
require 'rest_client'
|
|
956
|
+
require 'ddtrace'
|
|
957
|
+
|
|
958
|
+
Datadog.configure do |c|
|
|
959
|
+
c.use :rest_client, service_name: 'rest_client' # global service name
|
|
960
|
+
end
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
Where `options` is an optional `Hash` that accepts the following parameters:
|
|
964
|
+
|
|
965
|
+
| Key | Description | Default |
|
|
966
|
+
| --- | --- | --- |
|
|
967
|
+
| `service_name` | Service name for Rest Client instrumentation. | `'rest_client'` |
|
|
968
|
+
| `distributed_tracing` | Enables [distributed tracing](#distributed-tracing) | `false` |
|
|
969
|
+
| `tracer` | A `Datadog::Tracer` instance used to instrument the application. Usually you don't need to set that. | `Datadog.tracer` |
|
|
970
|
+
|
|
872
971
|
### Resque
|
|
873
972
|
|
|
874
973
|
The Resque integration uses Resque hooks that wraps the ``perform`` method.
|
|
@@ -963,6 +1062,27 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
963
1062
|
| --- | --- | --- |
|
|
964
1063
|
| ``service_name`` | Service name used for `sidekiq` instrumentation | sidekiq |
|
|
965
1064
|
|
|
1065
|
+
### DelayedJob
|
|
1066
|
+
|
|
1067
|
+
The DelayedJob integration uses lifecycle hooks to trace the job executions.
|
|
1068
|
+
|
|
1069
|
+
You can enable it through `Datadog.configure`:
|
|
1070
|
+
|
|
1071
|
+
```ruby
|
|
1072
|
+
require 'ddtrace'
|
|
1073
|
+
|
|
1074
|
+
Datadog.configure do |c|
|
|
1075
|
+
c.use :delayed_job, options
|
|
1076
|
+
end
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
Where `options` is an optional `Hash` that accepts the following parameters:
|
|
1080
|
+
|
|
1081
|
+
| Key | Description | Default |
|
|
1082
|
+
| --- | --- | --- |
|
|
1083
|
+
| ``service_name`` | Service name used for `DelayedJob` instrumentation | delayed_job |
|
|
1084
|
+
| ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
|
|
1085
|
+
|
|
966
1086
|
### Sinatra
|
|
967
1087
|
|
|
968
1088
|
The Sinatra integration traces requests and template rendering.
|
|
@@ -1238,6 +1358,7 @@ For more details on how to activate distributed tracing for integrations, see th
|
|
|
1238
1358
|
|
|
1239
1359
|
- [Excon](#excon)
|
|
1240
1360
|
- [Faraday](#faraday)
|
|
1361
|
+
- [Rest Client](#restclient)
|
|
1241
1362
|
- [Net/HTTP](#nethttp)
|
|
1242
1363
|
- [Rack](#rack)
|
|
1243
1364
|
- [Rails](#rails)
|
|
@@ -8,20 +8,32 @@ module Datadog
|
|
|
8
8
|
InvalidIntegrationError = Class.new(StandardError)
|
|
9
9
|
|
|
10
10
|
def initialize(options = {})
|
|
11
|
-
@registry = options.fetch(:registry
|
|
11
|
+
@registry = options.fetch(:registry) { Datadog.registry }
|
|
12
12
|
@wrapped_registry = {}
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def [](integration_name)
|
|
16
|
-
|
|
15
|
+
def [](integration_name, configuration_name = :default)
|
|
16
|
+
integration = fetch_integration(integration_name)
|
|
17
|
+
|
|
18
|
+
if integration.class <= Datadog::Contrib::Integration
|
|
19
|
+
integration.configuration(configuration_name)
|
|
20
|
+
else
|
|
21
|
+
@wrapped_registry[integration_name] ||= Proxy.new(integration)
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
|
|
19
|
-
def use(integration_name, options = {})
|
|
25
|
+
def use(integration_name, options = {}, &block)
|
|
20
26
|
integration = fetch_integration(integration_name)
|
|
21
|
-
settings = Proxy.new(integration)
|
|
22
27
|
|
|
23
|
-
integration.
|
|
24
|
-
|
|
28
|
+
if integration.class <= Datadog::Contrib::Integration
|
|
29
|
+
configuration_name = options[:describes] || :default
|
|
30
|
+
filtered_options = options.reject { |k, _v| k == :describes }
|
|
31
|
+
integration.configure(configuration_name, filtered_options, &block)
|
|
32
|
+
else
|
|
33
|
+
settings = Proxy.new(integration)
|
|
34
|
+
integration.sorted_options.each do |name|
|
|
35
|
+
settings[name] = options.fetch(name, settings[name])
|
|
36
|
+
end
|
|
25
37
|
end
|
|
26
38
|
|
|
27
39
|
integration.patch if integration.respond_to?(:patch)
|
data/lib/ddtrace/context.rb
CHANGED
|
@@ -63,6 +63,12 @@ module Datadog
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
def current_root_span
|
|
67
|
+
@mutex.synchronize do
|
|
68
|
+
return @current_root_span
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
66
72
|
# Add a span to the context trace list, keeping it as the last active span.
|
|
67
73
|
def add_span(span)
|
|
68
74
|
@mutex.synchronize do
|
|
@@ -77,6 +83,7 @@ module Datadog
|
|
|
77
83
|
return
|
|
78
84
|
end
|
|
79
85
|
set_current_span(span)
|
|
86
|
+
@current_root_span = span if @trace.empty?
|
|
80
87
|
@trace << span
|
|
81
88
|
span.context = self
|
|
82
89
|
end
|
|
@@ -158,6 +165,7 @@ module Datadog
|
|
|
158
165
|
@sampling_priority = options.fetch(:sampling_priority, nil)
|
|
159
166
|
@finished_spans = 0
|
|
160
167
|
@current_span = nil
|
|
168
|
+
@current_root_span = nil
|
|
161
169
|
end
|
|
162
170
|
|
|
163
171
|
def set_current_span(span)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'ddtrace/contrib/configuration/resolver'
|
|
2
|
+
require 'ddtrace/vendor/active_record/connection_specification'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Contrib
|
|
6
|
+
module ActiveRecord
|
|
7
|
+
module Configuration
|
|
8
|
+
# Converts Symbols, Strings, and Hashes to a normalized connection settings Hash.
|
|
9
|
+
class Resolver < Contrib::Configuration::Resolver
|
|
10
|
+
def initialize(configurations = nil)
|
|
11
|
+
@configurations = configurations
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def configurations
|
|
15
|
+
@configurations || ::ActiveRecord::Base.configurations
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def connection_resolver
|
|
19
|
+
@resolver ||= begin
|
|
20
|
+
if defined?(::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver)
|
|
21
|
+
::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configurations)
|
|
22
|
+
else
|
|
23
|
+
::Datadog::Vendor::ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configurations)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def resolve(spec)
|
|
29
|
+
return :default if spec == :default
|
|
30
|
+
normalize(connection_resolver.resolve(spec).symbolize_keys)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def normalize(hash)
|
|
34
|
+
{
|
|
35
|
+
adapter: hash[:adapter],
|
|
36
|
+
host: hash[:host],
|
|
37
|
+
port: hash[:port],
|
|
38
|
+
database: hash[:database],
|
|
39
|
+
username: hash[:username]
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'ddtrace/contrib/configuration/settings'
|
|
2
|
+
require 'ddtrace/contrib/active_record/utils'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Contrib
|
|
6
|
+
module ActiveRecord
|
|
7
|
+
module Configuration
|
|
8
|
+
# Unique settings for ActiveRecord
|
|
9
|
+
class Settings < Contrib::Configuration::Settings
|
|
10
|
+
option :orm_service_name
|
|
11
|
+
option :service_name, depends_on: [:tracer] do |value|
|
|
12
|
+
(value || Utils.adapter_name).tap do |service_name|
|
|
13
|
+
tracer.set_service_info(service_name, 'active_record', Ext::AppTypes::DB)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
option :tracer, default: Datadog.tracer do |value|
|
|
18
|
+
value.tap do
|
|
19
|
+
Events.subscriptions.each do |subscription|
|
|
20
|
+
subscription.tracer = value
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -22,9 +22,13 @@ module Datadog
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def process(span, event, _id, payload)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
config = Utils.connection_config(payload[:connection_id])
|
|
26
|
+
settings = Datadog.configuration[:active_record, config]
|
|
27
|
+
adapter_name = Datadog::Utils::Database.normalize_vendor(config[:adapter])
|
|
28
|
+
service_name = !settings.nil? ? settings.service_name : configuration[:service_name]
|
|
29
|
+
|
|
30
|
+
span.name = "#{adapter_name}.query"
|
|
31
|
+
span.service = service_name
|
|
28
32
|
span.resource = payload.fetch(:sql)
|
|
29
33
|
span.span_type = Datadog::Ext::SQL::TYPE
|
|
30
34
|
|
|
@@ -33,11 +37,11 @@ module Datadog
|
|
|
33
37
|
# is simply cached from memory, so the notification is fired with start == finish.
|
|
34
38
|
cached = payload[:cached] || (payload[:name] == 'CACHE')
|
|
35
39
|
|
|
36
|
-
span.set_tag('active_record.db.vendor',
|
|
37
|
-
span.set_tag('active_record.db.name',
|
|
40
|
+
span.set_tag('active_record.db.vendor', adapter_name)
|
|
41
|
+
span.set_tag('active_record.db.name', config[:database])
|
|
38
42
|
span.set_tag('active_record.db.cached', cached) if cached
|
|
39
|
-
span.set_tag('out.host',
|
|
40
|
-
span.set_tag('out.port',
|
|
43
|
+
span.set_tag('out.host', config[:host]) if config[:host]
|
|
44
|
+
span.set_tag('out.port', config[:port]) if config[:port]
|
|
41
45
|
rescue StandardError => e
|
|
42
46
|
Datadog::Tracer.log.debug(e.message)
|
|
43
47
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'ddtrace/ext/sql'
|
|
2
|
+
require 'ddtrace/ext/app_types'
|
|
3
|
+
require 'ddtrace/contrib/integration'
|
|
4
|
+
require 'ddtrace/contrib/active_record/events'
|
|
5
|
+
require 'ddtrace/contrib/active_record/configuration/resolver'
|
|
6
|
+
require 'ddtrace/contrib/active_record/configuration/settings'
|
|
7
|
+
require 'ddtrace/contrib/active_record/patcher'
|
|
8
|
+
|
|
9
|
+
module Datadog
|
|
10
|
+
module Contrib
|
|
11
|
+
module ActiveRecord
|
|
12
|
+
# Describes the ActiveRecord integration
|
|
13
|
+
class Integration
|
|
14
|
+
include Contrib::Integration
|
|
15
|
+
|
|
16
|
+
register_as :active_record, auto_patch: false
|
|
17
|
+
|
|
18
|
+
def self.version
|
|
19
|
+
Gem.loaded_specs['activerecord'] && Gem.loaded_specs['activerecord'].version
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.present?
|
|
23
|
+
super && defined?(::ActiveRecord)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.compatible?
|
|
27
|
+
super && version >= Gem::Version.new('3.0')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def default_configuration
|
|
31
|
+
Configuration::Settings.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def patcher
|
|
35
|
+
ActiveRecord::Patcher
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def resolver
|
|
39
|
+
@resolver ||= Configuration::Resolver.new
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|