ddtrace 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/Appraisals +21 -0
- data/Rakefile +14 -3
- data/circle.yml +0 -2
- data/docker-compose.yml +9 -0
- data/docs/GettingStarted.md +74 -2
- data/gemfiles/contrib.gemfile +1 -0
- data/gemfiles/rails3_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails4_postgres_sidekiq.gemfile +10 -0
- data/gemfiles/rails5_postgres_sidekiq.gemfile +9 -0
- data/lib/ddtrace.rb +2 -17
- data/lib/ddtrace/contrib/rails/framework.rb +20 -9
- data/lib/ddtrace/contrib/sidekiq/tracer.rb +67 -0
- data/lib/ddtrace/ext/app_types.rb +1 -0
- data/lib/ddtrace/sampler.rb +49 -0
- data/lib/ddtrace/span.rb +28 -4
- data/lib/ddtrace/tracer.rb +14 -2
- data/lib/ddtrace/version.rb +2 -2
- data/lib/ddtrace/writer.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80f9cffb7ec1f57e9215784dd53d859b6a9ffae7
|
4
|
+
data.tar.gz: 348d67544886fa8762b2c2125dd8033a766d5f62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6795138d773ce92ba5123d9fbbe42a84c49a66800a9ab2a487f5c73900059b5197dbae0768e055fd11b9990fed3e1c812cf5f0637c87de7f7b56fa0ec1ba242
|
7
|
+
data.tar.gz: 1658c85972eb0be8ecc6941382558623d2ba54407e3d28874efe5c6e0936510e108512ee6314cf8d483796a903e71af77a4b47057441d2ff25e35e3174c4dfc5
|
data/.rubocop.yml
CHANGED
@@ -34,7 +34,7 @@ Style/NumericLiterals:
|
|
34
34
|
Enabled: false
|
35
35
|
|
36
36
|
Metrics/ClassLength:
|
37
|
-
Max:
|
37
|
+
Max: 140
|
38
38
|
|
39
39
|
Metrics/BlockLength:
|
40
40
|
Max: 42
|
@@ -47,3 +47,6 @@ Metrics/CyclomaticComplexity:
|
|
47
47
|
|
48
48
|
Metrics/PerceivedComplexity:
|
49
49
|
Max: 15
|
50
|
+
|
51
|
+
Lint/UnusedMethodArgument:
|
52
|
+
Enabled: false
|
data/Appraisals
CHANGED
@@ -40,6 +40,20 @@ if RUBY_VERSION < "2.4.0"
|
|
40
40
|
gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
|
41
41
|
gem "redis-rails"
|
42
42
|
end
|
43
|
+
appraise "rails3-postgres-sidekiq" do
|
44
|
+
gem "test-unit"
|
45
|
+
gem "rails", "3.2.22.5"
|
46
|
+
gem "pg", platform: :ruby
|
47
|
+
gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
|
48
|
+
gem "sidekiq"
|
49
|
+
end
|
50
|
+
|
51
|
+
appraise "rails4-postgres-sidekiq" do
|
52
|
+
gem "rails", "4.2.7.1"
|
53
|
+
gem "pg", platform: :ruby
|
54
|
+
gem 'activerecord-jdbcpostgresql-adapter', platform: :jruby
|
55
|
+
gem "sidekiq"
|
56
|
+
end
|
43
57
|
|
44
58
|
if RUBY_VERSION >= "2.2.2" && RUBY_PLATFORM != "java"
|
45
59
|
appraise "rails5-postgres" do
|
@@ -57,6 +71,12 @@ if RUBY_VERSION < "2.4.0"
|
|
57
71
|
gem "pg", platform: :ruby
|
58
72
|
gem "redis-rails"
|
59
73
|
end
|
74
|
+
|
75
|
+
appraise "rails5-postgres-sidekiq" do
|
76
|
+
gem "rails", "5.0.1"
|
77
|
+
gem "pg", platform: :ruby
|
78
|
+
gem "sidekiq"
|
79
|
+
end
|
60
80
|
end
|
61
81
|
end
|
62
82
|
|
@@ -66,4 +86,5 @@ appraise "contrib" do
|
|
66
86
|
gem "hiredis"
|
67
87
|
gem "rack-test"
|
68
88
|
gem "sinatra"
|
89
|
+
gem "sidekiq"
|
69
90
|
end
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'appraisal'
|
|
6
6
|
require 'yard'
|
7
7
|
|
8
8
|
namespace :test do
|
9
|
-
task all: [:main, :rails, :railsredis, :elasticsearch, :http, :redis, :sinatra, :monkey]
|
9
|
+
task all: [:main, :rails, :railsredis, :elasticsearch, :http, :redis, :sidekiq, :sinatra, :monkey]
|
10
10
|
|
11
11
|
Rake::TestTask.new(:main) do |t|
|
12
12
|
t.libs << %w(test lib)
|
@@ -21,7 +21,8 @@ namespace :test do
|
|
21
21
|
Rake::TestTask.new(:rails) do |t|
|
22
22
|
t.libs << %w(test lib)
|
23
23
|
t.test_files = FileList['test/contrib/rails/**/*_test.rb'].reject do |path|
|
24
|
-
path.include?('redis')
|
24
|
+
path.include?('redis') ||
|
25
|
+
path.include?('sidekiq')
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -30,7 +31,12 @@ namespace :test do
|
|
30
31
|
t.test_files = FileList['test/contrib/rails/**/*redis*_test.rb']
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
Rake::TestTask.new(:railssidekiq) do |t|
|
35
|
+
t.libs << %w(test lib)
|
36
|
+
t.test_files = FileList['test/contrib/rails/**/*sidekiq*_test.rb']
|
37
|
+
end
|
38
|
+
|
39
|
+
[:elasticsearch, :http, :redis, :sinatra, :sidekiq].each do |contrib|
|
34
40
|
Rake::TestTask.new(contrib) do |t|
|
35
41
|
t.libs << %w(test lib)
|
36
42
|
t.test_files = FileList["test/contrib/#{contrib}/*_test.rb"]
|
@@ -49,6 +55,7 @@ Rake::TestTask.new(:benchmark) do |t|
|
|
49
55
|
end
|
50
56
|
|
51
57
|
RuboCop::RakeTask.new(:rubocop) do |t|
|
58
|
+
t.options << ['-D']
|
52
59
|
t.patterns = ['lib/**/*.rb', 'test/**/*.rb', 'Gemfile', 'Rakefile']
|
53
60
|
end
|
54
61
|
|
@@ -114,6 +121,10 @@ task :ci do
|
|
114
121
|
sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:http'
|
115
122
|
sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:redis'
|
116
123
|
sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:sinatra'
|
124
|
+
sh 'rvm $MRI_VERSIONS --verbose do appraisal contrib rake test:sidekiq'
|
125
|
+
sh 'rvm $RAILS_VERSIONS --verbose do appraisal rails3-postgres-sidekiq rake test:railssidekiq'
|
126
|
+
sh 'rvm $RAILS_VERSIONS --verbose do appraisal rails4-postgres-sidekiq rake test:railssidekiq'
|
127
|
+
sh 'rvm $RAILS5_VERSIONS --verbose do appraisal rails5-postgres-sidekiq rake test:railssidekiq'
|
117
128
|
when 2
|
118
129
|
sh 'rvm $RAILS_VERSIONS --verbose do appraisal rails3-postgres rake test:rails'
|
119
130
|
sh 'rvm $RAILS_VERSIONS --verbose do appraisal rails3-mysql2 rake test:rails'
|
data/circle.yml
CHANGED
@@ -28,8 +28,6 @@ dependencies:
|
|
28
28
|
# configure Ruby interpreters
|
29
29
|
- rvm get head
|
30
30
|
- rvm install $MRI_VERSIONS
|
31
|
-
# run the agent
|
32
|
-
- docker run -d -e DD_API_KEY=invalid_key_but_this_is_fine -e DD_BIND_HOST=0.0.0.0 -e DD_APM_ENABLED=true -p 127.0.0.1:8126:8126 -p 127.0.0.1:7777:7777 datadog/docker-dd-agent
|
33
31
|
override:
|
34
32
|
- rvm $MRI_VERSIONS --verbose do gem update --system
|
35
33
|
- rvm $MRI_VERSIONS --verbose do gem install bundler
|
data/docker-compose.yml
CHANGED
@@ -31,3 +31,12 @@ redis:
|
|
31
31
|
image: redis:3.0
|
32
32
|
ports:
|
33
33
|
- "127.0.0.1:${TEST_REDIS_PORT}:6379"
|
34
|
+
|
35
|
+
ddagent:
|
36
|
+
image: datadog/docker-dd-agent
|
37
|
+
environment:
|
38
|
+
- DD_APM_ENABLED=true
|
39
|
+
- DD_BIND_HOST=0.0.0.0
|
40
|
+
- DD_API_KEY=invalid_key_but_this_is_fine
|
41
|
+
ports:
|
42
|
+
- "127.0.0.1:8126:8126"
|
data/docs/GettingStarted.md
CHANGED
@@ -64,7 +64,7 @@ of the Datadog tracer, you can override the following defaults:
|
|
64
64
|
tracer: Datadog.tracer,
|
65
65
|
debug: false,
|
66
66
|
trace_agent_hostname: 'localhost',
|
67
|
-
trace_agent_port:
|
67
|
+
trace_agent_port: 8126
|
68
68
|
}
|
69
69
|
|
70
70
|
Available settings are:
|
@@ -175,6 +175,59 @@ Net::HTTP module.
|
|
175
175
|
|
176
176
|
content = Net::HTTP.get(URI('http://127.0.0.1/index.html'))
|
177
177
|
|
178
|
+
### Sidekiq
|
179
|
+
|
180
|
+
The Sidekiq integration is a server-side middleware which will trace job
|
181
|
+
executions. It can be added as any other Sidekiq middleware:
|
182
|
+
|
183
|
+
require 'sidekiq'
|
184
|
+
require 'ddtrace'
|
185
|
+
require 'ddtrace/contrib/sidekiq/tracer'
|
186
|
+
|
187
|
+
Sidekiq.configure_server do |config|
|
188
|
+
config.server_middleware do |chain|
|
189
|
+
chain.add(Datadog::Contrib::Sidekiq::Tracer)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
#### Configure the tracer middleware
|
194
|
+
|
195
|
+
To modify the default configuration, simply pass arguments to the middleware.
|
196
|
+
For example, to change the default service name:
|
197
|
+
|
198
|
+
Sidekiq.configure_server do |config|
|
199
|
+
config.server_middleware do |chain|
|
200
|
+
chain.add(
|
201
|
+
Datadog::Contrib::Sidekiq::Tracer,
|
202
|
+
sidekiq_service: 'sidekiq-notifications'
|
203
|
+
)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
Available settings are:
|
208
|
+
|
209
|
+
* ``enabled``: define if the ``tracer`` is enabled or not. If set to
|
210
|
+
``false``, the code is still instrumented but no spans are sent to the local
|
211
|
+
trace agent.
|
212
|
+
* ``sidekiq_service``: set the service name used when tracing application
|
213
|
+
requests. Defaults to ``sidekiq``.
|
214
|
+
* ``tracer``: set the tracer to use. Usually you don't need to change that
|
215
|
+
value unless you're already using a different initialized tracer somewhere
|
216
|
+
else.
|
217
|
+
* ``debug``: set to ``true`` to enable debug logging.
|
218
|
+
* ``trace_agent_hostname``: set the hostname of the trace agent.
|
219
|
+
* ``trace_agent_port``: set the port the trace agent is listening on.
|
220
|
+
|
221
|
+
If you're using Sidekiq along with [Ruby on Rails](#label-Ruby+on+Rails) auto-instrumentation,
|
222
|
+
the Sidekiq middleware will re-use the Rails configuration defined in the initializer file before
|
223
|
+
giving precedence to the middleware settings. Inherited configurations are:
|
224
|
+
|
225
|
+
* ``enabled``
|
226
|
+
* ``tracer``
|
227
|
+
* ``debug``
|
228
|
+
* ``trace_agent_hostname``
|
229
|
+
* ``trace_agent_port``
|
230
|
+
|
178
231
|
## Advanced usage
|
179
232
|
|
180
233
|
### Manual Instrumentation
|
@@ -195,13 +248,16 @@ to trace requests to the home page:
|
|
195
248
|
# set some span metadata
|
196
249
|
span.service = 'my-web-site'
|
197
250
|
span.resource = '/'
|
198
|
-
span.set_tag('http.method', request.request_method)
|
199
251
|
|
200
252
|
# trace the activerecord call
|
201
253
|
tracer.trace('posts.fetch') do
|
202
254
|
@posts = Posts.order(created_at: :desc).limit(10)
|
203
255
|
end
|
204
256
|
|
257
|
+
# add some attributes and metrics
|
258
|
+
span.set_tag('http.method', request.request_method)
|
259
|
+
span.set_metric('posts.count', len(@posts))
|
260
|
+
|
205
261
|
# trace the template rendering
|
206
262
|
tracer.trace('template.render') do
|
207
263
|
erb :index
|
@@ -329,6 +385,18 @@ for the first time:
|
|
329
385
|
Remember that the debug mode may affect your application performance and so it must not be used
|
330
386
|
in a production environment.
|
331
387
|
|
388
|
+
### Sampling
|
389
|
+
|
390
|
+
`ddtrace` can perform trace sampling. While the trace agent already samples
|
391
|
+
traces to reduce bandwidth usage, client sampling reduces performance
|
392
|
+
overhead.
|
393
|
+
|
394
|
+
`Datadog::RateSampler` samples a ratio of the traces. For example:
|
395
|
+
|
396
|
+
# Sample rate is between 0 (nothing sampled) to 1 (everything sampled).
|
397
|
+
sampler = Datadog::RateSampler.new(0.5) # sample 50% of the traces
|
398
|
+
Datadog.tracer.configure(sampler: sampler)
|
399
|
+
|
332
400
|
### Supported Versions
|
333
401
|
|
334
402
|
#### Ruby interpreters
|
@@ -360,6 +428,10 @@ The currently supported web server are:
|
|
360
428
|
|
361
429
|
Currently we are supporting Sinatra >= 1.4.0.
|
362
430
|
|
431
|
+
#### Sidekiq versions
|
432
|
+
|
433
|
+
Currently we are supporting Sidekiq >= 4.0.0.
|
434
|
+
|
363
435
|
### Glossary
|
364
436
|
|
365
437
|
* ``Service``: The name of a set of processes that do the same job. Some examples are ``datadog-web-app`` or ``datadog-metrics-db``.
|
data/gemfiles/contrib.gemfile
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "test-unit"
|
6
|
+
gem "rails", "3.2.22.5"
|
7
|
+
gem "pg", :platform => :ruby
|
8
|
+
gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
|
9
|
+
gem "sidekiq"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
data/lib/ddtrace.rb
CHANGED
@@ -31,24 +31,9 @@ if defined?(Rails::VERSION)
|
|
31
31
|
require 'ddtrace/contrib/rails/framework'
|
32
32
|
|
33
33
|
module Datadog
|
34
|
-
# Run the auto instrumentation directly after
|
35
|
-
#
|
34
|
+
# Run the auto instrumentation directly after initializers in
|
35
|
+
# `config/initializers` are executed
|
36
36
|
class Railtie < Rails::Railtie
|
37
|
-
config.before_configuration do
|
38
|
-
begin
|
39
|
-
# We include 'redis-rails' here if it's available, doing it later
|
40
|
-
# (typically in initialize callback) does not work, it does not
|
41
|
-
# get loaded in the right context.
|
42
|
-
require 'redis-rails'
|
43
|
-
Datadog::Tracer.log.debug("'redis-rails' module found, Datadog 'redis-rails' integration is available")
|
44
|
-
rescue LoadError
|
45
|
-
Datadog::Tracer.log.debug("'redis-rails' module not found, Datadog 'redis-rails' integration is disabled")
|
46
|
-
end
|
47
|
-
|
48
|
-
Datadog::Monkey.patch_module(:redis)
|
49
|
-
end
|
50
|
-
|
51
|
-
# we do actions
|
52
37
|
config.after_initialize do |app|
|
53
38
|
Datadog::Contrib::Rails::Framework.configure(config: app.config)
|
54
39
|
Datadog::Contrib::Rails::Framework.auto_instrument()
|
@@ -80,21 +80,32 @@ module Datadog
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def self.auto_instrument_redis
|
83
|
-
|
84
|
-
|
85
|
-
pin = Datadog::Pin.get_from(::Rails.cache.data)
|
86
|
-
return unless pin
|
83
|
+
return unless ::Rails.configuration.datadog_trace[:auto_instrument_redis]
|
84
|
+
Datadog::Tracer.log.debug('Enabling auto-instrumentation for Redis client')
|
87
85
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
86
|
+
# patch the Redis library and reload the CacheStore if it was using Redis
|
87
|
+
Datadog::Monkey.patch_module(:redis)
|
88
|
+
|
89
|
+
# reload the cache store if it's available and it's using Redis
|
90
|
+
return unless defined?(::ActiveSupport::Cache::RedisStore) &&
|
91
|
+
defined?(::Rails.cache) &&
|
92
|
+
::Rails.cache.is_a?(::ActiveSupport::Cache::RedisStore)
|
93
|
+
Datadog::Tracer.log.debug('Enabling auto-instrumentation for redis-rails connector')
|
94
|
+
|
95
|
+
# backward compatibility: Rails 3.x doesn't have `cache=` method
|
96
|
+
cache_store = ::Rails.configuration.cache_store
|
97
|
+
cache_instance = ::ActiveSupport::Cache.lookup_store(cache_store)
|
98
|
+
if ::Rails::VERSION::MAJOR.to_i == 3
|
99
|
+
silence_warnings { Object.const_set 'RAILS_CACHE', cache_instance }
|
100
|
+
elsif ::Rails::VERSION::MAJOR.to_i > 3
|
101
|
+
::Rails.cache = cache_instance
|
102
|
+
end
|
92
103
|
end
|
93
104
|
|
94
105
|
# automatically instrument all Rails component
|
95
106
|
def self.auto_instrument
|
96
107
|
return unless ::Rails.configuration.datadog_trace[:auto_instrument]
|
97
|
-
Datadog::Tracer.log.
|
108
|
+
Datadog::Tracer.log.debug('Enabling auto-instrumentation for core components')
|
98
109
|
|
99
110
|
# instrumenting Rails framework
|
100
111
|
Datadog::Contrib::Rails::ActionController.instrument()
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'sidekiq/api'
|
2
|
+
|
3
|
+
require 'ddtrace/ext/app_types'
|
4
|
+
|
5
|
+
sidekiq_vs = Gem::Version.new(Sidekiq::VERSION)
|
6
|
+
sidekiq_min_vs = Gem::Version.new('4.0.0')
|
7
|
+
if sidekiq_vs < sidekiq_min_vs
|
8
|
+
raise "sidekiq version #{sidekiq_vs} is not supported yet " \
|
9
|
+
+ "(supporting versions >=#{sidekiq_min_vs})"
|
10
|
+
end
|
11
|
+
|
12
|
+
Datadog::Tracer.log.debug("Activating instrumentation for Sidekiq '#{sidekiq_vs}'")
|
13
|
+
|
14
|
+
module Datadog
|
15
|
+
module Contrib
|
16
|
+
module Sidekiq
|
17
|
+
DEFAULT_CONFIG = {
|
18
|
+
enabled: true,
|
19
|
+
sidekiq_service: 'sidekiq',
|
20
|
+
tracer: Datadog.tracer,
|
21
|
+
debug: false,
|
22
|
+
trace_agent_hostname: Datadog::Writer::HOSTNAME,
|
23
|
+
trace_agent_port: Datadog::Writer::PORT
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
# Middleware is a Sidekiq server-side middleware which traces executed jobs
|
27
|
+
class Tracer
|
28
|
+
def initialize(options)
|
29
|
+
# check if Rails configuration is available and use it to override
|
30
|
+
# Sidekiq defaults
|
31
|
+
rails_config = ::Rails.configuration.datadog_trace rescue {}
|
32
|
+
base_config = DEFAULT_CONFIG.merge(rails_config)
|
33
|
+
user_config = base_config.merge(options)
|
34
|
+
@tracer = user_config[:tracer]
|
35
|
+
@sidekiq_service = user_config[:sidekiq_service]
|
36
|
+
|
37
|
+
# set Tracer status
|
38
|
+
@tracer.enabled = user_config[:enabled]
|
39
|
+
Datadog::Tracer.debug_logging = user_config[:debug]
|
40
|
+
|
41
|
+
# configure the Tracer instance
|
42
|
+
@tracer.configure(
|
43
|
+
hostname: user_config[:trace_agent_hostname],
|
44
|
+
port: user_config[:trace_agent_port]
|
45
|
+
)
|
46
|
+
|
47
|
+
# configure Sidekiq service
|
48
|
+
@tracer.set_service_info(
|
49
|
+
@sidekiq_service,
|
50
|
+
'sidekiq',
|
51
|
+
Datadog::Ext::AppTypes::WORKER
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(worker, job, queue)
|
56
|
+
@tracer.trace('sidekiq.job', service: @sidekiq_service, span_type: 'job') do |span|
|
57
|
+
span.resource = job['class']
|
58
|
+
span.set_tag('sidekiq.job.id', job['jid'])
|
59
|
+
span.set_tag('sidekiq.job.retry', job['retry'])
|
60
|
+
span.set_tag('sidekiq.job.queue', job['queue'])
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Datadog
|
2
|
+
# \Sampler performs client-side trace sampling.
|
3
|
+
class Sampler
|
4
|
+
def sample(_span)
|
5
|
+
raise NotImplementedError, 'samplers have to implement the sample() method'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# \AllSampler samples all the traces.
|
10
|
+
class AllSampler < Sampler
|
11
|
+
def sample(span)
|
12
|
+
span.sampled = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# \RateSampler is based on a sample rate.
|
17
|
+
class RateSampler < Sampler
|
18
|
+
KNUTH_FACTOR = 1111111111111111111
|
19
|
+
SAMPLE_RATE_METRIC_KEY = '_sample_rate'.freeze()
|
20
|
+
|
21
|
+
attr_reader :sample_rate
|
22
|
+
|
23
|
+
# Initialize a \RateSampler.
|
24
|
+
# This sampler keeps a random subset of the traces. Its main purpose is to
|
25
|
+
# reduce the instrumentation footprint.
|
26
|
+
#
|
27
|
+
# * +sample_rate+: the sample rate as a \Float between 0.0 and 1.0. 0.0
|
28
|
+
# means that no trace will be sampled; 1.0 means that all traces will be
|
29
|
+
# sampled.
|
30
|
+
def initialize(sample_rate = 1.0)
|
31
|
+
unless sample_rate > 0.0 && sample_rate <= 1.0
|
32
|
+
Datadog::Tracer.log.error('sample rate is not between 0 and 1, disabling the sampler')
|
33
|
+
sample_rate = 1.0
|
34
|
+
end
|
35
|
+
|
36
|
+
self.sample_rate = sample_rate
|
37
|
+
end
|
38
|
+
|
39
|
+
def sample_rate=(sample_rate)
|
40
|
+
@sample_rate = sample_rate
|
41
|
+
@sampling_id_threshold = sample_rate * Span::MAX_ID
|
42
|
+
end
|
43
|
+
|
44
|
+
def sample(span)
|
45
|
+
span.sampled = ((span.trace_id * KNUTH_FACTOR) % Datadog::Span::MAX_ID) <= @sampling_id_threshold
|
46
|
+
span.set_metric(SAMPLE_RATE_METRIC_KEY, @sample_rate)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/ddtrace/span.rb
CHANGED
@@ -16,7 +16,7 @@ module Datadog
|
|
16
16
|
attr_accessor :name, :service, :resource, :span_type,
|
17
17
|
:start_time, :end_time,
|
18
18
|
:span_id, :trace_id, :parent_id,
|
19
|
-
:status, :parent
|
19
|
+
:status, :parent, :sampled
|
20
20
|
|
21
21
|
# Create a new span linked to the given tracer. Call the <tt>finish()</tt> method once the
|
22
22
|
# tracer operation is over or use the <tt>finish_at(time)</tt> helper to close the span with the
|
@@ -40,9 +40,11 @@ module Datadog
|
|
40
40
|
@trace_id = options.fetch(:trace_id, @span_id)
|
41
41
|
|
42
42
|
@meta = {}
|
43
|
+
@metrics = {}
|
43
44
|
@status = 0
|
44
45
|
|
45
46
|
@parent = nil
|
47
|
+
@sampled = true
|
46
48
|
|
47
49
|
@start_time = Time.now.utc
|
48
50
|
@end_time = nil
|
@@ -55,14 +57,29 @@ module Datadog
|
|
55
57
|
def set_tag(key, value)
|
56
58
|
@meta[key] = value.to_s
|
57
59
|
rescue StandardError => e
|
58
|
-
Datadog::Tracer.log.
|
60
|
+
Datadog::Tracer.log.debug("Unable to set the tag #{key}, ignoring it. Caused by: #{e}")
|
59
61
|
end
|
60
62
|
|
61
|
-
# Return the tag
|
63
|
+
# Return the tag with the given key, nil if it doesn't exist.
|
62
64
|
def get_tag(key)
|
63
65
|
@meta[key]
|
64
66
|
end
|
65
67
|
|
68
|
+
# Set the given key / value metric pair on the span. Keys must be string.
|
69
|
+
# Values must be floating point numbers.
|
70
|
+
def set_metric(key, value)
|
71
|
+
# enforce that the value is a floating point number
|
72
|
+
value = Float(value)
|
73
|
+
@metrics[key] = value
|
74
|
+
rescue StandardError => e
|
75
|
+
Datadog::Tracer.log.debug("Unable to set the metric #{key}, ignoring it. Caused by: #{e}")
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return the metric with the given key, nil if it doesn't exist.
|
79
|
+
def get_metric(key)
|
80
|
+
@metrics[key]
|
81
|
+
end
|
82
|
+
|
66
83
|
# Mark the span with the given error.
|
67
84
|
def set_error(e)
|
68
85
|
return if e.nil?
|
@@ -122,6 +139,7 @@ module Datadog
|
|
122
139
|
resource: @resource,
|
123
140
|
type: @span_type,
|
124
141
|
meta: @meta,
|
142
|
+
metrics: @metrics,
|
125
143
|
error: @status
|
126
144
|
}
|
127
145
|
|
@@ -151,12 +169,18 @@ module Datadog
|
|
151
169
|
q.text "Start: #{start_time}\n"
|
152
170
|
q.text "End: #{end_time}\n"
|
153
171
|
q.text "Duration: #{duration}\n"
|
154
|
-
q.group(2, 'Tags: [',
|
172
|
+
q.group(2, 'Tags: [', "]\n") do
|
155
173
|
q.breakable
|
156
174
|
q.seplist @meta.each do |key, value|
|
157
175
|
q.text "#{key} => #{value}"
|
158
176
|
end
|
159
177
|
end
|
178
|
+
q.group(2, 'Metrics: [', ']') do
|
179
|
+
q.breakable
|
180
|
+
q.seplist @metrics.each do |key, value|
|
181
|
+
q.text "#{key} => #{value}"
|
182
|
+
end
|
183
|
+
end
|
160
184
|
end
|
161
185
|
end
|
162
186
|
end
|
data/lib/ddtrace/tracer.rb
CHANGED
@@ -5,6 +5,7 @@ require 'logger'
|
|
5
5
|
require 'ddtrace/span'
|
6
6
|
require 'ddtrace/buffer'
|
7
7
|
require 'ddtrace/writer'
|
8
|
+
require 'ddtrace/sampler'
|
8
9
|
|
9
10
|
# \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
|
10
11
|
module Datadog
|
@@ -13,7 +14,7 @@ module Datadog
|
|
13
14
|
# Even though the request may require multiple resources and machines to handle the request, all
|
14
15
|
# of these function calls and sub-requests would be encapsulated within a single trace.
|
15
16
|
class Tracer
|
16
|
-
attr_reader :writer, :services
|
17
|
+
attr_reader :writer, :sampler, :services
|
17
18
|
attr_accessor :enabled
|
18
19
|
|
19
20
|
# Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
|
@@ -44,6 +45,8 @@ module Datadog
|
|
44
45
|
def initialize(options = {})
|
45
46
|
@enabled = options.fetch(:enabled, true)
|
46
47
|
@writer = options.fetch(:writer, Datadog::Writer.new)
|
48
|
+
@sampler = options.fetch(:sampler, Datadog::AllSampler.new)
|
49
|
+
|
47
50
|
@buffer = Datadog::SpanBuffer.new()
|
48
51
|
|
49
52
|
@mutex = Mutex.new
|
@@ -66,10 +69,12 @@ module Datadog
|
|
66
69
|
enabled = options.fetch(:enabled, nil)
|
67
70
|
hostname = options.fetch(:hostname, nil)
|
68
71
|
port = options.fetch(:port, nil)
|
72
|
+
sampler = options.fetch(:sampler, nil)
|
69
73
|
|
70
74
|
@enabled = enabled unless enabled.nil?
|
71
75
|
@writer.transport.hostname = hostname unless hostname.nil?
|
72
76
|
@writer.transport.port = port unless port.nil?
|
77
|
+
@sampler = sampler unless sampler.nil?
|
73
78
|
end
|
74
79
|
|
75
80
|
# Set the information about the given service. A valid example is:
|
@@ -121,6 +126,13 @@ module Datadog
|
|
121
126
|
span.set_parent(parent)
|
122
127
|
@buffer.set(span)
|
123
128
|
|
129
|
+
# sampling
|
130
|
+
if parent.nil?
|
131
|
+
@sampler.sample(span)
|
132
|
+
else
|
133
|
+
span.sampled = span.parent.sampled
|
134
|
+
end
|
135
|
+
|
124
136
|
# call the finish only if a block is given; this ensures
|
125
137
|
# that a call to tracer.trace() without a block, returns
|
126
138
|
# a span that should be manually finished.
|
@@ -155,7 +167,7 @@ module Datadog
|
|
155
167
|
@spans = []
|
156
168
|
end
|
157
169
|
|
158
|
-
return if spans.empty?
|
170
|
+
return if spans.empty? || !span.sampled
|
159
171
|
write(spans)
|
160
172
|
end
|
161
173
|
|
data/lib/ddtrace/version.rb
CHANGED
data/lib/ddtrace/writer.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -121,12 +121,15 @@ files:
|
|
121
121
|
- gemfiles/rails3_mysql2.gemfile
|
122
122
|
- gemfiles/rails3_postgres.gemfile
|
123
123
|
- gemfiles/rails3_postgres_redis.gemfile
|
124
|
+
- gemfiles/rails3_postgres_sidekiq.gemfile
|
124
125
|
- gemfiles/rails4_mysql2.gemfile
|
125
126
|
- gemfiles/rails4_postgres.gemfile
|
126
127
|
- gemfiles/rails4_postgres_redis.gemfile
|
128
|
+
- gemfiles/rails4_postgres_sidekiq.gemfile
|
127
129
|
- gemfiles/rails5_mysql2.gemfile
|
128
130
|
- gemfiles/rails5_postgres.gemfile
|
129
131
|
- gemfiles/rails5_postgres_redis.gemfile
|
132
|
+
- gemfiles/rails5_postgres_sidekiq.gemfile
|
130
133
|
- lib/ddtrace.rb
|
131
134
|
- lib/ddtrace/buffer.rb
|
132
135
|
- lib/ddtrace/contrib/elasticsearch/core.rb
|
@@ -143,6 +146,7 @@ files:
|
|
143
146
|
- lib/ddtrace/contrib/redis/patcher.rb
|
144
147
|
- lib/ddtrace/contrib/redis/quantize.rb
|
145
148
|
- lib/ddtrace/contrib/redis/tags.rb
|
149
|
+
- lib/ddtrace/contrib/sidekiq/tracer.rb
|
146
150
|
- lib/ddtrace/contrib/sinatra/tracer.rb
|
147
151
|
- lib/ddtrace/encoding.rb
|
148
152
|
- lib/ddtrace/ext/app_types.rb
|
@@ -154,6 +158,7 @@ files:
|
|
154
158
|
- lib/ddtrace/ext/sql.rb
|
155
159
|
- lib/ddtrace/monkey.rb
|
156
160
|
- lib/ddtrace/pin.rb
|
161
|
+
- lib/ddtrace/sampler.rb
|
157
162
|
- lib/ddtrace/span.rb
|
158
163
|
- lib/ddtrace/tracer.rb
|
159
164
|
- lib/ddtrace/transport.rb
|
@@ -182,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
187
|
version: '0'
|
183
188
|
requirements: []
|
184
189
|
rubyforge_project:
|
185
|
-
rubygems_version: 2.
|
190
|
+
rubygems_version: 2.5.1
|
186
191
|
signing_key:
|
187
192
|
specification_version: 4
|
188
193
|
summary: Datadog tracing code for your Ruby applications
|