fair-ddtrace 0.8.2.a
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 +7 -0
- data/.env +11 -0
- data/.gitignore +59 -0
- data/.rubocop.yml +61 -0
- data/.yardopts +5 -0
- data/Appraisals +136 -0
- data/Gemfile +3 -0
- data/LICENSE +24 -0
- data/README.md +156 -0
- data/Rakefile +176 -0
- data/circle.yml +61 -0
- data/ddtrace.gemspec +44 -0
- data/docker-compose.yml +42 -0
- data/docs/GettingStarted.md +735 -0
- data/gemfiles/contrib.gemfile +16 -0
- data/gemfiles/contrib_old.gemfile +15 -0
- data/gemfiles/rails30_postgres.gemfile +10 -0
- data/gemfiles/rails30_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails32_mysql2.gemfile +11 -0
- data/gemfiles/rails32_postgres.gemfile +10 -0
- data/gemfiles/rails32_postgres_redis.gemfile +11 -0
- data/gemfiles/rails32_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails4_mysql2.gemfile +9 -0
- data/gemfiles/rails4_postgres.gemfile +9 -0
- data/gemfiles/rails4_postgres_redis.gemfile +10 -0
- data/gemfiles/rails4_postgres_sidekiq.gemfile +11 -0
- data/gemfiles/rails5_mysql2.gemfile +8 -0
- data/gemfiles/rails5_postgres.gemfile +8 -0
- data/gemfiles/rails5_postgres_redis.gemfile +9 -0
- data/gemfiles/rails5_postgres_sidekiq.gemfile +10 -0
- data/lib/ddtrace.rb +73 -0
- data/lib/ddtrace/buffer.rb +52 -0
- data/lib/ddtrace/context.rb +145 -0
- data/lib/ddtrace/contrib/active_record/patcher.rb +94 -0
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +108 -0
- data/lib/ddtrace/contrib/elasticsearch/quantize.rb +22 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +164 -0
- data/lib/ddtrace/contrib/grape/patcher.rb +73 -0
- data/lib/ddtrace/contrib/http/patcher.rb +156 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +150 -0
- data/lib/ddtrace/contrib/rails/action_controller.rb +81 -0
- data/lib/ddtrace/contrib/rails/action_view.rb +110 -0
- data/lib/ddtrace/contrib/rails/active_record.rb +56 -0
- data/lib/ddtrace/contrib/rails/active_support.rb +113 -0
- data/lib/ddtrace/contrib/rails/core_extensions.rb +137 -0
- data/lib/ddtrace/contrib/rails/framework.rb +171 -0
- data/lib/ddtrace/contrib/rails/middlewares.rb +32 -0
- data/lib/ddtrace/contrib/rails/utils.rb +43 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +118 -0
- data/lib/ddtrace/contrib/redis/quantize.rb +30 -0
- data/lib/ddtrace/contrib/redis/tags.rb +19 -0
- data/lib/ddtrace/contrib/sidekiq/tracer.rb +103 -0
- data/lib/ddtrace/contrib/sinatra/tracer.rb +169 -0
- data/lib/ddtrace/distributed.rb +38 -0
- data/lib/ddtrace/encoding.rb +65 -0
- data/lib/ddtrace/error.rb +37 -0
- data/lib/ddtrace/ext/app_types.rb +10 -0
- data/lib/ddtrace/ext/cache.rb +7 -0
- data/lib/ddtrace/ext/distributed.rb +10 -0
- data/lib/ddtrace/ext/errors.rb +10 -0
- data/lib/ddtrace/ext/http.rb +11 -0
- data/lib/ddtrace/ext/net.rb +8 -0
- data/lib/ddtrace/ext/redis.rb +11 -0
- data/lib/ddtrace/ext/sql.rb +8 -0
- data/lib/ddtrace/logger.rb +39 -0
- data/lib/ddtrace/monkey.rb +84 -0
- data/lib/ddtrace/pin.rb +63 -0
- data/lib/ddtrace/provider.rb +21 -0
- data/lib/ddtrace/sampler.rb +49 -0
- data/lib/ddtrace/span.rb +222 -0
- data/lib/ddtrace/tracer.rb +310 -0
- data/lib/ddtrace/transport.rb +162 -0
- data/lib/ddtrace/utils.rb +16 -0
- data/lib/ddtrace/version.rb +9 -0
- data/lib/ddtrace/workers.rb +108 -0
- data/lib/ddtrace/writer.rb +118 -0
- metadata +208 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'ddtrace/span'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
# Common code related to distributed tracing.
|
|
5
|
+
module Distributed
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
# Parses a trace_id and a parent_id, typically sent as headers in
|
|
9
|
+
# a distributed tracing context, and returns a couple of trace_id,parent_id
|
|
10
|
+
# which are garanteed to be both non-zero. This does not 100% ensure they
|
|
11
|
+
# are valid (after all, the caller could mess up data) but at least it
|
|
12
|
+
# sorts out most common errors, such as syntax, nil values, etc.
|
|
13
|
+
# Both headers must be set, else nil values are returned, for both.
|
|
14
|
+
# Reports problem on debug log.
|
|
15
|
+
def parse_trace_headers(trace_id_header, parent_id_header)
|
|
16
|
+
return nil, nil if trace_id_header.nil? || parent_id_header.nil?
|
|
17
|
+
trace_id = trace_id_header.to_i
|
|
18
|
+
parent_id = parent_id_header.to_i
|
|
19
|
+
if trace_id.zero?
|
|
20
|
+
Datadog::Tracer.log.debug("invalid trace_id header: #{trace_id_header}")
|
|
21
|
+
return nil, nil
|
|
22
|
+
end
|
|
23
|
+
if parent_id.zero?
|
|
24
|
+
Datadog::Tracer.log.debug("invalid parent_id header: #{parent_id_header}")
|
|
25
|
+
return nil, nil
|
|
26
|
+
end
|
|
27
|
+
if trace_id < 0 || trace_id >= Datadog::Span::MAX_ID
|
|
28
|
+
Datadog::Tracer.log.debug("trace_id out of range: #{trace_id_header}")
|
|
29
|
+
return nil, nil
|
|
30
|
+
end
|
|
31
|
+
if parent_id < 0 || parent_id >= Datadog::Span::MAX_ID
|
|
32
|
+
Datadog::Tracer.log.debug("parent_id out of range: #{parent_id_header}")
|
|
33
|
+
return nil, nil
|
|
34
|
+
end
|
|
35
|
+
[trace_id, parent_id]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'msgpack'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
# Encoding module that encodes data for the AgentTransport
|
|
6
|
+
module Encoding
|
|
7
|
+
# Encoder interface that provides the logic to encode traces and service
|
|
8
|
+
class Encoder
|
|
9
|
+
attr_reader :content_type
|
|
10
|
+
|
|
11
|
+
# When extending the ``Encoder`` class, ``content_type`` must be set because
|
|
12
|
+
# they're used by the HTTPTransport so that it should not need to know what is
|
|
13
|
+
# the right header to suggest the decoding format to the agent
|
|
14
|
+
def initialize
|
|
15
|
+
@content_type = ''
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Encodes a list of traces, expecting a list of items where each items
|
|
19
|
+
# is a list of spans. Before dump the string in a serialized format all
|
|
20
|
+
# traces are normalized. The traces nesting is not changed.
|
|
21
|
+
def encode_traces(traces)
|
|
22
|
+
to_send = []
|
|
23
|
+
traces.each do |trace|
|
|
24
|
+
to_send << trace.map(&:to_hash)
|
|
25
|
+
end
|
|
26
|
+
encode(to_send)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Encodes services hash
|
|
30
|
+
def encode_services(services)
|
|
31
|
+
encode(services)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Defines the underlying format used during traces or services encoding.
|
|
35
|
+
# This method must be implemented and should only be used by the internal functions.
|
|
36
|
+
def encode(_)
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Encoder for the JSON format
|
|
42
|
+
class JSONEncoder < Encoder
|
|
43
|
+
def initialize
|
|
44
|
+
Datadog::Tracer.log.debug('using JSON encoder; application performance may be degraded')
|
|
45
|
+
@content_type = 'application/json'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def encode(obj)
|
|
49
|
+
JSON.dump(obj)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Encoder for the Msgpack format
|
|
54
|
+
class MsgpackEncoder < Encoder
|
|
55
|
+
def initialize
|
|
56
|
+
Datadog::Tracer.log.debug('using Msgpack encoder')
|
|
57
|
+
@content_type = 'application/msgpack'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def encode(obj)
|
|
61
|
+
MessagePack.pack(obj)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Datadog global namespace
|
|
2
|
+
module Datadog
|
|
3
|
+
# Error is a value-object responsible for sanitizing/encapsulating error data
|
|
4
|
+
class Error
|
|
5
|
+
attr_reader :type, :message, :backtrace
|
|
6
|
+
|
|
7
|
+
def self.build_from(value)
|
|
8
|
+
case value
|
|
9
|
+
when Error then value
|
|
10
|
+
when Array then new(*value)
|
|
11
|
+
when Exception then new(value.class, value.message, value.backtrace)
|
|
12
|
+
when ContainsMessage then new(value.class, value.message)
|
|
13
|
+
else BlankError
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(type = nil, message = nil, backtrace = nil)
|
|
18
|
+
backtrace = Array(backtrace).join("\n")
|
|
19
|
+
@type = sanitize(type)
|
|
20
|
+
@message = sanitize(message)
|
|
21
|
+
@backtrace = sanitize(backtrace)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def sanitize(value)
|
|
27
|
+
value = value.to_s
|
|
28
|
+
|
|
29
|
+
return value if value.encoding == ::Encoding::UTF_8
|
|
30
|
+
|
|
31
|
+
value.encode(::Encoding::UTF_8)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
BlankError = Error.new
|
|
35
|
+
ContainsMessage = ->(v) { v.respond_to?(:message) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Ext
|
|
3
|
+
module DistributedTracing
|
|
4
|
+
# HTTP headers one should set for distributed tracing.
|
|
5
|
+
# These are cross-language (eg: Python, Go and other implementations should honor these)
|
|
6
|
+
HTTP_HEADER_TRACE_ID = 'x-datadog-trace-id'.freeze
|
|
7
|
+
HTTP_HEADER_PARENT_ID = 'x-datadog-parent-id'.freeze
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
LOG_PREFIX = 'ddtrace'.freeze
|
|
5
|
+
|
|
6
|
+
# A custom logger with minor enhancements:
|
|
7
|
+
# - progname defaults to ddtrace to clearly identify Datadog dd-trace-rb related messages
|
|
8
|
+
# - adds last caller stack-trace info to know where the message comes from
|
|
9
|
+
class Logger < ::Logger
|
|
10
|
+
def initialize(*args, &block)
|
|
11
|
+
super
|
|
12
|
+
self.progname = LOG_PREFIX
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add(severity, message = nil, progname = nil, &block)
|
|
16
|
+
where = ''
|
|
17
|
+
|
|
18
|
+
# We are in debug mode, or this is an error, add stack trace to help debugging
|
|
19
|
+
if debug? || severity >= ::Logger::ERROR
|
|
20
|
+
c = caller
|
|
21
|
+
where = "(#{c[1]}) " if c.length > 1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if message.nil?
|
|
25
|
+
if block_given?
|
|
26
|
+
super(severity, message, progname) do
|
|
27
|
+
"[#{self.progname}] #{where}#{yield}"
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
super(severity, message, "[#{self.progname}] #{where}#{progname}")
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
super(severity, "[#{self.progname}] #{where}#{message}")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
alias log add
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'thread'
|
|
2
|
+
|
|
3
|
+
# We import all patchers for every module we support, but this is fine
|
|
4
|
+
# because patchers do not include any 3rd party module nor even our
|
|
5
|
+
# patching code, which is required on demand, when patching.
|
|
6
|
+
require 'ddtrace/contrib/active_record/patcher'
|
|
7
|
+
require 'ddtrace/contrib/elasticsearch/patcher'
|
|
8
|
+
require 'ddtrace/contrib/grape/patcher'
|
|
9
|
+
require 'ddtrace/contrib/redis/patcher'
|
|
10
|
+
require 'ddtrace/contrib/http/patcher'
|
|
11
|
+
|
|
12
|
+
module Datadog
|
|
13
|
+
# Monkey is used for monkey-patching 3rd party libs.
|
|
14
|
+
module Monkey
|
|
15
|
+
@patched = []
|
|
16
|
+
@autopatch_modules = {
|
|
17
|
+
elasticsearch: true,
|
|
18
|
+
http: true,
|
|
19
|
+
redis: true,
|
|
20
|
+
grape: true,
|
|
21
|
+
active_record: false
|
|
22
|
+
}
|
|
23
|
+
# Patchers should expose 2 methods:
|
|
24
|
+
# - patch, which applies our patch if needed. Should be idempotent,
|
|
25
|
+
# can be call twice but should just do nothing the second time.
|
|
26
|
+
# - patched?, which returns true if the module has been succesfully
|
|
27
|
+
# patched (patching might have failed if requirements were not here)
|
|
28
|
+
@patchers = { elasticsearch: Datadog::Contrib::Elasticsearch::Patcher,
|
|
29
|
+
http: Datadog::Contrib::HTTP::Patcher,
|
|
30
|
+
redis: Datadog::Contrib::Redis::Patcher,
|
|
31
|
+
grape: Datadog::Contrib::Grape::Patcher,
|
|
32
|
+
active_record: Datadog::Contrib::ActiveRecord::Patcher }
|
|
33
|
+
@mutex = Mutex.new
|
|
34
|
+
|
|
35
|
+
module_function
|
|
36
|
+
|
|
37
|
+
def autopatch_modules
|
|
38
|
+
@autopatch_modules.clone
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def patch_all
|
|
42
|
+
patch @autopatch_modules
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def patch_module(m)
|
|
46
|
+
@mutex.synchronize do
|
|
47
|
+
patcher = @patchers[m]
|
|
48
|
+
raise "Unsupported module #{m}" unless patcher
|
|
49
|
+
patcher.patch
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def patch(modules)
|
|
54
|
+
modules.each do |k, v|
|
|
55
|
+
patch_module(k) if v
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def get_patched_modules
|
|
60
|
+
patched = autopatch_modules
|
|
61
|
+
@patchers.each do |k, v|
|
|
62
|
+
@mutex.synchronize do
|
|
63
|
+
if v
|
|
64
|
+
patcher = @patchers[k]
|
|
65
|
+
patched[k] = patcher.patched? if patcher
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
patched
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def without_warnings
|
|
73
|
+
# This is typically used when monkey patching functions such as
|
|
74
|
+
# intialize, which Ruby advices you not to. Use cautiously.
|
|
75
|
+
v = $VERBOSE
|
|
76
|
+
$VERBOSE = nil
|
|
77
|
+
begin
|
|
78
|
+
yield
|
|
79
|
+
ensure
|
|
80
|
+
$VERBOSE = v
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/ddtrace/pin.rb
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
|
|
2
|
+
module Datadog
|
|
3
|
+
# A \Pin (a.k.a Patch INfo) is a small class which is used to
|
|
4
|
+
# set tracing metadata on a particular traced object.
|
|
5
|
+
# This is useful if you wanted to, say, trace two different
|
|
6
|
+
# database clusters.
|
|
7
|
+
class Pin
|
|
8
|
+
def self.get_from(obj)
|
|
9
|
+
return nil unless obj.respond_to? :datadog_pin
|
|
10
|
+
obj.datadog_pin
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_accessor :service
|
|
14
|
+
attr_accessor :app
|
|
15
|
+
attr_accessor :tags
|
|
16
|
+
attr_accessor :app_type
|
|
17
|
+
attr_accessor :name
|
|
18
|
+
attr_accessor :tracer
|
|
19
|
+
attr_accessor :config
|
|
20
|
+
|
|
21
|
+
# [ruby19] named parameters would be more idiomatic here, but would break backward compatibility
|
|
22
|
+
def initialize(service, options = { app: nil, tags: nil, app_type: nil, tracer: nil, config: nil })
|
|
23
|
+
@service = service
|
|
24
|
+
@app = options.fetch(:app, nil)
|
|
25
|
+
@tags = options.fetch(:tags, nil)
|
|
26
|
+
@app_type = options.fetch(:app_type, nil)
|
|
27
|
+
@name = nil # this would rarely be overriden as it's really span-specific
|
|
28
|
+
@tracer = options[:tracer] || Datadog.tracer
|
|
29
|
+
@config = options.fetch(:config, nil)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def enabled?
|
|
33
|
+
return @tracer.enabled if @tracer
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def onto(obj)
|
|
38
|
+
unless obj.respond_to? :datadog_pin=
|
|
39
|
+
obj.instance_exec do
|
|
40
|
+
def datadog_pin=(pin)
|
|
41
|
+
Datadog::Tracer.log.debug("Set pin #{pin.service} on #{self.class}.")
|
|
42
|
+
@datadog_pin = pin
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
unless obj.respond_to? :datadog_pin
|
|
48
|
+
obj.instance_exec do
|
|
49
|
+
def datadog_pin
|
|
50
|
+
Datadog::Tracer.log.debug("Get pin from #{self.class}.")
|
|
51
|
+
@datadog_pin
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
obj.datadog_pin = self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_s
|
|
60
|
+
"Pin(service:#{@service},app:#{@app},app_type:#{@app_type},name:#{@name})"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
# DefaultContextProvider is a default context provider that retrieves
|
|
3
|
+
# all contexts from the current thread-local storage. It is suitable for
|
|
4
|
+
# synchronous programming.
|
|
5
|
+
class DefaultContextProvider
|
|
6
|
+
# Initializes the default context provider with a thread-bound context.
|
|
7
|
+
def initialize
|
|
8
|
+
@context = Datadog::ThreadLocalContext.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Sets the current context.
|
|
12
|
+
def context=(ctx)
|
|
13
|
+
@context.local = ctx
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return the current context.
|
|
17
|
+
def context
|
|
18
|
+
@context.local
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
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
|