ddtrace 0.40.0 → 0.45.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/.circleci/config.yml +148 -130
- data/.circleci/images/primary/Dockerfile-3.0.0 +73 -0
- data/.github/workflows/add-milestone-to-pull-requests.yml +42 -0
- data/.github/workflows/create-next-milestone.yml +20 -0
- data/.simplecov +3 -0
- data/Appraisals +414 -135
- data/CHANGELOG.md +1112 -342
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +4 -2
- data/README.md +1 -0
- data/Rakefile +231 -29
- data/ddtrace.gemspec +8 -8
- data/docker-compose.yml +30 -0
- data/docs/DevelopmentGuide.md +12 -2
- data/docs/GettingStarted.md +187 -16
- data/lib/ddtrace.rb +10 -0
- data/lib/ddtrace/auto_instrument.rb +3 -0
- data/lib/ddtrace/auto_instrument_base.rb +6 -0
- data/lib/ddtrace/buffer.rb +259 -52
- data/lib/ddtrace/configuration.rb +19 -0
- data/lib/ddtrace/configuration/options.rb +3 -1
- data/lib/ddtrace/configuration/settings.rb +9 -3
- data/lib/ddtrace/context.rb +18 -0
- data/lib/ddtrace/context_provider.rb +17 -5
- data/lib/ddtrace/contrib/action_cable/integration.rb +7 -0
- data/lib/ddtrace/contrib/action_pack/integration.rb +7 -0
- data/lib/ddtrace/contrib/action_view/event.rb +0 -4
- data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
- data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
- data/lib/ddtrace/contrib/action_view/integration.rb +7 -0
- data/lib/ddtrace/contrib/active_record/events/sql.rb +4 -0
- data/lib/ddtrace/contrib/active_record/integration.rb +7 -0
- data/lib/ddtrace/contrib/active_record/utils.rb +67 -21
- data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +104 -3
- data/lib/ddtrace/contrib/active_support/cache/patcher.rb +21 -0
- data/lib/ddtrace/contrib/active_support/ext.rb +3 -0
- data/lib/ddtrace/contrib/active_support/integration.rb +7 -1
- data/lib/ddtrace/contrib/active_support/notifications/event.rb +10 -0
- data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/ddtrace/contrib/auto_instrument.rb +48 -0
- data/lib/ddtrace/contrib/aws/instrumentation.rb +6 -1
- data/lib/ddtrace/contrib/aws/patcher.rb +0 -1
- data/lib/ddtrace/contrib/aws/services.rb +1 -0
- data/lib/ddtrace/contrib/configurable.rb +2 -0
- data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +6 -5
- data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +38 -0
- data/lib/ddtrace/contrib/cucumber/ext.rb +19 -0
- data/lib/ddtrace/contrib/cucumber/formatter.rb +104 -0
- data/lib/ddtrace/contrib/cucumber/instrumentation.rb +24 -0
- data/lib/ddtrace/contrib/cucumber/integration.rb +45 -0
- data/lib/ddtrace/contrib/cucumber/patcher.rb +23 -0
- data/lib/ddtrace/contrib/dalli/instrumentation.rb +4 -0
- data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +2 -0
- data/lib/ddtrace/contrib/delayed_job/ext.rb +2 -0
- data/lib/ddtrace/contrib/delayed_job/plugin.rb +39 -15
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +4 -0
- data/lib/ddtrace/contrib/ethon/easy_patch.rb +10 -7
- data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
- data/lib/ddtrace/contrib/ethon/multi_patch.rb +4 -0
- data/lib/ddtrace/contrib/excon/middleware.rb +11 -1
- data/lib/ddtrace/contrib/extensions.rb +27 -1
- data/lib/ddtrace/contrib/faraday/middleware.rb +4 -0
- data/lib/ddtrace/contrib/faraday/patcher.rb +1 -1
- data/lib/ddtrace/contrib/grape/configuration/settings.rb +7 -0
- data/lib/ddtrace/contrib/grape/endpoint.rb +53 -18
- data/lib/ddtrace/contrib/grape/ext.rb +1 -0
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +5 -1
- data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -0
- data/lib/ddtrace/contrib/http/instrumentation.rb +6 -2
- data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +32 -0
- data/lib/ddtrace/contrib/httpclient/ext.rb +17 -0
- data/lib/ddtrace/contrib/httpclient/instrumentation.rb +152 -0
- data/lib/ddtrace/contrib/httpclient/integration.rb +43 -0
- data/lib/ddtrace/contrib/httpclient/patcher.rb +35 -0
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +6 -3
- data/lib/ddtrace/contrib/kafka/event.rb +1 -1
- data/lib/ddtrace/contrib/mongodb/subscribers.rb +4 -0
- data/lib/ddtrace/contrib/mysql2/instrumentation.rb +4 -0
- data/lib/ddtrace/contrib/patchable.rb +18 -7
- data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -0
- data/lib/ddtrace/contrib/qless/configuration/settings.rb +35 -0
- data/lib/ddtrace/contrib/qless/ext.rb +20 -0
- data/lib/ddtrace/contrib/qless/integration.rb +38 -0
- data/lib/ddtrace/contrib/qless/patcher.rb +35 -0
- data/lib/ddtrace/contrib/qless/qless_job.rb +72 -0
- data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +32 -0
- data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/que/tracer.rb +2 -1
- data/lib/ddtrace/contrib/racecar/event.rb +4 -0
- data/lib/ddtrace/contrib/rack/integration.rb +7 -0
- data/lib/ddtrace/contrib/rack/middlewares.rb +1 -1
- data/lib/ddtrace/contrib/rack/request_queue.rb +6 -1
- data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +10 -0
- data/lib/ddtrace/contrib/rails/patcher.rb +19 -5
- data/lib/ddtrace/contrib/rails/utils.rb +4 -0
- data/lib/ddtrace/contrib/rake/integration.rb +1 -1
- data/lib/ddtrace/contrib/redis/configuration/resolver.rb +3 -1
- data/lib/ddtrace/contrib/redis/configuration/settings.rb +5 -0
- data/lib/ddtrace/contrib/redis/ext.rb +1 -0
- data/lib/ddtrace/contrib/redis/patcher.rb +20 -3
- data/lib/ddtrace/contrib/redis/quantize.rb +27 -0
- data/lib/ddtrace/contrib/redis/tags.rb +9 -1
- data/lib/ddtrace/contrib/resque/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/resque/integration.rb +1 -1
- data/lib/ddtrace/contrib/resque/resque_job.rb +1 -1
- data/lib/ddtrace/contrib/rest_client/request_patch.rb +4 -0
- data/lib/ddtrace/contrib/rspec/configuration/settings.rb +38 -0
- data/lib/ddtrace/contrib/rspec/example.rb +61 -0
- data/lib/ddtrace/contrib/rspec/example_group.rb +61 -0
- data/lib/ddtrace/contrib/rspec/ext.rb +19 -0
- data/lib/ddtrace/contrib/rspec/integration.rb +46 -0
- data/lib/ddtrace/contrib/rspec/patcher.rb +25 -0
- data/lib/ddtrace/contrib/sequel/database.rb +3 -1
- data/lib/ddtrace/contrib/sequel/dataset.rb +3 -2
- data/lib/ddtrace/contrib/sequel/ext.rb +1 -0
- data/lib/ddtrace/contrib/sequel/utils.rb +16 -5
- data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -1
- data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -1
- data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +2 -2
- data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/sneakers/tracer.rb +17 -20
- data/lib/ddtrace/contrib/status_code_matcher.rb +67 -0
- data/lib/ddtrace/ext/app_types.rb +1 -0
- data/lib/ddtrace/ext/ci.rb +297 -0
- data/lib/ddtrace/ext/distributed.rb +8 -2
- data/lib/ddtrace/ext/git.rb +11 -0
- data/lib/ddtrace/ext/integration.rb +8 -0
- data/lib/ddtrace/ext/runtime.rb +2 -0
- data/lib/ddtrace/ext/test.rb +24 -0
- data/lib/ddtrace/opentracer/distributed_headers.rb +1 -1
- data/lib/ddtrace/propagation/grpc_propagator.rb +18 -6
- data/lib/ddtrace/propagation/http_propagator.rb +17 -2
- data/lib/ddtrace/runtime/identity.rb +4 -5
- data/lib/ddtrace/runtime/metrics.rb +6 -2
- data/lib/ddtrace/sampler.rb +2 -2
- data/lib/ddtrace/sampling/rate_limiter.rb +65 -16
- data/lib/ddtrace/span.rb +152 -27
- data/lib/ddtrace/tracer.rb +25 -13
- data/lib/ddtrace/transport/http/adapters/net.rb +8 -2
- data/lib/ddtrace/transport/http/statistics.rb +14 -1
- data/lib/ddtrace/transport/traces.rb +7 -2
- data/lib/ddtrace/utils.rb +16 -13
- data/lib/ddtrace/utils/forking.rb +52 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers/runtime_metrics.rb +7 -3
- data/lib/ddtrace/writer.rb +19 -1
- metadata +111 -19
|
@@ -20,8 +20,14 @@ module Datadog
|
|
|
20
20
|
PROPAGATION_STYLE_DATADOG = 'Datadog'.freeze
|
|
21
21
|
PROPAGATION_STYLE_B3 = 'B3'.freeze
|
|
22
22
|
PROPAGATION_STYLE_B3_SINGLE_HEADER = 'B3 single header'.freeze
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
PROPAGATION_STYLE_INJECT_ENV = 'DD_PROPAGATION_STYLE_INJECT'.freeze
|
|
24
|
+
PROPAGATION_STYLE_EXTRACT_ENV = 'DD_PROPAGATION_STYLE_EXTRACT'.freeze
|
|
25
|
+
# Note: the below inject/extract values are deprecated and were defined erronously
|
|
26
|
+
# they were never part of the datadog language client standard or documentation
|
|
27
|
+
# some users may already be relying on them, but we should look to remove these in the future
|
|
28
|
+
# or before 1.0.
|
|
29
|
+
PROPAGATION_INJECT_STYLE_ENV_OLD = 'DD_PROPAGATION_INJECT_STYLE'.freeze
|
|
30
|
+
PROPAGATION_EXTRACT_STYLE_ENV_OLD = 'DD_PROPAGATION_EXTRACT_STYLE'.freeze
|
|
25
31
|
|
|
26
32
|
# gRPC metadata keys for distributed tracing. https://github.com/grpc/grpc-go/blob/v1.10.x/Documentation/grpc-metadata.md
|
|
27
33
|
GRPC_METADATA_TRACE_ID = 'x-datadog-trace-id'.freeze
|
data/lib/ddtrace/ext/runtime.rb
CHANGED
|
@@ -7,8 +7,10 @@ module Datadog
|
|
|
7
7
|
LANG = 'ruby'.freeze
|
|
8
8
|
LANG_INTERPRETER = (RUBY_ENGINE + '-' + RUBY_PLATFORM).freeze
|
|
9
9
|
LANG_VERSION = RUBY_VERSION
|
|
10
|
+
RUBY_ENGINE = ::RUBY_ENGINE # e.g. 'ruby', 'jruby', 'truffleruby'
|
|
10
11
|
TRACER_VERSION = Datadog::VERSION::STRING
|
|
11
12
|
|
|
13
|
+
TAG_ID = 'runtime-id'.freeze
|
|
12
14
|
TAG_LANG = 'language'.freeze
|
|
13
15
|
|
|
14
16
|
# Metrics
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module Ext
|
|
3
|
+
# Defines constants for test tags
|
|
4
|
+
module Test
|
|
5
|
+
TAG_ARGUMENTS = 'test.arguments'.freeze
|
|
6
|
+
TAG_FRAMEWORK = 'test.framework'.freeze
|
|
7
|
+
TAG_NAME = 'test.name'.freeze
|
|
8
|
+
TAG_SKIP_REASON = 'test.skip_reason'.freeze
|
|
9
|
+
TAG_STATUS = 'test.status'.freeze
|
|
10
|
+
TAG_SUITE = 'test.suite'.freeze
|
|
11
|
+
TAG_TRAITS = 'test.traits'.freeze
|
|
12
|
+
TAG_TYPE = 'test.type'.freeze
|
|
13
|
+
|
|
14
|
+
# TODO: is there a better place for SPAN_KIND?
|
|
15
|
+
TAG_SPAN_KIND = 'span.kind'.freeze
|
|
16
|
+
|
|
17
|
+
module Status
|
|
18
|
+
PASS = 'pass'.freeze
|
|
19
|
+
FAIL = 'fail'.freeze
|
|
20
|
+
SKIP = 'skip'.freeze
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -44,7 +44,7 @@ module Datadog
|
|
|
44
44
|
|
|
45
45
|
def id(header)
|
|
46
46
|
value = @carrier[header].to_i
|
|
47
|
-
return if value.zero? || value >= Datadog::Span::
|
|
47
|
+
return if value.zero? || value >= Datadog::Span::EXTERNAL_MAX_ID
|
|
48
48
|
value < 0 ? value + 0x1_0000_0000_0000_0000 : value
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -38,24 +38,36 @@ module Datadog
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def trace_id
|
|
41
|
-
value =
|
|
42
|
-
value if (1..Span::
|
|
41
|
+
value = metadata_for_key(GRPC_METADATA_TRACE_ID).to_i
|
|
42
|
+
value if (1..Span::EXTERNAL_MAX_ID).cover? value
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def parent_id
|
|
46
|
-
value =
|
|
47
|
-
value if (1..Span::
|
|
46
|
+
value = metadata_for_key(GRPC_METADATA_PARENT_ID).to_i
|
|
47
|
+
value if (1..Span::EXTERNAL_MAX_ID).cover? value
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def sampling_priority
|
|
51
|
-
value =
|
|
51
|
+
value = metadata_for_key(GRPC_METADATA_SAMPLING_PRIORITY)
|
|
52
52
|
value && value.to_i
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def origin
|
|
56
|
-
value =
|
|
56
|
+
value = metadata_for_key(GRPC_METADATA_ORIGIN)
|
|
57
57
|
value if value != ''
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def metadata_for_key(key)
|
|
63
|
+
# metadata values can be arrays (multiple headers with the same key)
|
|
64
|
+
value = @metadata[key]
|
|
65
|
+
if value.is_a?(Array)
|
|
66
|
+
value.first
|
|
67
|
+
else
|
|
68
|
+
value
|
|
69
|
+
end
|
|
70
|
+
end
|
|
59
71
|
end
|
|
60
72
|
end
|
|
61
73
|
end
|
|
@@ -26,7 +26,14 @@ module Datadog
|
|
|
26
26
|
# Inject all configured propagation styles
|
|
27
27
|
::Datadog.configuration.distributed_tracing.propagation_inject_style.each do |style|
|
|
28
28
|
propagator = PROPAGATION_STYLES[style]
|
|
29
|
-
|
|
29
|
+
begin
|
|
30
|
+
propagator.inject!(context, env) unless propagator.nil?
|
|
31
|
+
rescue => e
|
|
32
|
+
Datadog.logger.error(
|
|
33
|
+
'Error injecting propagated context into the environment. ' \
|
|
34
|
+
"Cause: #{e} Location: #{e.backtrace.first}"
|
|
35
|
+
)
|
|
36
|
+
end
|
|
30
37
|
end
|
|
31
38
|
end
|
|
32
39
|
|
|
@@ -42,7 +49,15 @@ module Datadog
|
|
|
42
49
|
|
|
43
50
|
# Extract context
|
|
44
51
|
# DEV: `propagator.extract` will return `nil`, where `HTTPPropagator#extract` will not
|
|
45
|
-
|
|
52
|
+
begin
|
|
53
|
+
extracted_context = propagator.extract(env)
|
|
54
|
+
rescue => e
|
|
55
|
+
Datadog.logger.error(
|
|
56
|
+
'Error extracting propagated context from the environment. ' \
|
|
57
|
+
"Cause: #{e} Location: #{e.backtrace.first}"
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
46
61
|
# Skip this style if no valid headers were found
|
|
47
62
|
next if extracted_context.nil?
|
|
48
63
|
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
require 'securerandom'
|
|
2
2
|
require 'ddtrace/ext/runtime'
|
|
3
|
+
require 'ddtrace/utils/forking'
|
|
3
4
|
|
|
4
5
|
module Datadog
|
|
5
6
|
module Runtime
|
|
6
7
|
# For runtime identity
|
|
7
8
|
module Identity
|
|
9
|
+
extend Datadog::Utils::Forking
|
|
10
|
+
|
|
8
11
|
module_function
|
|
9
12
|
|
|
10
13
|
# Retrieves number of classes from runtime
|
|
11
14
|
def id
|
|
12
|
-
@pid ||= Process.pid
|
|
13
15
|
@id ||= SecureRandom.uuid
|
|
14
16
|
|
|
15
17
|
# Check if runtime has changed, e.g. forked.
|
|
16
|
-
|
|
17
|
-
@pid = Process.pid
|
|
18
|
-
@id = SecureRandom.uuid
|
|
19
|
-
end
|
|
18
|
+
after_fork! { @id = SecureRandom.uuid }
|
|
20
19
|
|
|
21
20
|
@id
|
|
22
21
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'ddtrace/ext/integration'
|
|
1
2
|
require 'ddtrace/ext/runtime'
|
|
2
3
|
|
|
3
4
|
require 'ddtrace/metrics'
|
|
@@ -25,8 +26,11 @@ module Datadog
|
|
|
25
26
|
# Register service as associated with metrics
|
|
26
27
|
register_service(span.service) unless span.service.nil?
|
|
27
28
|
|
|
28
|
-
# Tag span with language and runtime ID for association with metrics
|
|
29
|
-
|
|
29
|
+
# Tag span with language and runtime ID for association with metrics.
|
|
30
|
+
# We only tag spans that performed internal application work.
|
|
31
|
+
unless span.get_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE)
|
|
32
|
+
span.set_tag(Ext::Runtime::TAG_LANG, Runtime::Identity.lang)
|
|
33
|
+
end
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
# Associate service with runtime metrics
|
data/lib/ddtrace/sampler.rb
CHANGED
|
@@ -61,11 +61,11 @@ module Datadog
|
|
|
61
61
|
|
|
62
62
|
def sample_rate=(sample_rate)
|
|
63
63
|
@sample_rate = sample_rate
|
|
64
|
-
@sampling_id_threshold = sample_rate * Span::
|
|
64
|
+
@sampling_id_threshold = sample_rate * Span::EXTERNAL_MAX_ID
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def sample?(span)
|
|
68
|
-
((span.trace_id * KNUTH_FACTOR) % Datadog::Span::
|
|
68
|
+
((span.trace_id * KNUTH_FACTOR) % Datadog::Span::EXTERNAL_MAX_ID) <= @sampling_id_threshold
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def sample!(span)
|
|
@@ -38,6 +38,10 @@ module Datadog
|
|
|
38
38
|
@tokens = max_tokens
|
|
39
39
|
@total_messages = 0
|
|
40
40
|
@conforming_messages = 0
|
|
41
|
+
@prev_conforming_messages = nil
|
|
42
|
+
@prev_total_messages = nil
|
|
43
|
+
@current_window = nil
|
|
44
|
+
|
|
41
45
|
@last_refill = Utils::Time.get_time
|
|
42
46
|
end
|
|
43
47
|
|
|
@@ -47,28 +51,17 @@ module Datadog
|
|
|
47
51
|
# If it does, return +true+ and remove +size+
|
|
48
52
|
# tokens from the bucket.
|
|
49
53
|
# If it does not, return +false+ without affecting
|
|
50
|
-
# the tokens
|
|
54
|
+
# the tokens from the bucket.
|
|
51
55
|
#
|
|
52
56
|
# @return [Boolean] +true+ if message conforms with current bucket limit
|
|
53
57
|
def allow?(size)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
refill_since_last_message
|
|
58
|
-
|
|
59
|
-
increment_total_count
|
|
60
|
-
|
|
61
|
-
return false if @tokens < size
|
|
62
|
-
|
|
63
|
-
increment_conforming_count
|
|
64
|
-
|
|
65
|
-
@tokens -= size
|
|
66
|
-
|
|
67
|
-
true
|
|
58
|
+
allowed = should_allow?(size)
|
|
59
|
+
update_rate_counts(allowed)
|
|
60
|
+
allowed
|
|
68
61
|
end
|
|
69
62
|
|
|
70
63
|
# Ratio of 'conformance' per 'total messages' checked
|
|
71
|
-
#
|
|
64
|
+
# averaged for the past 2 buckets
|
|
72
65
|
#
|
|
73
66
|
# Returns +1.0+ when no messages have been checked yet.
|
|
74
67
|
#
|
|
@@ -77,6 +70,20 @@ module Datadog
|
|
|
77
70
|
return 0.0 if @rate.zero?
|
|
78
71
|
return 1.0 if @rate < 0 || @total_messages.zero?
|
|
79
72
|
|
|
73
|
+
return current_window_rate if @prev_conforming_messages.nil? || @prev_total_messages.nil?
|
|
74
|
+
|
|
75
|
+
(@conforming_messages.to_f + @prev_conforming_messages.to_f) / (@total_messages + @prev_total_messages)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Ratio of 'conformance' per 'total messages' checked
|
|
79
|
+
# on this bucket
|
|
80
|
+
#
|
|
81
|
+
# Returns +1.0+ when no messages have been checked yet.
|
|
82
|
+
#
|
|
83
|
+
# @return [Float] Conformance ratio, between +[0,1]+
|
|
84
|
+
def current_window_rate
|
|
85
|
+
return 1.0 if @total_messages.zero?
|
|
86
|
+
|
|
80
87
|
@conforming_messages.to_f / @total_messages
|
|
81
88
|
end
|
|
82
89
|
|
|
@@ -91,6 +98,8 @@ module Datadog
|
|
|
91
98
|
now = Utils::Time.get_time
|
|
92
99
|
elapsed = now - @last_refill
|
|
93
100
|
|
|
101
|
+
# Update the number of available tokens, but ensure we do not exceed the max
|
|
102
|
+
# we return the min of tokens + rate*elapsed, or max tokens
|
|
94
103
|
refill_tokens(@rate * elapsed)
|
|
95
104
|
|
|
96
105
|
@last_refill = now
|
|
@@ -108,6 +117,46 @@ module Datadog
|
|
|
108
117
|
def increment_conforming_count
|
|
109
118
|
@conforming_messages += 1
|
|
110
119
|
end
|
|
120
|
+
|
|
121
|
+
def should_allow?(size)
|
|
122
|
+
# rate limit of 0 blocks everything
|
|
123
|
+
return false if @rate.zero?
|
|
124
|
+
|
|
125
|
+
# negative rate limit disables rate limiting
|
|
126
|
+
return true if @rate < 0
|
|
127
|
+
|
|
128
|
+
refill_since_last_message
|
|
129
|
+
|
|
130
|
+
# if tokens < 1 we don't allow?
|
|
131
|
+
return false if @tokens < size
|
|
132
|
+
|
|
133
|
+
@tokens -= size
|
|
134
|
+
|
|
135
|
+
true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Sets and Updates the past two 1 second windows for which
|
|
139
|
+
# the rate limiter must compute it's rate over and updates
|
|
140
|
+
# the total count, and conforming message count if +allowed+
|
|
141
|
+
def update_rate_counts(allowed)
|
|
142
|
+
now = Utils::Time.get_time
|
|
143
|
+
|
|
144
|
+
# No tokens have been seen yet, start a new window
|
|
145
|
+
if @current_window.nil?
|
|
146
|
+
@current_window = now
|
|
147
|
+
# If more than 1 second has past since last window, reset
|
|
148
|
+
elsif now - @current_window >= 1
|
|
149
|
+
@prev_conforming_messages = @conforming_messages
|
|
150
|
+
@prev_total_messages = @total_messages
|
|
151
|
+
@conforming_messages = 0
|
|
152
|
+
@total_messages = 0
|
|
153
|
+
@current_window = now
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
increment_conforming_count if allowed
|
|
157
|
+
|
|
158
|
+
increment_total_count
|
|
159
|
+
end
|
|
111
160
|
end
|
|
112
161
|
|
|
113
162
|
# \RateLimiter that accepts all resources,
|
data/lib/ddtrace/span.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'time'
|
|
2
4
|
require 'thread'
|
|
3
5
|
|
|
@@ -8,6 +10,7 @@ require 'ddtrace/environment'
|
|
|
8
10
|
require 'ddtrace/analytics'
|
|
9
11
|
require 'ddtrace/forced_tracing'
|
|
10
12
|
require 'ddtrace/diagnostics/health'
|
|
13
|
+
require 'ddtrace/utils/time'
|
|
11
14
|
|
|
12
15
|
module Datadog
|
|
13
16
|
# Represents a logical unit of work in the system. Each trace consists of one or more spans.
|
|
@@ -24,24 +27,26 @@ module Datadog
|
|
|
24
27
|
# The max value for a \Span identifier.
|
|
25
28
|
# Span and trace identifiers should be strictly positive and strictly inferior to this limit.
|
|
26
29
|
#
|
|
27
|
-
# Limited to
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
+
# Limited to +2<<62-1+ positive integers, as Ruby is able to represent such numbers "inline",
|
|
31
|
+
# inside a +VALUE+ scalar, thus not requiring memory allocation.
|
|
32
|
+
#
|
|
33
|
+
# The range of IDs also has to consider portability across different languages and platforms.
|
|
34
|
+
RUBY_MAX_ID = (1 << 62) - 1
|
|
30
35
|
|
|
31
36
|
# While we only generate 63-bit integers due to limitations in other languages, we support
|
|
32
37
|
# parsing 64-bit integers for distributed tracing since an upstream system may generate one
|
|
33
|
-
EXTERNAL_MAX_ID =
|
|
38
|
+
EXTERNAL_MAX_ID = 1 << 64
|
|
34
39
|
|
|
35
40
|
# This limit is for numeric tags because uint64 could end up rounded.
|
|
36
|
-
NUMERIC_TAG_SIZE_RANGE = (-
|
|
41
|
+
NUMERIC_TAG_SIZE_RANGE = (-1 << 53..1 << 53)
|
|
37
42
|
|
|
38
43
|
attr_accessor :name, :service, :resource, :span_type,
|
|
39
|
-
:start_time, :end_time,
|
|
40
44
|
:span_id, :trace_id, :parent_id,
|
|
41
45
|
:status, :sampled,
|
|
42
|
-
:tracer, :context
|
|
46
|
+
:tracer, :context, :duration, :start_time, :end_time
|
|
43
47
|
|
|
44
48
|
attr_reader :parent
|
|
49
|
+
|
|
45
50
|
# Create a new span linked to the given tracer. Call the \Tracer method <tt>start_span()</tt>
|
|
46
51
|
# and then <tt>finish()</tt> once the tracer operation is over.
|
|
47
52
|
#
|
|
@@ -72,11 +77,20 @@ module Datadog
|
|
|
72
77
|
@parent = nil
|
|
73
78
|
@sampled = true
|
|
74
79
|
|
|
75
|
-
@start_time = nil # set by Tracer.start_span
|
|
76
|
-
@end_time = nil # set by Span.finish
|
|
77
|
-
|
|
78
80
|
@allocation_count_start = now_allocations
|
|
79
81
|
@allocation_count_finish = @allocation_count_start
|
|
82
|
+
|
|
83
|
+
# start_time and end_time track wall clock. In Ruby, wall clock
|
|
84
|
+
# has less accuracy than monotonic clock, so if possible we look to only use wall clock
|
|
85
|
+
# to measure duration when a time is supplied by the user, or if monotonic clock
|
|
86
|
+
# is unsupported.
|
|
87
|
+
@start_time = nil
|
|
88
|
+
@end_time = nil
|
|
89
|
+
|
|
90
|
+
# duration_start and duration_end track monotonic clock, and may remain nil in cases where it
|
|
91
|
+
# is known that we have to use wall clock to measure duration.
|
|
92
|
+
@duration_start = nil
|
|
93
|
+
@duration_end = nil
|
|
80
94
|
end
|
|
81
95
|
|
|
82
96
|
# Set the given key / value tag pair on the span. Keys and values
|
|
@@ -160,6 +174,28 @@ module Datadog
|
|
|
160
174
|
set_tag(Ext::Errors::STACK, e.backtrace) unless e.backtrace.empty?
|
|
161
175
|
end
|
|
162
176
|
|
|
177
|
+
# Mark the span started at the current time.
|
|
178
|
+
def start(start_time = nil)
|
|
179
|
+
# A span should not be started twice. However, this is existing
|
|
180
|
+
# behavior and so we maintain it for backward compatibility for those
|
|
181
|
+
# who are using async manual instrumentation that may rely on this
|
|
182
|
+
|
|
183
|
+
@start_time = start_time || Time.now.utc
|
|
184
|
+
@duration_start = start_time.nil? ? duration_marker : nil
|
|
185
|
+
|
|
186
|
+
self
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# for backwards compatibility
|
|
190
|
+
def start_time=(time)
|
|
191
|
+
time.tap { start(time) }
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# for backwards compatibility
|
|
195
|
+
def end_time=(time)
|
|
196
|
+
time.tap { finish(time) }
|
|
197
|
+
end
|
|
198
|
+
|
|
163
199
|
# Mark the span finished at the current time and submit it.
|
|
164
200
|
def finish(finish_time = nil)
|
|
165
201
|
# A span should not be finished twice. Note that this is not thread-safe,
|
|
@@ -170,12 +206,15 @@ module Datadog
|
|
|
170
206
|
|
|
171
207
|
@allocation_count_finish = now_allocations
|
|
172
208
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
#
|
|
176
|
-
|
|
209
|
+
now = Time.now.utc
|
|
210
|
+
|
|
211
|
+
# Provide a default start_time if unset.
|
|
212
|
+
# Using `now` here causes duration to be 0; this is expected
|
|
213
|
+
# behavior when start_time is unknown.
|
|
214
|
+
start(finish_time || now) unless started?
|
|
177
215
|
|
|
178
|
-
@end_time = finish_time
|
|
216
|
+
@end_time = finish_time || now
|
|
217
|
+
@duration_end = finish_time.nil? ? duration_marker : nil
|
|
179
218
|
|
|
180
219
|
# Finish does not really do anything if the span is not bound to a tracer and a context.
|
|
181
220
|
return self if @tracer.nil? || @context.nil?
|
|
@@ -195,11 +234,6 @@ module Datadog
|
|
|
195
234
|
self
|
|
196
235
|
end
|
|
197
236
|
|
|
198
|
-
# Return whether the span is finished or not.
|
|
199
|
-
def finished?
|
|
200
|
-
!@end_time.nil?
|
|
201
|
-
end
|
|
202
|
-
|
|
203
237
|
# Return a string representation of the span.
|
|
204
238
|
def to_s
|
|
205
239
|
"Span(name:#{@name},sid:#{@span_id},tid:#{@trace_id},pid:#{@parent_id})"
|
|
@@ -246,19 +280,76 @@ module Datadog
|
|
|
246
280
|
error: @status
|
|
247
281
|
}
|
|
248
282
|
|
|
249
|
-
if
|
|
250
|
-
h[:start] =
|
|
251
|
-
h[:duration] =
|
|
283
|
+
if finished?
|
|
284
|
+
h[:start] = start_time_nano
|
|
285
|
+
h[:duration] = duration_nano
|
|
252
286
|
end
|
|
253
287
|
|
|
254
288
|
h
|
|
255
289
|
end
|
|
256
290
|
|
|
291
|
+
# MessagePack serializer interface. Making this object
|
|
292
|
+
# respond to `#to_msgpack` allows it to be automatically
|
|
293
|
+
# serialized by MessagePack.
|
|
294
|
+
#
|
|
295
|
+
# This is more efficient than doing +MessagePack.pack(span.to_hash)+
|
|
296
|
+
# as we don't have to create an intermediate Hash.
|
|
297
|
+
#
|
|
298
|
+
# @param packer [MessagePack::Packer] serialization buffer, can be +nil+ with JRuby
|
|
299
|
+
def to_msgpack(packer = nil)
|
|
300
|
+
# As of 1.3.3, JRuby implementation doesn't pass an existing packer
|
|
301
|
+
packer ||= MessagePack::Packer.new
|
|
302
|
+
|
|
303
|
+
if finished?
|
|
304
|
+
packer.write_map_header(13) # Set header with how many elements in the map
|
|
305
|
+
|
|
306
|
+
packer.write('start')
|
|
307
|
+
packer.write(start_time_nano)
|
|
308
|
+
|
|
309
|
+
packer.write('duration')
|
|
310
|
+
packer.write(duration_nano)
|
|
311
|
+
else
|
|
312
|
+
packer.write_map_header(11) # Set header with how many elements in the map
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# DEV: We use strings as keys here, instead of symbols, as
|
|
316
|
+
# DEV: MessagePack will ultimately convert them to strings.
|
|
317
|
+
# DEV: By providing strings directly, we skip this indirection operation.
|
|
318
|
+
packer.write('span_id')
|
|
319
|
+
packer.write(@span_id)
|
|
320
|
+
packer.write('parent_id')
|
|
321
|
+
packer.write(@parent_id)
|
|
322
|
+
packer.write('trace_id')
|
|
323
|
+
packer.write(@trace_id)
|
|
324
|
+
packer.write('name')
|
|
325
|
+
packer.write(@name)
|
|
326
|
+
packer.write('service')
|
|
327
|
+
packer.write(@service)
|
|
328
|
+
packer.write('resource')
|
|
329
|
+
packer.write(@resource)
|
|
330
|
+
packer.write('type')
|
|
331
|
+
packer.write(@span_type)
|
|
332
|
+
packer.write('meta')
|
|
333
|
+
packer.write(@meta)
|
|
334
|
+
packer.write('metrics')
|
|
335
|
+
packer.write(@metrics)
|
|
336
|
+
packer.write('allocations')
|
|
337
|
+
packer.write(allocations)
|
|
338
|
+
packer.write('error')
|
|
339
|
+
packer.write(@status)
|
|
340
|
+
packer
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# JSON serializer interface.
|
|
344
|
+
# Used by older version of the transport.
|
|
345
|
+
def to_json(*args)
|
|
346
|
+
to_hash.to_json(*args)
|
|
347
|
+
end
|
|
348
|
+
|
|
257
349
|
# Return a human readable version of the span
|
|
258
350
|
def pretty_print(q)
|
|
259
|
-
start_time = (
|
|
260
|
-
end_time = (
|
|
261
|
-
duration = ((@end_time - @start_time) * 1e9).to_i rescue 0
|
|
351
|
+
start_time = (self.start_time.to_f * 1e9).to_i
|
|
352
|
+
end_time = (self.end_time.to_f * 1e9).to_i
|
|
262
353
|
q.group 0 do
|
|
263
354
|
q.breakable
|
|
264
355
|
q.text "Name: #{@name}\n"
|
|
@@ -271,7 +362,7 @@ module Datadog
|
|
|
271
362
|
q.text "Error: #{@status}\n"
|
|
272
363
|
q.text "Start: #{start_time}\n"
|
|
273
364
|
q.text "End: #{end_time}\n"
|
|
274
|
-
q.text "Duration: #{duration}\n"
|
|
365
|
+
q.text "Duration: #{duration.to_f if finished?}\n"
|
|
275
366
|
q.text "Allocations: #{allocations}\n"
|
|
276
367
|
q.group(2, 'Tags: [', "]\n") do
|
|
277
368
|
q.breakable
|
|
@@ -288,8 +379,30 @@ module Datadog
|
|
|
288
379
|
end
|
|
289
380
|
end
|
|
290
381
|
|
|
382
|
+
# Return whether the duration is started or not
|
|
383
|
+
def started?
|
|
384
|
+
!@start_time.nil?
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Return whether the duration is finished or not.
|
|
388
|
+
def finished?
|
|
389
|
+
!@end_time.nil?
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def duration
|
|
393
|
+
if @duration_end.nil? || @duration_start.nil?
|
|
394
|
+
@end_time - @start_time
|
|
395
|
+
else
|
|
396
|
+
@duration_end - @duration_start
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
291
400
|
private
|
|
292
401
|
|
|
402
|
+
def duration_marker
|
|
403
|
+
Utils::Time.get_time
|
|
404
|
+
end
|
|
405
|
+
|
|
293
406
|
if defined?(JRUBY_VERSION) || Gem::Version.new(RUBY_VERSION) < Gem::Version.new(VERSION::MINIMUM_RUBY_VERSION)
|
|
294
407
|
def now_allocations
|
|
295
408
|
0
|
|
@@ -303,5 +416,17 @@ module Datadog
|
|
|
303
416
|
GC.stat(:total_allocated_objects)
|
|
304
417
|
end
|
|
305
418
|
end
|
|
419
|
+
|
|
420
|
+
# Used for serialization
|
|
421
|
+
# @return [Integer] in nanoseconds since Epoch
|
|
422
|
+
def start_time_nano
|
|
423
|
+
@start_time.to_i * 1000000000 + @start_time.nsec
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
# Used for serialization
|
|
427
|
+
# @return [Integer] in nanoseconds since Epoch
|
|
428
|
+
def duration_nano
|
|
429
|
+
(duration * 1e9).to_i
|
|
430
|
+
end
|
|
306
431
|
end
|
|
307
432
|
end
|