ddtrace 0.4.3 → 0.5.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 +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
|