ddtrace 0.47.0 → 0.48.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 +5 -5
- data/.circleci/config.yml +4 -2
- data/.circleci/images/primary/Dockerfile-2.0.0 +11 -1
- data/.circleci/images/primary/Dockerfile-2.1.10 +11 -1
- data/.circleci/images/primary/Dockerfile-2.2.10 +11 -1
- data/.circleci/images/primary/Dockerfile-2.3.8 +10 -0
- data/.circleci/images/primary/Dockerfile-2.4.6 +10 -0
- data/.circleci/images/primary/Dockerfile-2.5.6 +10 -0
- data/.circleci/images/primary/Dockerfile-2.6.4 +10 -0
- data/.circleci/images/primary/Dockerfile-2.7.0 +10 -0
- data/.circleci/images/primary/Dockerfile-jruby-9.2-latest +10 -0
- data/.gitlab-ci.yml +18 -18
- data/.rubocop.yml +19 -0
- data/.rubocop_todo.yml +44 -3
- data/Appraisals +55 -1
- data/CHANGELOG.md +47 -1
- data/Gemfile +10 -0
- data/Rakefile +9 -0
- data/bin/ddtracerb +15 -0
- data/ddtrace.gemspec +4 -2
- data/docs/GettingStarted.md +36 -53
- data/docs/ProfilingDevelopment.md +88 -0
- data/integration/README.md +1 -2
- data/integration/apps/rack/Dockerfile +3 -0
- data/integration/apps/rack/script/build-images +1 -1
- data/integration/apps/rack/script/ci +1 -1
- data/integration/apps/rails-five/script/build-images +1 -1
- data/integration/apps/rails-five/script/ci +1 -1
- data/integration/apps/ruby/script/build-images +1 -1
- data/integration/apps/ruby/script/ci +1 -1
- data/integration/images/include/http-health-check +1 -1
- data/integration/images/wrk/scripts/entrypoint.sh +1 -1
- data/integration/script/build-images +1 -1
- data/lib/ddtrace.rb +1 -0
- data/lib/ddtrace/configuration.rb +39 -13
- data/lib/ddtrace/configuration/components.rb +85 -3
- data/lib/ddtrace/configuration/settings.rb +31 -0
- data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +30 -0
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +9 -3
- data/lib/ddtrace/contrib/resque/configuration/settings.rb +17 -1
- data/lib/ddtrace/contrib/resque/patcher.rb +4 -4
- data/lib/ddtrace/contrib/resque/resque_job.rb +22 -1
- data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
- data/lib/ddtrace/contrib/shoryuken/tracer.rb +7 -3
- data/lib/ddtrace/diagnostics/environment_logger.rb +1 -1
- data/lib/ddtrace/error.rb +2 -0
- data/lib/ddtrace/ext/profiling.rb +52 -0
- data/lib/ddtrace/ext/transport.rb +1 -0
- data/lib/ddtrace/metrics.rb +4 -0
- data/lib/ddtrace/profiling.rb +54 -0
- data/lib/ddtrace/profiling/backtrace_location.rb +32 -0
- data/lib/ddtrace/profiling/buffer.rb +41 -0
- data/lib/ddtrace/profiling/collectors/stack.rb +253 -0
- data/lib/ddtrace/profiling/encoding/profile.rb +31 -0
- data/lib/ddtrace/profiling/event.rb +13 -0
- data/lib/ddtrace/profiling/events/stack.rb +102 -0
- data/lib/ddtrace/profiling/exporter.rb +23 -0
- data/lib/ddtrace/profiling/ext/cpu.rb +54 -0
- data/lib/ddtrace/profiling/ext/cthread.rb +134 -0
- data/lib/ddtrace/profiling/ext/forking.rb +97 -0
- data/lib/ddtrace/profiling/flush.rb +41 -0
- data/lib/ddtrace/profiling/pprof/builder.rb +121 -0
- data/lib/ddtrace/profiling/pprof/converter.rb +85 -0
- data/lib/ddtrace/profiling/pprof/message_set.rb +12 -0
- data/lib/ddtrace/profiling/pprof/payload.rb +18 -0
- data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
- data/lib/ddtrace/profiling/pprof/pprof_pb.rb +81 -0
- data/lib/ddtrace/profiling/pprof/stack_sample.rb +90 -0
- data/lib/ddtrace/profiling/pprof/string_table.rb +10 -0
- data/lib/ddtrace/profiling/pprof/template.rb +114 -0
- data/lib/ddtrace/profiling/preload.rb +3 -0
- data/lib/ddtrace/profiling/profiler.rb +28 -0
- data/lib/ddtrace/profiling/recorder.rb +87 -0
- data/lib/ddtrace/profiling/scheduler.rb +84 -0
- data/lib/ddtrace/profiling/tasks/setup.rb +77 -0
- data/lib/ddtrace/profiling/transport/client.rb +12 -0
- data/lib/ddtrace/profiling/transport/http.rb +122 -0
- data/lib/ddtrace/profiling/transport/http/api.rb +43 -0
- data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +90 -0
- data/lib/ddtrace/profiling/transport/http/api/instance.rb +36 -0
- data/lib/ddtrace/profiling/transport/http/api/spec.rb +40 -0
- data/lib/ddtrace/profiling/transport/http/builder.rb +28 -0
- data/lib/ddtrace/profiling/transport/http/client.rb +33 -0
- data/lib/ddtrace/profiling/transport/http/response.rb +21 -0
- data/lib/ddtrace/profiling/transport/io.rb +30 -0
- data/lib/ddtrace/profiling/transport/io/client.rb +27 -0
- data/lib/ddtrace/profiling/transport/io/response.rb +16 -0
- data/lib/ddtrace/profiling/transport/parcel.rb +17 -0
- data/lib/ddtrace/profiling/transport/request.rb +15 -0
- data/lib/ddtrace/profiling/transport/response.rb +8 -0
- data/lib/ddtrace/runtime/container.rb +11 -3
- data/lib/ddtrace/sampling/rule_sampler.rb +3 -9
- data/lib/ddtrace/tasks/exec.rb +48 -0
- data/lib/ddtrace/tasks/help.rb +14 -0
- data/lib/ddtrace/tracer.rb +21 -0
- data/lib/ddtrace/transport/io/client.rb +15 -8
- data/lib/ddtrace/transport/parcel.rb +4 -0
- data/lib/ddtrace/version.rb +3 -1
- data/lib/ddtrace/workers/runtime_metrics.rb +14 -1
- metadata +70 -9
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'ddtrace'
|
|
2
|
+
require 'ddtrace/utils/only_once'
|
|
3
|
+
require 'ddtrace/profiling'
|
|
4
|
+
require 'ddtrace/profiling/ext/cpu'
|
|
5
|
+
require 'ddtrace/profiling/ext/forking'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Profiling
|
|
9
|
+
module Tasks
|
|
10
|
+
# Takes care of loading our extensions/monkey patches to handle fork() and CPU profiling.
|
|
11
|
+
class Setup
|
|
12
|
+
ACTIVATE_EXTENSIONS_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
ACTIVATE_EXTENSIONS_ONLY_ONCE.run do
|
|
16
|
+
begin
|
|
17
|
+
activate_forking_extensions
|
|
18
|
+
activate_cpu_extensions
|
|
19
|
+
setup_at_fork_hooks
|
|
20
|
+
rescue StandardError, ScriptError => e
|
|
21
|
+
log "[DDTRACE] Main extensions unavailable. Cause: #{e.message} Location: #{e.backtrace.first}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def activate_forking_extensions
|
|
29
|
+
if Ext::Forking.supported?
|
|
30
|
+
Ext::Forking.apply!
|
|
31
|
+
elsif Datadog.configuration.profiling.enabled
|
|
32
|
+
# Log warning if profiling was supposed to be activated.
|
|
33
|
+
log '[DDTRACE] Forking extensions skipped; forking not supported.'
|
|
34
|
+
end
|
|
35
|
+
rescue StandardError, ScriptError => e
|
|
36
|
+
log "[DDTRACE] Forking extensions unavailable. Cause: #{e.message} Location: #{e.backtrace.first}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def activate_cpu_extensions
|
|
40
|
+
if Ext::CPU.supported?
|
|
41
|
+
Ext::CPU.apply!
|
|
42
|
+
elsif Datadog.configuration.profiling.enabled
|
|
43
|
+
# Log warning if profiling was supposed to be activated.
|
|
44
|
+
log "[DDTRACE] CPU profiling skipped because native CPU time is not supported: #{Ext::CPU.unsupported_reason}."
|
|
45
|
+
end
|
|
46
|
+
rescue StandardError, ScriptError => e
|
|
47
|
+
log "[DDTRACE] CPU profiling unavailable. Cause: #{e.message} Location: #{e.backtrace.first}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def setup_at_fork_hooks
|
|
51
|
+
if Process.respond_to?(:at_fork)
|
|
52
|
+
Process.at_fork(:child) do
|
|
53
|
+
begin
|
|
54
|
+
# When Ruby forks, clock IDs for each of the threads
|
|
55
|
+
# will change. We can only update these IDs from the
|
|
56
|
+
# execution context of the thread that owns it.
|
|
57
|
+
# This hook will update the IDs for the main thread
|
|
58
|
+
# after a fork occurs.
|
|
59
|
+
Thread.current.send(:update_native_ids) if Thread.current.respond_to?(:update_native_ids, true)
|
|
60
|
+
|
|
61
|
+
# Restart profiler, if enabled
|
|
62
|
+
Datadog.profiler.start if Datadog.profiler
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
log "[DDTRACE] Error during post-fork hooks. Cause: #{e.message} Location: #{e.backtrace.first}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def log(message)
|
|
71
|
+
# Print to STDOUT for now because logging may not be setup yet...
|
|
72
|
+
puts message
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'ddtrace/ext/runtime'
|
|
2
|
+
require 'ddtrace/ext/transport'
|
|
3
|
+
|
|
4
|
+
require 'ddtrace/runtime/container'
|
|
5
|
+
|
|
6
|
+
require 'ddtrace/profiling/transport/http/builder'
|
|
7
|
+
require 'ddtrace/profiling/transport/http/api'
|
|
8
|
+
|
|
9
|
+
require 'ddtrace/transport/http/adapters/net'
|
|
10
|
+
require 'ddtrace/transport/http/adapters/test'
|
|
11
|
+
require 'ddtrace/transport/http/adapters/unix_socket'
|
|
12
|
+
|
|
13
|
+
module Datadog
|
|
14
|
+
module Profiling
|
|
15
|
+
module Transport
|
|
16
|
+
# TODO: Consolidate with Dataog::Transport::HTTP
|
|
17
|
+
# Namespace for HTTP transport components
|
|
18
|
+
module HTTP
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# Builds a new Transport::HTTP::Client
|
|
22
|
+
def new(&block)
|
|
23
|
+
Builder.new(&block).to_transport
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Builds a new Transport::HTTP::Client with default settings
|
|
27
|
+
# Pass a block to override any settings.
|
|
28
|
+
def default(options = {})
|
|
29
|
+
new do |transport|
|
|
30
|
+
transport.headers default_headers
|
|
31
|
+
|
|
32
|
+
# Configure adapter & API
|
|
33
|
+
if options[:site] && options[:api_key]
|
|
34
|
+
configure_for_agentless(transport, options)
|
|
35
|
+
else
|
|
36
|
+
configure_for_agent(transport, options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Additional options
|
|
40
|
+
unless options.empty?
|
|
41
|
+
# Change default API
|
|
42
|
+
transport.default_api = options[:api_version] if options.key?(:api_version)
|
|
43
|
+
|
|
44
|
+
# Add headers
|
|
45
|
+
transport.headers options[:headers] if options.key?(:headers)
|
|
46
|
+
|
|
47
|
+
# Execute on_build callback
|
|
48
|
+
options[:on_build].call(transport) if options[:on_build].is_a?(Proc)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Call block to apply any customization, if provided.
|
|
52
|
+
yield(transport) if block_given?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def default_headers
|
|
57
|
+
{
|
|
58
|
+
Datadog::Ext::Transport::HTTP::HEADER_META_LANG => Datadog::Ext::Runtime::LANG,
|
|
59
|
+
Datadog::Ext::Transport::HTTP::HEADER_META_LANG_VERSION => Datadog::Ext::Runtime::LANG_VERSION,
|
|
60
|
+
Datadog::Ext::Transport::HTTP::HEADER_META_LANG_INTERPRETER => Datadog::Ext::Runtime::LANG_INTERPRETER,
|
|
61
|
+
Datadog::Ext::Transport::HTTP::HEADER_META_TRACER_VERSION => Datadog::Ext::Runtime::TRACER_VERSION
|
|
62
|
+
}.tap do |headers|
|
|
63
|
+
# Add container ID, if present.
|
|
64
|
+
container_id = Datadog::Runtime::Container.container_id
|
|
65
|
+
headers[Datadog::Ext::Transport::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def default_adapter
|
|
70
|
+
:net_http
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def default_hostname
|
|
74
|
+
ENV.fetch(Datadog::Ext::Transport::HTTP::ENV_DEFAULT_HOST, Datadog::Ext::Transport::HTTP::DEFAULT_HOST)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def default_port
|
|
78
|
+
ENV.fetch(Datadog::Ext::Transport::HTTP::ENV_DEFAULT_PORT, Datadog::Ext::Transport::HTTP::DEFAULT_PORT).to_i
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def configure_for_agent(transport, options = {})
|
|
82
|
+
apis = API.agent_defaults
|
|
83
|
+
|
|
84
|
+
hostname = options[:hostname] || default_hostname
|
|
85
|
+
port = options[:port] || default_port
|
|
86
|
+
|
|
87
|
+
adapter_options = {}
|
|
88
|
+
adapter_options[:timeout] = options[:timeout] if options.key?(:timeout)
|
|
89
|
+
adapter_options[:ssl] = options[:ssl] if options.key?(:ssl)
|
|
90
|
+
|
|
91
|
+
transport.adapter default_adapter, hostname, port, adapter_options
|
|
92
|
+
transport.api API::V1, apis[API::V1], default: true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def configure_for_agentless(transport, options = {})
|
|
96
|
+
apis = API.api_defaults
|
|
97
|
+
|
|
98
|
+
site_uri = URI(format(Datadog::Ext::Profiling::Transport::HTTP::URI_TEMPLATE_DD_API, options[:site]))
|
|
99
|
+
hostname = options[:hostname] || site_uri.host
|
|
100
|
+
port = options[:port] || site_uri.port
|
|
101
|
+
|
|
102
|
+
adapter_options = {}
|
|
103
|
+
adapter_options[:timeout] = options[:timeout] if options.key?(:timeout)
|
|
104
|
+
adapter_options[:ssl] = options[:ssl] || (site_uri.scheme == 'https'.freeze)
|
|
105
|
+
|
|
106
|
+
transport.adapter default_adapter, hostname, port, adapter_options
|
|
107
|
+
transport.api API::V1, apis[API::V1], default: true
|
|
108
|
+
transport.headers(Datadog::Ext::Transport::HTTP::HEADER_DD_API_KEY => options[:api_key])
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Add adapters to registry
|
|
112
|
+
Builder::REGISTRY.set(Datadog::Transport::HTTP::Adapters::Net, :net_http)
|
|
113
|
+
Builder::REGISTRY.set(Datadog::Transport::HTTP::Adapters::Test, :test)
|
|
114
|
+
Builder::REGISTRY.set(Datadog::Transport::HTTP::Adapters::UnixSocket, :unix)
|
|
115
|
+
|
|
116
|
+
private \
|
|
117
|
+
:configure_for_agent,
|
|
118
|
+
:configure_for_agentless
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'ddtrace/transport/http/api/map'
|
|
2
|
+
require 'ddtrace/profiling/encoding/profile'
|
|
3
|
+
require 'ddtrace/profiling/transport/http/api/spec'
|
|
4
|
+
require 'ddtrace/profiling/transport/http/api/instance'
|
|
5
|
+
require 'ddtrace/profiling/transport/http/api/endpoint'
|
|
6
|
+
|
|
7
|
+
module Datadog
|
|
8
|
+
module Profiling
|
|
9
|
+
module Transport
|
|
10
|
+
module HTTP
|
|
11
|
+
# Extensions for HTTP API Spec
|
|
12
|
+
module API
|
|
13
|
+
# Default API versions
|
|
14
|
+
V1 = 'v1'.freeze
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def agent_defaults
|
|
19
|
+
@agent_defaults ||= Datadog::Transport::HTTP::API::Map[
|
|
20
|
+
V1 => Spec.new do |s|
|
|
21
|
+
s.profiles = Endpoint.new(
|
|
22
|
+
'/profiling/v1/input'.freeze,
|
|
23
|
+
Profiling::Encoding::Profile::Protobuf
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def api_defaults
|
|
30
|
+
@api_defaults ||= Datadog::Transport::HTTP::API::Map[
|
|
31
|
+
V1 => Spec.new do |s|
|
|
32
|
+
s.profiles = Endpoint.new(
|
|
33
|
+
'/v1/input'.freeze,
|
|
34
|
+
Profiling::Encoding::Profile::Protobuf
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require 'ddtrace/ext/profiling'
|
|
2
|
+
require 'ddtrace/utils/compression'
|
|
3
|
+
require 'ddtrace/vendor/multipart-post/multipart/post/composite_read_io'
|
|
4
|
+
|
|
5
|
+
require 'ddtrace/transport/http/api/endpoint'
|
|
6
|
+
require 'ddtrace/profiling/transport/http/response'
|
|
7
|
+
|
|
8
|
+
module Datadog
|
|
9
|
+
module Profiling
|
|
10
|
+
module Transport
|
|
11
|
+
module HTTP
|
|
12
|
+
module API
|
|
13
|
+
# Datadog API endpoint for profiling
|
|
14
|
+
class Endpoint < Datadog::Transport::HTTP::API::Endpoint
|
|
15
|
+
include Datadog::Ext::Profiling::Transport::HTTP
|
|
16
|
+
|
|
17
|
+
attr_reader \
|
|
18
|
+
:encoder
|
|
19
|
+
|
|
20
|
+
def initialize(path, encoder, options = {})
|
|
21
|
+
super(:post, path)
|
|
22
|
+
@encoder = encoder
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(env, &block)
|
|
26
|
+
# Build request
|
|
27
|
+
env.form = build_form(env)
|
|
28
|
+
|
|
29
|
+
# Send request
|
|
30
|
+
http_response = super(env, &block)
|
|
31
|
+
|
|
32
|
+
# Build response
|
|
33
|
+
Profiling::Transport::HTTP::Response.new(http_response)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def build_form(env)
|
|
37
|
+
flush = env.request.parcel.data
|
|
38
|
+
pprof_file, types = build_pprof(flush)
|
|
39
|
+
|
|
40
|
+
form = {
|
|
41
|
+
# NOTE: Redundant w/ 'runtime-id' tag below; may want to remove this later.
|
|
42
|
+
FORM_FIELD_RUNTIME_ID => flush.runtime_id,
|
|
43
|
+
FORM_FIELD_RECORDING_START => flush.start.utc.iso8601,
|
|
44
|
+
FORM_FIELD_RECORDING_END => flush.finish.utc.iso8601,
|
|
45
|
+
FORM_FIELD_TAGS => [
|
|
46
|
+
"#{FORM_FIELD_TAG_RUNTIME}:#{flush.language}",
|
|
47
|
+
"#{FORM_FIELD_TAG_RUNTIME_ID}:#{flush.runtime_id}",
|
|
48
|
+
"#{FORM_FIELD_TAG_RUNTIME_ENGINE}:#{flush.runtime_engine}",
|
|
49
|
+
"#{FORM_FIELD_TAG_RUNTIME_PLATFORM}:#{flush.runtime_platform}",
|
|
50
|
+
"#{FORM_FIELD_TAG_RUNTIME_VERSION}:#{flush.runtime_version}",
|
|
51
|
+
"#{FORM_FIELD_TAG_PROFILER_VERSION}:#{flush.profiler_version}",
|
|
52
|
+
# NOTE: Redundant w/ 'runtime'; may want to remove this later.
|
|
53
|
+
"#{FORM_FIELD_TAG_LANGUAGE}:#{flush.language}",
|
|
54
|
+
"#{FORM_FIELD_TAG_HOST}:#{flush.host}"
|
|
55
|
+
],
|
|
56
|
+
FORM_FIELD_DATA => pprof_file,
|
|
57
|
+
FORM_FIELD_RUNTIME => flush.language,
|
|
58
|
+
FORM_FIELD_FORMAT => FORM_FIELD_FORMAT_PPROF
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Add types
|
|
62
|
+
form[FORM_FIELD_TYPES] = types.join(',')
|
|
63
|
+
|
|
64
|
+
# Optional fields
|
|
65
|
+
form[FORM_FIELD_TAGS] << "#{FORM_FIELD_TAG_SERVICE}:#{flush.service}" unless flush.service.nil?
|
|
66
|
+
form[FORM_FIELD_TAGS] << "#{FORM_FIELD_TAG_ENV}:#{flush.env}" unless flush.env.nil?
|
|
67
|
+
form[FORM_FIELD_TAGS] << "#{FORM_FIELD_TAG_VERSION}:#{flush.version}" unless flush.version.nil?
|
|
68
|
+
|
|
69
|
+
form
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def build_pprof(flush)
|
|
73
|
+
pprof = encoder.encode(flush)
|
|
74
|
+
|
|
75
|
+
# Wrap pprof as a gzipped file
|
|
76
|
+
gzipped_data = Datadog::Utils::Compression.gzip(pprof.data)
|
|
77
|
+
pprof_file = Datadog::Vendor::Multipart::Post::UploadIO.new(
|
|
78
|
+
StringIO.new(gzipped_data),
|
|
79
|
+
HEADER_CONTENT_TYPE_OCTET_STREAM,
|
|
80
|
+
PPROF_DEFAULT_FILENAME
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
[pprof_file, [FORM_FIELD_TYPES_AUTO]]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'ddtrace/transport/http/api/instance'
|
|
2
|
+
require 'ddtrace/profiling/transport/http/api/spec'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module Profiling
|
|
6
|
+
module Transport
|
|
7
|
+
module HTTP
|
|
8
|
+
module API
|
|
9
|
+
# API instance for profiling
|
|
10
|
+
class Instance < Datadog::Transport::HTTP::API::Instance
|
|
11
|
+
def send_profiling_flush(env)
|
|
12
|
+
raise ProfilesNotSupportedError, spec unless spec.is_a?(Spec)
|
|
13
|
+
|
|
14
|
+
spec.send_profiling_flush(env) do |request_env|
|
|
15
|
+
call(request_env)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Raised when profiles sent to API that does not support profiles
|
|
20
|
+
class ProfilesNotSupportedError < StandardError
|
|
21
|
+
attr_reader :spec
|
|
22
|
+
|
|
23
|
+
def initialize(spec)
|
|
24
|
+
@spec = spec
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def message
|
|
28
|
+
'Profiles not supported for this API!'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'ddtrace/transport/http/api/spec'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Profiling
|
|
5
|
+
module Transport
|
|
6
|
+
module HTTP
|
|
7
|
+
module API
|
|
8
|
+
# API specification for profiling
|
|
9
|
+
class Spec < Datadog::Transport::HTTP::API::Spec
|
|
10
|
+
attr_accessor \
|
|
11
|
+
:profiles
|
|
12
|
+
|
|
13
|
+
def send_profiling_flush(env, &block)
|
|
14
|
+
raise NoProfilesEndpointDefinedError, self if profiles.nil?
|
|
15
|
+
|
|
16
|
+
profiles.call(env, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def encoder
|
|
20
|
+
profiles.encoder
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Raised when profiles sent but no profiles endpoint is defined
|
|
24
|
+
class NoProfilesEndpointDefinedError < StandardError
|
|
25
|
+
attr_reader :spec
|
|
26
|
+
|
|
27
|
+
def initialize(spec)
|
|
28
|
+
@spec = spec
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def message
|
|
32
|
+
'No profiles endpoint is defined for API specification!'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'ddtrace/transport/http/builder'
|
|
2
|
+
|
|
3
|
+
require 'ddtrace/profiling/transport/http/api'
|
|
4
|
+
require 'ddtrace/profiling/transport/http/client'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module Profiling
|
|
8
|
+
module Transport
|
|
9
|
+
module HTTP
|
|
10
|
+
# Builds new instances of Transport::HTTP::Client
|
|
11
|
+
class Builder < Datadog::Transport::HTTP::Builder
|
|
12
|
+
def api_instance_class
|
|
13
|
+
API::Instance
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_transport
|
|
17
|
+
raise Datadog::Transport::HTTP::Builder::NoDefaultApiError if @default_api.nil?
|
|
18
|
+
|
|
19
|
+
# TODO: Profiling doesn't have multiple APIs yet.
|
|
20
|
+
# When it does, we should build it out with these APIs.
|
|
21
|
+
# Just use :default_api for now.
|
|
22
|
+
Client.new(to_api_instances[@default_api])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|