ddtrace 0.40.0 → 0.45.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|