ddtrace 0.47.0 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +4 -2
  3. data/.circleci/images/primary/Dockerfile-2.0.0 +11 -1
  4. data/.circleci/images/primary/Dockerfile-2.1.10 +11 -1
  5. data/.circleci/images/primary/Dockerfile-2.2.10 +11 -1
  6. data/.circleci/images/primary/Dockerfile-2.3.8 +10 -0
  7. data/.circleci/images/primary/Dockerfile-2.4.6 +10 -0
  8. data/.circleci/images/primary/Dockerfile-2.5.6 +10 -0
  9. data/.circleci/images/primary/Dockerfile-2.6.4 +10 -0
  10. data/.circleci/images/primary/Dockerfile-2.7.0 +10 -0
  11. data/.circleci/images/primary/Dockerfile-jruby-9.2-latest +10 -0
  12. data/.gitlab-ci.yml +18 -18
  13. data/.rubocop.yml +19 -0
  14. data/.rubocop_todo.yml +44 -3
  15. data/Appraisals +55 -1
  16. data/CHANGELOG.md +47 -1
  17. data/Gemfile +10 -0
  18. data/Rakefile +9 -0
  19. data/bin/ddtracerb +15 -0
  20. data/ddtrace.gemspec +4 -2
  21. data/docs/GettingStarted.md +36 -53
  22. data/docs/ProfilingDevelopment.md +88 -0
  23. data/integration/README.md +1 -2
  24. data/integration/apps/rack/Dockerfile +3 -0
  25. data/integration/apps/rack/script/build-images +1 -1
  26. data/integration/apps/rack/script/ci +1 -1
  27. data/integration/apps/rails-five/script/build-images +1 -1
  28. data/integration/apps/rails-five/script/ci +1 -1
  29. data/integration/apps/ruby/script/build-images +1 -1
  30. data/integration/apps/ruby/script/ci +1 -1
  31. data/integration/images/include/http-health-check +1 -1
  32. data/integration/images/wrk/scripts/entrypoint.sh +1 -1
  33. data/integration/script/build-images +1 -1
  34. data/lib/ddtrace.rb +1 -0
  35. data/lib/ddtrace/configuration.rb +39 -13
  36. data/lib/ddtrace/configuration/components.rb +85 -3
  37. data/lib/ddtrace/configuration/settings.rb +31 -0
  38. data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +30 -0
  39. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +9 -3
  40. data/lib/ddtrace/contrib/resque/configuration/settings.rb +17 -1
  41. data/lib/ddtrace/contrib/resque/patcher.rb +4 -4
  42. data/lib/ddtrace/contrib/resque/resque_job.rb +22 -1
  43. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +1 -0
  44. data/lib/ddtrace/contrib/shoryuken/tracer.rb +7 -3
  45. data/lib/ddtrace/diagnostics/environment_logger.rb +1 -1
  46. data/lib/ddtrace/error.rb +2 -0
  47. data/lib/ddtrace/ext/profiling.rb +52 -0
  48. data/lib/ddtrace/ext/transport.rb +1 -0
  49. data/lib/ddtrace/metrics.rb +4 -0
  50. data/lib/ddtrace/profiling.rb +54 -0
  51. data/lib/ddtrace/profiling/backtrace_location.rb +32 -0
  52. data/lib/ddtrace/profiling/buffer.rb +41 -0
  53. data/lib/ddtrace/profiling/collectors/stack.rb +253 -0
  54. data/lib/ddtrace/profiling/encoding/profile.rb +31 -0
  55. data/lib/ddtrace/profiling/event.rb +13 -0
  56. data/lib/ddtrace/profiling/events/stack.rb +102 -0
  57. data/lib/ddtrace/profiling/exporter.rb +23 -0
  58. data/lib/ddtrace/profiling/ext/cpu.rb +54 -0
  59. data/lib/ddtrace/profiling/ext/cthread.rb +134 -0
  60. data/lib/ddtrace/profiling/ext/forking.rb +97 -0
  61. data/lib/ddtrace/profiling/flush.rb +41 -0
  62. data/lib/ddtrace/profiling/pprof/builder.rb +121 -0
  63. data/lib/ddtrace/profiling/pprof/converter.rb +85 -0
  64. data/lib/ddtrace/profiling/pprof/message_set.rb +12 -0
  65. data/lib/ddtrace/profiling/pprof/payload.rb +18 -0
  66. data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
  67. data/lib/ddtrace/profiling/pprof/pprof_pb.rb +81 -0
  68. data/lib/ddtrace/profiling/pprof/stack_sample.rb +90 -0
  69. data/lib/ddtrace/profiling/pprof/string_table.rb +10 -0
  70. data/lib/ddtrace/profiling/pprof/template.rb +114 -0
  71. data/lib/ddtrace/profiling/preload.rb +3 -0
  72. data/lib/ddtrace/profiling/profiler.rb +28 -0
  73. data/lib/ddtrace/profiling/recorder.rb +87 -0
  74. data/lib/ddtrace/profiling/scheduler.rb +84 -0
  75. data/lib/ddtrace/profiling/tasks/setup.rb +77 -0
  76. data/lib/ddtrace/profiling/transport/client.rb +12 -0
  77. data/lib/ddtrace/profiling/transport/http.rb +122 -0
  78. data/lib/ddtrace/profiling/transport/http/api.rb +43 -0
  79. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +90 -0
  80. data/lib/ddtrace/profiling/transport/http/api/instance.rb +36 -0
  81. data/lib/ddtrace/profiling/transport/http/api/spec.rb +40 -0
  82. data/lib/ddtrace/profiling/transport/http/builder.rb +28 -0
  83. data/lib/ddtrace/profiling/transport/http/client.rb +33 -0
  84. data/lib/ddtrace/profiling/transport/http/response.rb +21 -0
  85. data/lib/ddtrace/profiling/transport/io.rb +30 -0
  86. data/lib/ddtrace/profiling/transport/io/client.rb +27 -0
  87. data/lib/ddtrace/profiling/transport/io/response.rb +16 -0
  88. data/lib/ddtrace/profiling/transport/parcel.rb +17 -0
  89. data/lib/ddtrace/profiling/transport/request.rb +15 -0
  90. data/lib/ddtrace/profiling/transport/response.rb +8 -0
  91. data/lib/ddtrace/runtime/container.rb +11 -3
  92. data/lib/ddtrace/sampling/rule_sampler.rb +3 -9
  93. data/lib/ddtrace/tasks/exec.rb +48 -0
  94. data/lib/ddtrace/tasks/help.rb +14 -0
  95. data/lib/ddtrace/tracer.rb +21 -0
  96. data/lib/ddtrace/transport/io/client.rb +15 -8
  97. data/lib/ddtrace/transport/parcel.rb +4 -0
  98. data/lib/ddtrace/version.rb +3 -1
  99. data/lib/ddtrace/workers/runtime_metrics.rb +14 -1
  100. metadata +70 -9
@@ -0,0 +1,88 @@
1
+ # Profiling Development
2
+
3
+ This file contains development notes specific to the profiling feature.
4
+
5
+ For a more practical view of getting started with development of `ddtrace`, see <DevelopmentGuide.md>.
6
+
7
+ ## Profiling components high-level view
8
+
9
+ Components below live inside <../lib/ddtrace/profiling>:
10
+
11
+ * `Collectors::Stack`: Collects stack trace samples from Ruby threads for both CPU-time (if available) and wall-clock.
12
+ Runs on its own background thread.
13
+ * `Encoding::Profile`: Encodes gathered data into the pprof format.
14
+ * `Events::Stack`, `Events::StackSample`, `Events::StackExceptionSample`: Entity classes used to represent stacks.
15
+ * `Ext::CPU`: Monkey patches Ruby's `Thread` with our `Ext::CThread` to enable CPU-time profiling.
16
+ * `Ext::CThread`: Extension used to enable CPU-time profiling via use of Pthread's `getcpuclockid`.
17
+ * `Ext::Forking`: Monkey patches `Kernel#fork`, adding a `Kernel#at_fork` callback mechanism which is used to restore
18
+ profiling abilities after the VM forks (such as re-instrumenting the main thread, and restarting profiler threads).
19
+ * `Pprof::*` (in <../lib/ddtrace/profiling/pprof>): Converts samples captured in the `Recorder` into the pprof format.
20
+ * `Tasks::Setup`: Takes care of loading our extensions/monkey patches to handle fork() and CPU profiling.
21
+ * `Transport::*` (in <../lib/ddtrace/profiling/transport>): Implements transmission of profiling payloads to the Datadog agent
22
+ or backend.
23
+ * `BacktraceLocation`: Entity class used to represent an entry in a stack trace.
24
+ * `Buffer`: Bounded buffer used to store profiling events.
25
+ * `Exporter`: Writes profiling data to a given transport.
26
+ * `Flush`: Entity class used to represent metadata for a given profile.
27
+ * `Profiler`: Profiling entry point, which coordinates collectors and a scheduler.
28
+ * `Recorder`: Stores profiling events gathered by `Collector`s.
29
+ * `Scheduler`: Periodically (every 1 minute) takes data from the `Recorder` and pushes them to all configured
30
+ `Exporter`s. Runs on its own background thread.
31
+
32
+ ## Initialization
33
+
34
+ When started via `ddtracerb exec` (together with `DD_PROFILING_ENABLED=true`), initialization goes through the following
35
+ flow:
36
+
37
+ 1. <../lib/ddtrace/profiling/preload.rb> triggers the creation of the `Datadog.profiler` instance by calling the method
38
+ 2. `Datadog.profiler` is handled by `Datadog::Configuration`, which triggers the configuration of `ddtrace` components
39
+ in `#build_components`
40
+ 3. Inside `Datadog::Components`, the `build_profiler` method triggers the execution of the `Tasks::Setup`
41
+ 4. The `Setup` task activates our extensions
42
+ * `Datadog::Profiling::Ext::Forking`
43
+ * `Datadog::Profiling::Ext::CPU`
44
+ 5. Still inside `Datadog::Components`, the `build_profiler` method then creates and wires up the Profiler:
45
+ ```ruby
46
+ recorder = build_profiler_recorder(settings)
47
+ collectors = build_profiler_collectors(settings, recorder)
48
+ exporters = build_profiler_exporters(settings)
49
+ scheduler = build_profiler_scheduler(settings, recorder, exporters)
50
+
51
+ Datadog::Profiler.new(collectors, scheduler)
52
+ ```
53
+ ```asciiflow
54
+ +------------+
55
+ | Profiler |
56
+ +-+--------+-+
57
+ | |
58
+ v v
59
+ +---------+--+ +--+--------+
60
+ | Collectors | | Scheduler |
61
+ +---------+--+ +-+-------+-+
62
+ | | |
63
+ v | v
64
+ +-----+-+ | +----+------+
65
+ | Stack | | | Exporters |
66
+ +-----+-+ | +-----------+
67
+ | |
68
+ v v
69
+ +-+-------+-+
70
+ | Recorder |
71
+ +-----------+
72
+ ```
73
+ 6. The profiler gets started when `startup!` is called by `Datadog::Configuration` after component creation.
74
+
75
+ ## Run-time execution
76
+
77
+ During run-time, the `Scheduler` and the `Collectors::Stack` each execute on their own background thread.
78
+
79
+ The `Collectors::Stack` samples stack traces of threads, capturing both CPU-time (if available) and wall-clock, storing
80
+ them in the `Recorder`.
81
+
82
+ The `Scheduler` wakes up every 1 minute to flush the results of the `Recorder` into one or more `exporter`s.
83
+ Usually only one exporter is in use. By default, the `Exporter` delegates to the default `Transport::HTTP` transport, which
84
+ takes care of encoding the data and reporting it to the datadog agent (or to the API, when running without an agent).
85
+
86
+ ## How CPU-time profiling works
87
+
88
+ **TODO**: Document our pthread-based approach to getting CPU-time for threads.
@@ -6,8 +6,7 @@ Integration tests for `ddtrace` that use a variety of real applications.
6
6
 
7
7
  1. Build Docker base images:
8
8
 
9
- ```sh
10
- #!/bin/bash
9
+ ```bash
11
10
  ./script/build-images
12
11
  ```
13
12
 
@@ -15,6 +15,9 @@ ENV DD_DEMO_ENV_GEM_REF_DDTRACE ${ddtrace_ref}
15
15
 
16
16
  # Install dependencies
17
17
  COPY Gemfile /app/Gemfile
18
+ # This forces gems with native extensions to be compiled, rather than using pre-compiled binaries; it's needed because
19
+ # some google-protobuf versions ship with missing binaries for older rubies.
20
+ ENV BUNDLE_FORCE_RUBY_PLATFORM true
18
21
  RUN bundle install
19
22
 
20
23
  # Add files
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  APP_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  # If health check URL provided, wait till it passes.
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  bash /vendor/dd-demo/http-health-check
3
3
 
4
4
  # Start the load test
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
4
  INTEGRATION_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
data/lib/ddtrace.rb CHANGED
@@ -15,6 +15,7 @@ require 'ddtrace/configuration'
15
15
  require 'ddtrace/patcher'
16
16
  require 'ddtrace/metrics'
17
17
  require 'ddtrace/auto_instrument_base'
18
+ require 'ddtrace/profiling'
18
19
 
19
20
  # \Datadog global namespace that includes all tracing functionality for Tracer and Span classes.
20
21
  module Datadog
@@ -2,10 +2,11 @@ require 'forwardable'
2
2
  require 'ddtrace/configuration/pin_setup'
3
3
  require 'ddtrace/configuration/settings'
4
4
  require 'ddtrace/configuration/components'
5
+ require 'ddtrace/utils/only_once'
5
6
 
6
7
  module Datadog
7
8
  # Configuration provides a unique access point for configurations
8
- module Configuration
9
+ module Configuration # rubocop:disable Metrics/ModuleLength
9
10
  extend Forwardable
10
11
 
11
12
  # Used to ensure that @components initialization/reconfiguration is performed one-at-a-time, by a single thread.
@@ -42,6 +43,8 @@ module Datadog
42
43
  end
43
44
 
44
45
  def configure(target = configuration, opts = {})
46
+ ruby_version_deprecation_warning
47
+
45
48
  if target.is_a?(Settings)
46
49
  yield(target) if block_given?
47
50
 
@@ -64,6 +67,7 @@ module Datadog
64
67
  def_delegators \
65
68
  :components,
66
69
  :health_metrics,
70
+ :profiler,
67
71
  :runtime_metrics,
68
72
  :tracer
69
73
 
@@ -94,18 +98,6 @@ module Datadog
94
98
  end
95
99
  end
96
100
 
97
- # Gracefully shuts down the tracer and disposes of component references,
98
- # allowing execution to start anew.
99
- #
100
- # In contrast with +#shutdown!+, components will be automatically
101
- # reinitialized after a reset.
102
- def reset!
103
- safely_synchronize do |write_components|
104
- @components.shutdown! if components?
105
- write_components.call(nil)
106
- end
107
- end
108
-
109
101
  protected
110
102
 
111
103
  def components(allow_initialization: true)
@@ -119,6 +111,21 @@ module Datadog
119
111
 
120
112
  private
121
113
 
114
+ # Gracefully shuts down the tracer and disposes of component references,
115
+ # allowing execution to start anew.
116
+ #
117
+ # In contrast with +#shutdown!+, components will be automatically
118
+ # reinitialized after a reset.
119
+ #
120
+ # Used internally to ensure a clean environment between test runs.
121
+ def reset!
122
+ safely_synchronize do |write_components|
123
+ @components.shutdown! if components?
124
+ write_components.call(nil)
125
+ configuration.reset!
126
+ end
127
+ end
128
+
122
129
  def safely_synchronize
123
130
  # Writes to @components should only happen through this proc. Because this proc is only accessible to callers of
124
131
  # safely_synchronize, this forces all writers to go through this method.
@@ -168,5 +175,24 @@ module Datadog
168
175
  logger
169
176
  end
170
177
  end
178
+
179
+ # Perform version check only once
180
+ DEPRECATED_RUBY_VERSION = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.1')
181
+ private_constant :DEPRECATED_RUBY_VERSION
182
+
183
+ RUBY_VERSION_DEPRECATION_ONLY_ONCE = Datadog::Utils::OnlyOnce.new
184
+ private_constant :RUBY_VERSION_DEPRECATION_ONLY_ONCE
185
+
186
+ def ruby_version_deprecation_warning
187
+ return unless DEPRECATED_RUBY_VERSION
188
+
189
+ RUBY_VERSION_DEPRECATION_ONLY_ONCE.run do
190
+ Datadog.logger.warn(
191
+ "Support for Ruby versions < 2.1 in dd-trace-rb is DEPRECATED.\n" \
192
+ "Last version to support Ruby < 2.1 will be 0.49.x, which will only receive critical bugfixes.\n" \
193
+ 'Support for Ruby versions < 2.1 will be REMOVED in version 0.50.0.'
194
+ )
195
+ end
196
+ end
171
197
  end
172
198
  end
@@ -1,5 +1,6 @@
1
1
  require 'ddtrace/diagnostics/health'
2
2
  require 'ddtrace/logger'
3
+ require 'ddtrace/profiling'
3
4
  require 'ddtrace/runtime/metrics'
4
5
  require 'ddtrace/tracer'
5
6
  require 'ddtrace/workers/runtime_metrics'
@@ -8,6 +9,7 @@ module Datadog
8
9
  module Configuration
9
10
  # Global components for the trace library.
10
11
  # rubocop:disable Layout/LineLength
12
+ # rubocop:disable Metrics/ClassLength
11
13
  class Components
12
14
  class << self
13
15
  def build_health_metrics(settings)
@@ -66,6 +68,22 @@ module Datadog
66
68
  tracer
67
69
  end
68
70
 
71
+ def build_profiler(settings)
72
+ return unless Datadog::Profiling.supported? && settings.profiling.enabled
73
+
74
+ # Load extensions needed to support some of the Profiling features
75
+ Datadog::Profiling::Tasks::Setup.new.run
76
+
77
+ # NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
78
+
79
+ recorder = build_profiler_recorder(settings)
80
+ collectors = build_profiler_collectors(settings, recorder)
81
+ exporters = build_profiler_exporters(settings)
82
+ scheduler = build_profiler_scheduler(settings, recorder, exporters)
83
+
84
+ Datadog::Profiler.new(collectors, scheduler)
85
+ end
86
+
69
87
  private
70
88
 
71
89
  def build_tracer_tags(settings)
@@ -90,11 +108,51 @@ module Datadog
90
108
  opts[:writer_options] = settings.writer_options if settings.writer.nil?
91
109
  end
92
110
  end
111
+
112
+ def build_profiler_recorder(settings)
113
+ event_classes = [Datadog::Profiling::Events::StackSample]
114
+
115
+ Datadog::Profiling::Recorder.new(event_classes, settings.profiling.max_events)
116
+ end
117
+
118
+ def build_profiler_collectors(settings, recorder)
119
+ [
120
+ Datadog::Profiling::Collectors::Stack.new(
121
+ recorder,
122
+ max_frames: settings.profiling.max_frames
123
+ # TODO: Provide proc that identifies Datadog worker threads?
124
+ # ignore_thread: settings.profiling.ignore_profiler
125
+ )
126
+ ]
127
+ end
128
+
129
+ def build_profiler_exporters(settings)
130
+ if settings.profiling.exporter.instances.is_a?(Array)
131
+ settings.profiling.exporter.instances
132
+ else
133
+ transport = if settings.profiling.exporter.transport
134
+ settings.profiling.exporter.transport
135
+ else
136
+ transport_options = settings.profiling.exporter.transport_options.dup
137
+ transport_options[:site] ||= settings.site if settings.site
138
+ transport_options[:api_key] ||= settings.api_key if settings.api_key
139
+ transport_options[:timeout] ||= settings.profiling.upload.timeout
140
+ Datadog::Profiling::Transport::HTTP.default(transport_options)
141
+ end
142
+
143
+ [Datadog::Profiling::Exporter.new(transport)]
144
+ end
145
+ end
146
+
147
+ def build_profiler_scheduler(settings, recorder, exporters)
148
+ Datadog::Profiling::Scheduler.new(recorder, exporters)
149
+ end
93
150
  end
94
151
 
95
152
  attr_reader \
96
153
  :health_metrics,
97
154
  :logger,
155
+ :profiler,
98
156
  :runtime_metrics,
99
157
  :tracer
100
158
 
@@ -105,6 +163,9 @@ module Datadog
105
163
  # Tracer
106
164
  @tracer = self.class.build_tracer(settings)
107
165
 
166
+ # Profiler
167
+ @profiler = self.class.build_profiler(settings)
168
+
108
169
  # Runtime metrics
109
170
  @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
110
171
 
@@ -113,7 +174,20 @@ module Datadog
113
174
  end
114
175
 
115
176
  # Starts up components
116
- def startup!(settings); end
177
+ def startup!(settings)
178
+ if settings.profiling.enabled
179
+ if profiler
180
+ @logger.debug('Profiling started')
181
+ profiler.start
182
+ else
183
+ # Display a warning for users who expected profiling to autostart
184
+ protobuf = Datadog::Profiling.google_protobuf_supported?
185
+ logger.warn("Profiling was enabled but is not supported; profiling disabled. (google-protobuf?: #{protobuf})")
186
+ end
187
+ else
188
+ @logger.debug('Profiling is disabled')
189
+ end
190
+ end
117
191
 
118
192
  # Shuts down all the components in use.
119
193
  # If it has another instance to compare to, it will compare
@@ -123,12 +197,20 @@ module Datadog
123
197
  # (e.g. a custom tracer instance passed in.)
124
198
  tracer.shutdown! unless replacement && tracer == replacement.tracer
125
199
 
200
+ # Shutdown old profiler
201
+ profiler.shutdown! unless profiler.nil?
202
+
126
203
  # Shutdown workers
127
- runtime_metrics.enabled = false
128
- runtime_metrics.stop(true)
204
+ runtime_metrics.stop(true, close_metrics: false)
129
205
 
130
206
  # Shutdown the old metrics, unless they are still being used.
131
207
  # (e.g. custom Statsd instances.)
208
+ #
209
+ # TODO: This violates the encapsulation created by Runtime::Metrics and
210
+ # Health::Metrics, by directly manipulating `statsd` and changing
211
+ # it's lifecycle management.
212
+ # If we need to directly have ownership of `statsd` lifecycle, we should
213
+ # have direct ownership of it.
132
214
  old_statsd = [
133
215
  runtime_metrics.metrics.statsd,
134
216
  health_metrics.statsd
@@ -3,6 +3,7 @@ require 'ddtrace/configuration/base'
3
3
 
4
4
  require 'ddtrace/ext/analytics'
5
5
  require 'ddtrace/ext/distributed'
6
+ require 'ddtrace/ext/profiling'
6
7
  require 'ddtrace/ext/runtime'
7
8
  require 'ddtrace/ext/sampling'
8
9
 
@@ -108,6 +109,36 @@ module Datadog
108
109
  get_option(:logger).instance = logger
109
110
  end
110
111
 
112
+ settings :profiling do
113
+ option :enabled do |o|
114
+ o.default { env_to_bool(Ext::Profiling::ENV_ENABLED, false) }
115
+ o.lazy
116
+ end
117
+
118
+ settings :exporter do
119
+ option :instances
120
+ option :transport
121
+ option :transport_options, default: ->(_o) { {} }, lazy: true
122
+ end
123
+
124
+ option :max_events, default: 32768
125
+
126
+ # Controls the maximum number of frames for each thread sampled. Can be tuned to avoid omitted frames in the
127
+ # produced profiles. Increasing this may increase the overhead of profiling.
128
+ option :max_frames do |o|
129
+ o.default { env_to_int(Ext::Profiling::ENV_MAX_FRAMES, 400) }
130
+ o.lazy
131
+ end
132
+
133
+ settings :upload do
134
+ option :timeout do |o|
135
+ o.setter { |value| value.nil? ? 30.0 : value.to_f }
136
+ o.default { env_to_float(Ext::Profiling::ENV_UPLOAD_TIMEOUT, 30.0) }
137
+ o.lazy
138
+ end
139
+ end
140
+ end
141
+
111
142
  option :report_hostname do |o|
112
143
  o.default { env_to_bool(Ext::NET::ENV_REPORT_HOSTNAME, false) }
113
144
  o.lazy