ddtrace 0.46.0 → 0.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +52 -12
- data/.circleci/images/primary/{Dockerfile-jruby-9.2 → Dockerfile-jruby-9.2-latest} +2 -1
- data/.circleci/images/primary/Dockerfile-jruby-9.2.0.0 +73 -0
- data/.circleci/images/primary/Dockerfile-truffleruby-21.0.0 +73 -0
- data/.github/workflows/create-next-milestone.yml +2 -2
- data/.rubocop_todo.yml +3 -2
- data/.simplecov +6 -0
- data/Appraisals +1 -1
- data/CHANGELOG.md +83 -1
- data/Gemfile +19 -4
- data/LICENSE-3rdparty.csv +2 -0
- data/docker-compose.yml +75 -7
- data/docs/GettingStarted.md +61 -8
- data/lib/ddtrace/configuration.rb +92 -23
- data/lib/ddtrace/configuration/options.rb +2 -4
- data/lib/ddtrace/context_provider.rb +0 -2
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +97 -26
- data/lib/ddtrace/contrib/aws/services.rb +1 -0
- data/lib/ddtrace/contrib/configurable.rb +63 -39
- data/lib/ddtrace/contrib/configuration/resolver.rb +70 -5
- data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +19 -17
- data/lib/ddtrace/contrib/configuration/settings.rb +7 -6
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -0
- data/lib/ddtrace/contrib/extensions.rb +26 -3
- data/lib/ddtrace/contrib/httpclient/instrumentation.rb +12 -16
- data/lib/ddtrace/contrib/httpclient/patcher.rb +5 -2
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +12 -17
- data/lib/ddtrace/contrib/httprb/patcher.rb +5 -2
- data/lib/ddtrace/contrib/patcher.rb +8 -5
- data/lib/ddtrace/contrib/presto/patcher.rb +5 -2
- data/lib/ddtrace/contrib/rails/patcher.rb +6 -2
- data/lib/ddtrace/contrib/redis/configuration/resolver.rb +11 -4
- data/lib/ddtrace/contrib/resque/integration.rb +1 -1
- data/lib/ddtrace/ext/runtime.rb +2 -0
- data/lib/ddtrace/patcher.rb +23 -1
- data/lib/ddtrace/pin.rb +5 -9
- data/lib/ddtrace/runtime/cgroup.rb +1 -1
- data/lib/ddtrace/runtime/container.rb +25 -27
- data/lib/ddtrace/runtime/identity.rb +8 -0
- data/lib/ddtrace/sync_writer.rb +5 -2
- data/lib/ddtrace/tracer.rb +6 -4
- data/lib/ddtrace/transport/http.rb +14 -5
- data/lib/ddtrace/transport/http/adapters/net.rb +18 -4
- data/lib/ddtrace/transport/http/builder.rb +5 -1
- data/lib/ddtrace/transport/http/env.rb +8 -0
- data/lib/ddtrace/transport/io/response.rb +1 -3
- data/lib/ddtrace/transport/io/traces.rb +6 -0
- data/lib/ddtrace/transport/traces.rb +15 -1
- data/lib/ddtrace/utils/compression.rb +27 -0
- data/lib/ddtrace/utils/object_set.rb +41 -0
- data/lib/ddtrace/utils/only_once.rb +40 -0
- data/lib/ddtrace/utils/sequence.rb +17 -0
- data/lib/ddtrace/utils/string_table.rb +45 -0
- data/lib/ddtrace/utils/time.rb +7 -0
- data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
- data/lib/ddtrace/vendor/multipart-post/multipart.rb +12 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +8 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +116 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +57 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +135 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +9 -0
- data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +32 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers/async.rb +3 -3
- data/lib/ddtrace/workers/loop.rb +14 -3
- data/lib/ddtrace/workers/queue.rb +1 -0
- data/lib/ddtrace/workers/trace_writer.rb +1 -0
- data/lib/ddtrace/writer.rb +4 -1
- metadata +21 -4
@@ -21,7 +21,7 @@ module Datadog
|
|
21
21
|
filepath = "/proc/#{process}/cgroup"
|
22
22
|
|
23
23
|
if File.exist?(filepath)
|
24
|
-
File.
|
24
|
+
File.foreach("/proc/#{process}/cgroup") do |line|
|
25
25
|
line = line.strip
|
26
26
|
descriptors << parse(line) unless line.empty?
|
27
27
|
end
|
@@ -32,39 +32,37 @@ module Datadog
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def descriptor
|
35
|
-
@descriptor ||=
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
next if path.nil?
|
35
|
+
@descriptor ||= Descriptor.new.tap do |descriptor|
|
36
|
+
begin
|
37
|
+
Cgroup.descriptors.each do |cgroup_descriptor|
|
38
|
+
# Parse container data from cgroup descriptor
|
39
|
+
path = cgroup_descriptor.path
|
40
|
+
next if path.nil?
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
# Split path into parts
|
43
|
+
parts = path.split('/')
|
44
|
+
parts.shift # Remove leading empty part
|
45
|
+
next if parts.length < 2
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
# Read info from path
|
48
|
+
platform = parts[0]
|
49
|
+
container_id = parts[-1][CONTAINER_REGEX]
|
50
|
+
task_uid = parts[-2][POD_REGEX]
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
# If container ID wasn't found, ignore.
|
53
|
+
# Path might describe a non-container environment.
|
54
|
+
next if container_id.nil?
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
descriptor.platform = platform
|
57
|
+
descriptor.container_id = container_id
|
58
|
+
descriptor.task_uid = task_uid
|
60
59
|
|
61
|
-
|
62
|
-
end
|
63
|
-
rescue StandardError => e
|
64
|
-
Datadog.logger.error(
|
65
|
-
"Error while parsing container info. Cause: #{e.message} Location: #{e.backtrace.first}"
|
66
|
-
)
|
60
|
+
break
|
67
61
|
end
|
62
|
+
rescue StandardError => e
|
63
|
+
Datadog.logger.error(
|
64
|
+
"Error while parsing container info. Cause: #{e.message} Location: #{e.backtrace.first}"
|
65
|
+
)
|
68
66
|
end
|
69
67
|
end
|
70
68
|
end
|
@@ -24,10 +24,18 @@ module Datadog
|
|
24
24
|
Ext::Runtime::LANG
|
25
25
|
end
|
26
26
|
|
27
|
+
def lang_engine
|
28
|
+
Ext::Runtime::LANG_ENGINE
|
29
|
+
end
|
30
|
+
|
27
31
|
def lang_interpreter
|
28
32
|
Ext::Runtime::LANG_INTERPRETER
|
29
33
|
end
|
30
34
|
|
35
|
+
def lang_platform
|
36
|
+
Ext::Runtime::LANG_PLATFORM
|
37
|
+
end
|
38
|
+
|
31
39
|
def lang_version
|
32
40
|
Ext::Runtime::LANG_VERSION
|
33
41
|
end
|
data/lib/ddtrace/sync_writer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'ddtrace/ext/net'
|
2
2
|
require 'ddtrace/runtime/socket'
|
3
3
|
require 'ddtrace/runtime/metrics'
|
4
|
+
require 'ddtrace/utils/only_once'
|
4
5
|
|
5
6
|
module Datadog
|
6
7
|
# SyncWriter flushes both services and traces synchronously
|
@@ -10,6 +11,8 @@ module Datadog
|
|
10
11
|
# the separate `datadog-lambda` uses it as of February 2021:
|
11
12
|
# <https://github.com/DataDog/datadog-lambda-rb/blob/c15f0f0916c90123416dc44e7d6800ef4a7cfdbf/lib/datadog/lambda.rb#L38>
|
12
13
|
class SyncWriter
|
14
|
+
DEPRECATION_WARN_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
|
15
|
+
|
13
16
|
attr_reader \
|
14
17
|
:priority_sampler,
|
15
18
|
:transport
|
@@ -25,10 +28,10 @@ module Datadog
|
|
25
28
|
|
26
29
|
def write(trace, services = nil)
|
27
30
|
unless services.nil?
|
28
|
-
|
31
|
+
DEPRECATION_WARN_ONLY_ONCE.run do
|
29
32
|
Datadog.logger.warn(%(
|
30
33
|
write: Writing services has been deprecated and no longer need to be provided.
|
31
|
-
write(traces, services) can be
|
34
|
+
write(traces, services) can be updated to write(traces)
|
32
35
|
))
|
33
36
|
end
|
34
37
|
end
|
data/lib/ddtrace/tracer.rb
CHANGED
@@ -10,6 +10,7 @@ require 'ddtrace/runtime/identity'
|
|
10
10
|
require 'ddtrace/sampler'
|
11
11
|
require 'ddtrace/sampling'
|
12
12
|
require 'ddtrace/correlation'
|
13
|
+
require 'ddtrace/utils/only_once'
|
13
14
|
|
14
15
|
# \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
|
15
16
|
module Datadog
|
@@ -19,6 +20,9 @@ module Datadog
|
|
19
20
|
# of these function calls and sub-requests would be encapsulated within a single trace.
|
20
21
|
# rubocop:disable Metrics/ClassLength
|
21
22
|
class Tracer
|
23
|
+
SERVICES_DEPRECATION_WARN_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
|
24
|
+
SET_SERVICE_INFO_DEPRECATION_WARN_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
|
25
|
+
|
22
26
|
attr_reader :sampler, :tags, :provider, :context_flush
|
23
27
|
attr_accessor :enabled, :writer
|
24
28
|
attr_writer :default_service
|
@@ -27,8 +31,7 @@ module Datadog
|
|
27
31
|
DEFAULT_ON_ERROR = proc { |span, error| span.set_error(error) unless span.nil? }
|
28
32
|
|
29
33
|
def services
|
30
|
-
|
31
|
-
Datadog::Patcher.do_once('Tracer#set_service_info') do
|
34
|
+
SERVICES_DEPRECATION_WARN_ONLY_ONCE.run do
|
32
35
|
Datadog.logger.warn('services: Usage of Tracer.services has been deprecated')
|
33
36
|
end
|
34
37
|
|
@@ -129,8 +132,7 @@ module Datadog
|
|
129
132
|
#
|
130
133
|
# set_service_info is deprecated, no service information needs to be tracked
|
131
134
|
def set_service_info(service, app, app_type)
|
132
|
-
|
133
|
-
Datadog::Patcher.do_once('Tracer#set_service_info') do
|
135
|
+
SET_SERVICE_INFO_DEPRECATION_WARN_ONLY_ONCE.run do
|
134
136
|
Datadog.logger.warn(%(
|
135
137
|
set_service_info: Usage of set_service_info has been deprecated,
|
136
138
|
service information no longer needs to be reported to the trace agent.
|
@@ -27,7 +27,7 @@ module Datadog
|
|
27
27
|
# Pass a block to override any settings.
|
28
28
|
def default(options = {})
|
29
29
|
new do |transport|
|
30
|
-
transport.adapter
|
30
|
+
transport.adapter default_adapter, default_hostname, default_port, timeout: 1
|
31
31
|
transport.headers default_headers
|
32
32
|
|
33
33
|
apis = API.defaults
|
@@ -39,10 +39,15 @@ module Datadog
|
|
39
39
|
# Apply any settings given by options
|
40
40
|
unless options.empty?
|
41
41
|
# Change hostname/port
|
42
|
-
if
|
43
|
-
hostname = options
|
44
|
-
port = options
|
45
|
-
|
42
|
+
if [:hostname, :port, :timeout, :ssl].any? { |key| options.key?(key) }
|
43
|
+
hostname = options[:hostname] || default_hostname
|
44
|
+
port = options[:port] || default_port
|
45
|
+
|
46
|
+
adapter_options = { timeout: 1 }
|
47
|
+
adapter_options[:timeout] = options[:timeout] if options.key?(:timeout)
|
48
|
+
adapter_options[:ssl] = options[:ssl] if options.key?(:ssl)
|
49
|
+
|
50
|
+
transport.adapter default_adapter, hostname, port, adapter_options
|
46
51
|
end
|
47
52
|
|
48
53
|
# Change default API
|
@@ -73,6 +78,10 @@ module Datadog
|
|
73
78
|
end
|
74
79
|
end
|
75
80
|
|
81
|
+
def default_adapter
|
82
|
+
:net_http
|
83
|
+
end
|
84
|
+
|
76
85
|
def default_hostname
|
77
86
|
return default_url.hostname if default_url
|
78
87
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ddtrace/transport/response'
|
2
|
+
require 'ddtrace/vendor/multipart-post/net/http/post/multipart'
|
2
3
|
|
3
4
|
module Datadog
|
4
5
|
module Transport
|
@@ -9,14 +10,16 @@ module Datadog
|
|
9
10
|
attr_reader \
|
10
11
|
:hostname,
|
11
12
|
:port,
|
12
|
-
:timeout
|
13
|
+
:timeout,
|
14
|
+
:ssl
|
13
15
|
|
14
|
-
DEFAULT_TIMEOUT =
|
16
|
+
DEFAULT_TIMEOUT = 30
|
15
17
|
|
16
18
|
def initialize(hostname, port, options = {})
|
17
19
|
@hostname = hostname
|
18
20
|
@port = port
|
19
21
|
@timeout = options[:timeout] || DEFAULT_TIMEOUT
|
22
|
+
@ssl = options.key?(:ssl) ? options[:ssl] == true : false
|
20
23
|
end
|
21
24
|
|
22
25
|
def open(&block)
|
@@ -25,6 +28,7 @@ module Datadog
|
|
25
28
|
# https://github.com/ruby/ruby/blob/b2d96abb42abbe2e01f010ffc9ac51f0f9a50002/lib/net/http.rb#L614-L618
|
26
29
|
req = ::Net::HTTP.new(hostname, port, nil)
|
27
30
|
|
31
|
+
req.use_ssl = ssl
|
28
32
|
req.open_timeout = req.read_timeout = timeout
|
29
33
|
|
30
34
|
req.start(&block)
|
@@ -39,8 +43,18 @@ module Datadog
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def post(env)
|
42
|
-
post =
|
43
|
-
|
46
|
+
post = nil
|
47
|
+
|
48
|
+
if env.form.nil? || env.form.empty?
|
49
|
+
post = ::Net::HTTP::Post.new(env.path, env.headers)
|
50
|
+
post.body = env.body
|
51
|
+
else
|
52
|
+
post = ::Datadog::Vendor::Net::HTTP::Post::Multipart.new(
|
53
|
+
env.path,
|
54
|
+
env.form,
|
55
|
+
env.headers
|
56
|
+
)
|
57
|
+
end
|
44
58
|
|
45
59
|
# Connect and send the request
|
46
60
|
http_response = open do |http|
|
@@ -95,7 +95,7 @@ module Datadog
|
|
95
95
|
api_options[:headers] = @default_headers.merge((api_options[:headers] || {}))
|
96
96
|
|
97
97
|
# Add API::Instance with all settings
|
98
|
-
instances[key] =
|
98
|
+
instances[key] = api_instance_class.new(
|
99
99
|
spec,
|
100
100
|
adapter,
|
101
101
|
api_options
|
@@ -107,6 +107,10 @@ module Datadog
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def api_instance_class
|
111
|
+
API::Instance
|
112
|
+
end
|
113
|
+
|
110
114
|
# Raised when the API key does not match known APIs.
|
111
115
|
class UnknownApiError < StandardError
|
112
116
|
attr_reader :key
|
@@ -6,14 +6,12 @@ module Datadog
|
|
6
6
|
# Response from HTTP transport for traces
|
7
7
|
class Response
|
8
8
|
include Transport::Response
|
9
|
-
include Transport::Traces::Response
|
10
9
|
|
11
10
|
attr_reader \
|
12
11
|
:result
|
13
12
|
|
14
|
-
def initialize(result
|
13
|
+
def initialize(result)
|
15
14
|
@result = result
|
16
|
-
@trace_count = trace_count
|
17
15
|
end
|
18
16
|
|
19
17
|
def ok?
|
@@ -10,6 +10,12 @@ module Datadog
|
|
10
10
|
module Traces
|
11
11
|
# Response from HTTP transport for traces
|
12
12
|
class Response < IO::Response
|
13
|
+
include Transport::Traces::Response
|
14
|
+
|
15
|
+
def initialize(result, trace_count = 1)
|
16
|
+
super(result)
|
17
|
+
@trace_count = trace_count
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
21
|
# Extensions for HTTP client
|
@@ -123,7 +123,21 @@ module Datadog
|
|
123
123
|
return send_traces(traces)
|
124
124
|
end
|
125
125
|
end
|
126
|
-
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Force resolution of lazy enumerator.
|
129
|
+
#
|
130
|
+
# The "correct" method to call here would be `#force`,
|
131
|
+
# as this method was created to force the eager loading
|
132
|
+
# of a lazy enumerator.
|
133
|
+
#
|
134
|
+
# Unfortunately, JRuby < 9.2.9.0 erroneously eagerly loads
|
135
|
+
# the lazy Enumerator during intermediate steps.
|
136
|
+
# This forces us to use `#to_a`, as this method works for both
|
137
|
+
# lazy and regular Enumerators.
|
138
|
+
# Using `#to_a` can mask the fact that we expect a lazy
|
139
|
+
# Enumerator.
|
140
|
+
responses = responses.to_a
|
127
141
|
|
128
142
|
Datadog.health_metrics.transport_chunked(responses.size)
|
129
143
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Utils
|
5
|
+
# Common database-related utility functions.
|
6
|
+
module Compression
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def gzip(string, level: nil, strategy: nil)
|
10
|
+
sio = StringIO.new
|
11
|
+
sio.binmode
|
12
|
+
gz = Zlib::GzipWriter.new(sio, level, strategy)
|
13
|
+
gz.write(string)
|
14
|
+
gz.close
|
15
|
+
sio.string
|
16
|
+
end
|
17
|
+
|
18
|
+
def gunzip(string, encoding = ::Encoding::ASCII_8BIT)
|
19
|
+
sio = StringIO.new(string)
|
20
|
+
gz = Zlib::GzipReader.new(sio, encoding: encoding)
|
21
|
+
gz.read
|
22
|
+
ensure
|
23
|
+
gz && gz.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'ddtrace/utils/sequence'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Utils
|
5
|
+
# Acts as a unique dictionary of objects
|
6
|
+
class ObjectSet
|
7
|
+
# You can provide a block that defines how the key
|
8
|
+
# for this message type is resolved.
|
9
|
+
def initialize(seed = 0, &block)
|
10
|
+
@sequence = Utils::Sequence.new(seed)
|
11
|
+
@items = {}
|
12
|
+
@key_block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
# Submit an array of arguments that define the message.
|
16
|
+
# If they match an existing message, it will return the
|
17
|
+
# matching object. If it doesn't match, it will yield to
|
18
|
+
# the block with the next ID & args given.
|
19
|
+
def fetch(*args, &block)
|
20
|
+
key = @key_block ? @key_block.call(*args) : args.hash
|
21
|
+
# TODO: Ruby 2.0 doesn't like yielding here... switch when 2.0 is dropped.
|
22
|
+
# rubocop:disable Performance/RedundantBlockCall
|
23
|
+
@items[key] ||= block.call(@sequence.next, *args)
|
24
|
+
# rubocop:enable Performance/RedundantBlockCall
|
25
|
+
end
|
26
|
+
|
27
|
+
def length
|
28
|
+
@items.length
|
29
|
+
end
|
30
|
+
|
31
|
+
def objects
|
32
|
+
@items.values
|
33
|
+
end
|
34
|
+
|
35
|
+
def freeze
|
36
|
+
super
|
37
|
+
@items.freeze
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Utils
|
5
|
+
# Helper class to execute something only once such as not repeating warning logs, and instrumenting classes
|
6
|
+
# only once.
|
7
|
+
#
|
8
|
+
# Thread-safe when used correctly (e.g. be careful of races when lazily initializing instances of this class).
|
9
|
+
#
|
10
|
+
# Note: In its current state, this class is not Ractor-safe.
|
11
|
+
# In https://github.com/DataDog/dd-trace-rb/pull/1398#issuecomment-797378810 we have a discussion of alternatives,
|
12
|
+
# including an alternative implementation that is Ractor-safe once spent.
|
13
|
+
class OnlyOnce
|
14
|
+
def initialize
|
15
|
+
@mutex = Mutex.new
|
16
|
+
@ran_once = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
@mutex.synchronize do
|
21
|
+
return if @ran_once
|
22
|
+
|
23
|
+
@ran_once = true
|
24
|
+
|
25
|
+
yield
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def ran?
|
30
|
+
@mutex.synchronize { @ran_once }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def reset_ran_once_state_for_tests
|
36
|
+
@mutex.synchronize { @ran_once = false }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|