ddtrace 1.18.0 → 1.23.2
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/CHANGELOG.md +228 -2
- data/LICENSE-3rdparty.csv +1 -1
- data/bin/ddprofrb +15 -0
- data/bin/ddtracerb +3 -1
- data/ext/{ddtrace_profiling_loader/ddtrace_profiling_loader.c → datadog_profiling_loader/datadog_profiling_loader.c} +2 -2
- data/ext/{ddtrace_profiling_loader → datadog_profiling_loader}/extconf.rb +3 -3
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_cpu_and_wall_time_worker.c +312 -117
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +422 -0
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +101 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.c +22 -14
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_dynamic_sampling_rate.h +4 -0
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +156 -0
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.h +5 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.c +43 -102
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_stack.h +10 -3
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.c +272 -136
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_thread_context.h +2 -1
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/extconf.rb +28 -7
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1047 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.h +166 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/helpers.h +6 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/http_transport.c +15 -19
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.c +20 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/libdatadog_helpers.h +11 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/native_extension_helpers.rb +50 -4
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.c +19 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/private_vm_api_access.h +4 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/profiling.c +18 -1
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +267 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/ruby_helpers.h +33 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.c +476 -58
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/stack_recorder.h +3 -0
- data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.h +2 -0
- data/lib/datadog/appsec/contrib/devise/tracking.rb +8 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +45 -14
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/components.rb +7 -6
- data/lib/datadog/core/configuration/option.rb +8 -6
- data/lib/datadog/core/configuration/settings.rb +259 -60
- data/lib/datadog/core/configuration.rb +20 -4
- data/lib/datadog/core/diagnostics/environment_logger.rb +4 -3
- data/lib/datadog/core/environment/class_count.rb +6 -6
- data/lib/datadog/core/environment/git.rb +25 -0
- data/lib/datadog/core/environment/identity.rb +18 -48
- data/lib/datadog/core/environment/platform.rb +7 -1
- data/lib/datadog/core/git/ext.rb +2 -23
- data/lib/datadog/core/remote/client/capabilities.rb +1 -1
- data/lib/datadog/core/remote/component.rb +25 -12
- data/lib/datadog/core/remote/ext.rb +1 -0
- data/lib/datadog/core/remote/negotiation.rb +2 -2
- data/lib/datadog/core/remote/tie/tracing.rb +39 -0
- data/lib/datadog/core/remote/tie.rb +27 -0
- data/lib/datadog/core/remote/transport/http/config.rb +1 -1
- data/lib/datadog/core/remote/worker.rb +7 -4
- data/lib/datadog/core/telemetry/client.rb +18 -10
- data/lib/datadog/core/telemetry/emitter.rb +9 -13
- data/lib/datadog/core/telemetry/event.rb +247 -56
- data/lib/datadog/core/telemetry/ext.rb +4 -0
- data/lib/datadog/core/telemetry/heartbeat.rb +1 -3
- data/lib/datadog/core/telemetry/http/ext.rb +4 -1
- data/lib/datadog/core/telemetry/http/response.rb +4 -0
- data/lib/datadog/core/telemetry/http/transport.rb +9 -4
- data/lib/datadog/core/telemetry/request.rb +59 -0
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/utils/url.rb +25 -0
- data/lib/datadog/opentelemetry/sdk/propagator.rb +3 -2
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +10 -4
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +36 -12
- data/lib/datadog/profiling/collectors/info.rb +101 -0
- data/lib/datadog/profiling/component.rb +210 -34
- data/lib/datadog/profiling/exporter.rb +23 -6
- data/lib/datadog/profiling/ext.rb +2 -0
- data/lib/datadog/profiling/flush.rb +6 -3
- data/lib/datadog/profiling/http_transport.rb +5 -1
- data/lib/datadog/profiling/load_native_extension.rb +19 -6
- data/lib/datadog/profiling/native_extension.rb +1 -1
- data/lib/datadog/profiling/scheduler.rb +4 -6
- data/lib/datadog/profiling/stack_recorder.rb +19 -4
- data/lib/datadog/profiling/tag_builder.rb +5 -0
- data/lib/datadog/profiling/tasks/exec.rb +3 -3
- data/lib/datadog/profiling/tasks/help.rb +3 -3
- data/lib/datadog/profiling.rb +13 -2
- data/lib/datadog/tracing/configuration/ext.rb +0 -1
- data/lib/datadog/tracing/configuration/settings.rb +2 -1
- data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/action_cable/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/action_pack/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/action_view/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/active_job/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +11 -4
- data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/active_support/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/analytics.rb +0 -1
- data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/aws/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +20 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +11 -1
- data/lib/datadog/tracing/contrib/configurable.rb +1 -1
- data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/delayed_job/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +6 -2
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +7 -0
- data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +1 -1
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/grape/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +2 -2
- data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/kafka/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/pg/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +11 -4
- data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/presto/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/qless/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/qless/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/racecar/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +9 -2
- data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +0 -2
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/rake/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/redis/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/patcher.rb +34 -21
- data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/resque/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/roda/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/sequel/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/shoryuken/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/sneakers/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/stripe/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +1 -0
- data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +58 -0
- data/lib/datadog/tracing/contrib/trilogy/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +94 -0
- data/lib/datadog/tracing/contrib/trilogy/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/trilogy/patcher.rb +31 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/sampling/matcher.rb +23 -3
- data/lib/datadog/tracing/sampling/rule.rb +7 -2
- data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
- data/lib/datadog/tracing/trace_operation.rb +1 -2
- data/lib/datadog/tracing/transport/http.rb +1 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +31 -0
- data/lib/datadog/tracing.rb +8 -2
- data/lib/ddtrace/version.rb +2 -2
- metadata +71 -61
- data/ext/ddtrace_profiling_native_extension/pid_controller.c +0 -57
- data/ext/ddtrace_profiling_native_extension/pid_controller.h +0 -45
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +0 -110
- data/lib/datadog/core/telemetry/collector.rb +0 -240
- data/lib/datadog/core/telemetry/v1/app_event.rb +0 -52
- data/lib/datadog/core/telemetry/v1/application.rb +0 -92
- data/lib/datadog/core/telemetry/v1/configuration.rb +0 -25
- data/lib/datadog/core/telemetry/v1/dependency.rb +0 -43
- data/lib/datadog/core/telemetry/v1/host.rb +0 -59
- data/lib/datadog/core/telemetry/v1/integration.rb +0 -64
- data/lib/datadog/core/telemetry/v1/product.rb +0 -36
- data/lib/datadog/core/telemetry/v1/telemetry_request.rb +0 -106
- data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +0 -41
- data/lib/datadog/core/telemetry/v2/request.rb +0 -29
- data/lib/datadog/profiling/diagnostics/environment_logger.rb +0 -39
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/NativeExtensionDesign.md +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_from_pthread.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/clock_id_noop.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/collectors_idle_sampling_helper.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.c +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/setup_signal_handler.h +0 -0
- /data/ext/{ddtrace_profiling_native_extension → datadog_profiling_native_extension}/time_helpers.c +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
require 'time'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module Profiling
|
|
8
|
+
module Collectors
|
|
9
|
+
# Collects information of relevance for profiler. This will get sent alongside
|
|
10
|
+
# the profile and show up in the UI or potentially influence processing in some way.
|
|
11
|
+
#
|
|
12
|
+
# Information is currently collected and frozen at construction time. A full collector
|
|
13
|
+
# could be seen as overkill for this case but it allows us to centralize information
|
|
14
|
+
# gathering and easily support more flexible/dynamic info collection in the future.
|
|
15
|
+
class Info
|
|
16
|
+
def initialize(settings)
|
|
17
|
+
@profiler_info = nil
|
|
18
|
+
@info = {
|
|
19
|
+
platform: collect_platform_info,
|
|
20
|
+
runtime: collect_runtime_info,
|
|
21
|
+
application: collect_application_info(settings),
|
|
22
|
+
profiler: collect_profiler_info(settings),
|
|
23
|
+
}.freeze
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
attr_reader :info
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Instead of trying to figure out real process start time by checking
|
|
31
|
+
# /proc or some other complex/non-portable way, approximate start time
|
|
32
|
+
# by time of requirement of this file.
|
|
33
|
+
START_TIME = Time.now.utc.freeze
|
|
34
|
+
|
|
35
|
+
def collect_platform_info
|
|
36
|
+
@platform_info ||= {
|
|
37
|
+
container_id: Datadog::Core::Environment::Container.container_id,
|
|
38
|
+
hostname: Datadog::Core::Environment::Platform.hostname,
|
|
39
|
+
kernel_name: Datadog::Core::Environment::Platform.kernel_name,
|
|
40
|
+
kernel_release: Datadog::Core::Environment::Platform.kernel_release,
|
|
41
|
+
kernel_version: Datadog::Core::Environment::Platform.kernel_version
|
|
42
|
+
}.freeze
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def collect_runtime_info
|
|
46
|
+
@runtime_info ||= {
|
|
47
|
+
engine: Datadog::Core::Environment::Identity.lang_engine,
|
|
48
|
+
version: Datadog::Core::Environment::Identity.lang_version,
|
|
49
|
+
platform: Datadog::Core::Environment::Identity.lang_platform,
|
|
50
|
+
}.freeze
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def collect_application_info(settings)
|
|
54
|
+
@application_info ||= {
|
|
55
|
+
start_time: START_TIME.iso8601,
|
|
56
|
+
env: settings.env,
|
|
57
|
+
service: settings.service,
|
|
58
|
+
version: settings.version,
|
|
59
|
+
}.freeze
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def collect_profiler_info(settings)
|
|
63
|
+
unless @profiler_info
|
|
64
|
+
lib_datadog_gem = ::Gem.loaded_specs['libdatadog']
|
|
65
|
+
@profiler_info = {
|
|
66
|
+
version: Datadog::Core::Environment::Identity.tracer_version,
|
|
67
|
+
libdatadog: "#{lib_datadog_gem.version}-#{lib_datadog_gem.platform}",
|
|
68
|
+
settings: collect_settings_recursively(settings.profiling),
|
|
69
|
+
}.freeze
|
|
70
|
+
end
|
|
71
|
+
@profiler_info
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The settings/option model isn't directly serializable because
|
|
75
|
+
# of subsettings and options that link to full blown custom object
|
|
76
|
+
# instances without proper serialization.
|
|
77
|
+
# This method navigates a settings object recursively, converting
|
|
78
|
+
# it into more basic types that are trivially convertible to JSON.
|
|
79
|
+
def collect_settings_recursively(v)
|
|
80
|
+
v = v.options_hash if v.respond_to?(:options_hash)
|
|
81
|
+
|
|
82
|
+
if v.nil? || v.is_a?(Symbol) || v.is_a?(Numeric) || v.is_a?(String) || v.equal?(true) || v.equal?(false)
|
|
83
|
+
Core::Utils::SafeDup.frozen_or_dup(v)
|
|
84
|
+
elsif v.is_a?(Hash)
|
|
85
|
+
collected_hash = v.each_with_object({}) do |(key, value), hash|
|
|
86
|
+
collected_value = collect_settings_recursively(value)
|
|
87
|
+
hash[key] = collected_value
|
|
88
|
+
end
|
|
89
|
+
collected_hash.freeze
|
|
90
|
+
elsif v.is_a?(Enumerable)
|
|
91
|
+
collected_list = v
|
|
92
|
+
.map { |value| collect_settings_recursively(value) }
|
|
93
|
+
collected_list.freeze
|
|
94
|
+
else
|
|
95
|
+
v.inspect
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -7,12 +7,8 @@ module Datadog
|
|
|
7
7
|
# Passing in a `nil` tracer is supported and will disable the following profiling features:
|
|
8
8
|
# * Code Hotspots panel in the trace viewer, as well as scoping a profile down to a span
|
|
9
9
|
# * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
|
|
10
|
-
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Profiling::Diagnostics::EnvironmentLogger.collect_and_log!
|
|
14
|
-
|
|
15
|
-
return unless settings.profiling.enabled
|
|
10
|
+
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:) # rubocop:disable Metrics/MethodLength
|
|
11
|
+
return [nil, { profiling_enabled: false }] unless settings.profiling.enabled
|
|
16
12
|
|
|
17
13
|
# Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
|
|
18
14
|
# dependency on individual products, in this case the Profiler.
|
|
@@ -32,7 +28,8 @@ module Datadog
|
|
|
32
28
|
# done, then profiling may not be loaded, and thus to avoid this issue we do a require here (which is a
|
|
33
29
|
# no-op if profiling is already loaded).
|
|
34
30
|
require_relative '../profiling'
|
|
35
|
-
|
|
31
|
+
|
|
32
|
+
return [nil, { profiling_enabled: false }] unless Profiling.supported?
|
|
36
33
|
|
|
37
34
|
# Activate forking extensions
|
|
38
35
|
Profiling::Tasks::Setup.new.run
|
|
@@ -40,45 +37,64 @@ module Datadog
|
|
|
40
37
|
# NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
|
|
41
38
|
|
|
42
39
|
no_signals_workaround_enabled = no_signals_workaround_enabled?(settings)
|
|
43
|
-
timeline_enabled = settings.profiling.advanced.
|
|
40
|
+
timeline_enabled = settings.profiling.advanced.timeline_enabled
|
|
41
|
+
allocation_profiling_enabled = enable_allocation_profiling?(settings)
|
|
42
|
+
heap_sample_every = get_heap_sample_every(settings)
|
|
43
|
+
heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every)
|
|
44
|
+
heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
|
45
|
+
|
|
46
|
+
overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage)
|
|
47
|
+
upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
|
|
44
48
|
|
|
45
49
|
recorder = Datadog::Profiling::StackRecorder.new(
|
|
46
50
|
cpu_time_enabled: RUBY_PLATFORM.include?('linux'), # Only supported on Linux currently
|
|
47
|
-
alloc_samples_enabled:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
max_frames: settings.profiling.advanced.max_frames,
|
|
52
|
-
tracer: optional_tracer,
|
|
53
|
-
endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled,
|
|
51
|
+
alloc_samples_enabled: allocation_profiling_enabled,
|
|
52
|
+
heap_samples_enabled: heap_profiling_enabled,
|
|
53
|
+
heap_size_enabled: heap_size_profiling_enabled,
|
|
54
|
+
heap_sample_every: heap_sample_every,
|
|
54
55
|
timeline_enabled: timeline_enabled,
|
|
55
56
|
)
|
|
57
|
+
thread_context_collector = build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
|
56
58
|
worker = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
|
|
57
59
|
gc_profiling_enabled: enable_gc_profiling?(settings),
|
|
58
|
-
allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
|
|
59
60
|
no_signals_workaround_enabled: no_signals_workaround_enabled,
|
|
60
61
|
thread_context_collector: thread_context_collector,
|
|
61
|
-
|
|
62
|
+
dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
|
|
63
|
+
allocation_profiling_enabled: allocation_profiling_enabled,
|
|
62
64
|
)
|
|
63
65
|
|
|
64
66
|
internal_metadata = {
|
|
65
67
|
no_signals_workaround_enabled: no_signals_workaround_enabled,
|
|
66
68
|
timeline_enabled: timeline_enabled,
|
|
69
|
+
heap_sample_every: heap_sample_every,
|
|
67
70
|
}.freeze
|
|
68
71
|
|
|
69
|
-
exporter = build_profiler_exporter(settings, recorder, internal_metadata: internal_metadata)
|
|
72
|
+
exporter = build_profiler_exporter(settings, recorder, worker, internal_metadata: internal_metadata)
|
|
70
73
|
transport = build_profiler_transport(settings, agent_settings)
|
|
71
|
-
scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport)
|
|
74
|
+
scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
|
|
72
75
|
|
|
73
|
-
Profiling::Profiler.new(worker: worker, scheduler: scheduler)
|
|
76
|
+
[Profiling::Profiler.new(worker: worker, scheduler: scheduler), { profiling_enabled: true }]
|
|
74
77
|
end
|
|
75
78
|
|
|
76
|
-
private_class_method def self.
|
|
79
|
+
private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
|
80
|
+
Datadog::Profiling::Collectors::ThreadContext.new(
|
|
81
|
+
recorder: recorder,
|
|
82
|
+
max_frames: settings.profiling.advanced.max_frames,
|
|
83
|
+
tracer: optional_tracer,
|
|
84
|
+
endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled,
|
|
85
|
+
timeline_enabled: timeline_enabled,
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private_class_method def self.build_profiler_exporter(settings, recorder, worker, internal_metadata:)
|
|
90
|
+
info_collector = Profiling::Collectors::Info.new(settings)
|
|
77
91
|
code_provenance_collector =
|
|
78
92
|
(Profiling::Collectors::CodeProvenance.new if settings.profiling.advanced.code_provenance_enabled)
|
|
79
93
|
|
|
80
94
|
Profiling::Exporter.new(
|
|
81
95
|
pprof_recorder: recorder,
|
|
96
|
+
worker: worker,
|
|
97
|
+
info_collector: info_collector,
|
|
82
98
|
code_provenance_collector: code_provenance_collector,
|
|
83
99
|
internal_metadata: internal_metadata,
|
|
84
100
|
)
|
|
@@ -95,19 +111,134 @@ module Datadog
|
|
|
95
111
|
end
|
|
96
112
|
|
|
97
113
|
private_class_method def self.enable_gc_profiling?(settings)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
return false unless settings.profiling.advanced.gc_enabled
|
|
115
|
+
|
|
116
|
+
# SEVERE - Only with Ractors
|
|
117
|
+
# On Ruby versions 3.0 (all), 3.1.0 to 3.1.3, and 3.2.0 to 3.2.2 gc profiling can trigger a VM bug
|
|
118
|
+
# that causes a segmentation fault during garbage collection of Ractors
|
|
119
|
+
# (https://bugs.ruby-lang.org/issues/18464). We don't allow enabling gc profiling on such Rubies.
|
|
120
|
+
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
|
121
|
+
if RUBY_VERSION.start_with?('3.0.') ||
|
|
122
|
+
(RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION < '3.1.4') ||
|
|
123
|
+
(RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3')
|
|
124
|
+
Datadog.logger.warn(
|
|
125
|
+
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause "\
|
|
126
|
+
'crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled.'
|
|
127
|
+
)
|
|
128
|
+
return false
|
|
129
|
+
elsif RUBY_VERSION.start_with?('3.')
|
|
130
|
+
Datadog.logger.debug(
|
|
131
|
+
'In all known versions of Ruby 3.x, using Ractors may result in GC profiling unexpectedly ' \
|
|
132
|
+
'stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your ' \
|
|
133
|
+
'application stability or performance. This does not happen if Ractors are not used.'
|
|
134
|
+
)
|
|
135
|
+
end
|
|
106
136
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
137
|
+
true
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private_class_method def self.get_heap_sample_every(settings)
|
|
141
|
+
heap_sample_rate = settings.profiling.advanced.experimental_heap_sample_rate
|
|
142
|
+
|
|
143
|
+
raise ArgumentError, "Heap sample rate must be a positive integer. Was #{heap_sample_rate}" if heap_sample_rate <= 0
|
|
144
|
+
|
|
145
|
+
heap_sample_rate
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private_class_method def self.enable_allocation_profiling?(settings)
|
|
149
|
+
return false unless settings.profiling.allocation_enabled
|
|
150
|
+
|
|
151
|
+
# Allocation sampling is safe and supported on Ruby 2.x, but has a few caveats on Ruby 3.x.
|
|
152
|
+
|
|
153
|
+
# SEVERE - All configurations
|
|
154
|
+
# Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
|
|
155
|
+
# https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
|
|
156
|
+
# fixed on Ruby versions 3.2.3 and 3.3.0.
|
|
157
|
+
if RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3'
|
|
158
|
+
Datadog.logger.warn(
|
|
159
|
+
'Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly '\
|
|
160
|
+
'disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). '\
|
|
161
|
+
'Other Ruby versions do not suffer from this issue.'
|
|
162
|
+
)
|
|
163
|
+
return false
|
|
110
164
|
end
|
|
165
|
+
|
|
166
|
+
# SEVERE - Only with Ractors
|
|
167
|
+
# On Ruby versions 3.0 (all), 3.1.0 to 3.1.3, and 3.2.0 to 3.2.2 allocation profiling can trigger a VM bug
|
|
168
|
+
# that causes a segmentation fault during garbage collection of Ractors
|
|
169
|
+
# (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
|
|
170
|
+
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
|
171
|
+
if RUBY_VERSION.start_with?('3.0.') ||
|
|
172
|
+
(RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION < '3.1.4') ||
|
|
173
|
+
(RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3')
|
|
174
|
+
Datadog.logger.warn(
|
|
175
|
+
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using "\
|
|
176
|
+
'Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). '\
|
|
177
|
+
'This does not happen if Ractors are not used.'
|
|
178
|
+
)
|
|
179
|
+
# ANNOYANCE - Only with Ractors
|
|
180
|
+
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
|
|
181
|
+
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
|
|
182
|
+
elsif RUBY_VERSION.start_with?('3.')
|
|
183
|
+
Datadog.logger.warn(
|
|
184
|
+
'In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly ' \
|
|
185
|
+
'stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your ' \
|
|
186
|
+
'application stability or performance. This does not happen if Ractors are not used.'
|
|
187
|
+
)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
Datadog.logger.debug('Enabled allocation profiling')
|
|
191
|
+
|
|
192
|
+
true
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate)
|
|
196
|
+
heap_profiling_enabled = settings.profiling.advanced.experimental_heap_enabled
|
|
197
|
+
|
|
198
|
+
return false unless heap_profiling_enabled
|
|
199
|
+
|
|
200
|
+
if RUBY_VERSION.start_with?('2.') && RUBY_VERSION < '2.7'
|
|
201
|
+
Datadog.logger.warn(
|
|
202
|
+
'Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. '\
|
|
203
|
+
'Please upgrade to Ruby >= 2.7 in order to use this feature.'
|
|
204
|
+
)
|
|
205
|
+
return false
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if RUBY_VERSION < '3.1'
|
|
209
|
+
Datadog.logger.debug(
|
|
210
|
+
"Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
|
|
211
|
+
'heap profiler is forced to work around to remain accurate. This workaround requires force-setting '\
|
|
212
|
+
"the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
|
|
213
|
+
'https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be ' \
|
|
214
|
+
'bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling ' \
|
|
215
|
+
'was completely removed (https://bugs.ruby-lang.org/issues/18290).'
|
|
216
|
+
)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
unless allocation_profiling_enabled
|
|
220
|
+
raise ArgumentError,
|
|
221
|
+
'Heap profiling requires allocation profiling to be enabled'
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
Datadog.logger.warn(
|
|
225
|
+
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
|
226
|
+
'recommended, and will increase overhead!'
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
true
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
|
233
|
+
heap_size_profiling_enabled = settings.profiling.advanced.experimental_heap_size_enabled
|
|
234
|
+
|
|
235
|
+
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
|
236
|
+
|
|
237
|
+
Datadog.logger.warn(
|
|
238
|
+
'Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!'
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
true
|
|
111
242
|
end
|
|
112
243
|
|
|
113
244
|
private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
|
|
@@ -217,9 +348,12 @@ module Datadog
|
|
|
217
348
|
|
|
218
349
|
return true unless mysql2_client_class && mysql2_client_class.respond_to?(:info)
|
|
219
350
|
|
|
220
|
-
|
|
351
|
+
info = mysql2_client_class.info
|
|
352
|
+
libmysqlclient_version = Gem::Version.new(info[:version])
|
|
221
353
|
|
|
222
|
-
compatible =
|
|
354
|
+
compatible =
|
|
355
|
+
libmysqlclient_version >= Gem::Version.new('8.0.0') ||
|
|
356
|
+
looks_like_mariadb?(info, libmysqlclient_version)
|
|
223
357
|
|
|
224
358
|
Datadog.logger.debug(
|
|
225
359
|
"The `mysql2` gem is using #{compatible ? 'a compatible' : 'an incompatible'} version of " \
|
|
@@ -245,6 +379,48 @@ module Datadog
|
|
|
245
379
|
true
|
|
246
380
|
end
|
|
247
381
|
end
|
|
382
|
+
|
|
383
|
+
private_class_method def self.valid_overhead_target(overhead_target_percentage)
|
|
384
|
+
if overhead_target_percentage > 0 && overhead_target_percentage <= 20
|
|
385
|
+
overhead_target_percentage
|
|
386
|
+
else
|
|
387
|
+
Datadog.logger.error(
|
|
388
|
+
'Ignoring invalid value for profiling overhead_target_percentage setting: ' \
|
|
389
|
+
"#{overhead_target_percentage.inspect}. Falling back to default value."
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
2.0
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# To add just a bit more complexity to our detection code, in https://github.com/DataDog/dd-trace-rb/issues/3334
|
|
397
|
+
# a user reported that our code was incorrectly flagging the mariadb variant of libmysqlclient as being
|
|
398
|
+
# incompatible. In fact we have no reports of the mariadb variant needing the "no signals" workaround,
|
|
399
|
+
# so we flag it as compatible when it's in use.
|
|
400
|
+
#
|
|
401
|
+
# A problem is that there doesn't seem to be an obvious way to query the mysql2 gem on which kind of
|
|
402
|
+
# libmysqlclient it's using, so we detect it by looking at the version.
|
|
403
|
+
#
|
|
404
|
+
# The info method for mysql2 with mariadb looks something like this:
|
|
405
|
+
# `{:id=>30308, :version=>"3.3.8", :header_version=>"11.2.2"}`
|
|
406
|
+
#
|
|
407
|
+
# * The version seems to come from https://github.com/mariadb-corporation/mariadb-connector-c and the latest
|
|
408
|
+
# one is 3.x.
|
|
409
|
+
# * The header_version is what people usually see as the "mariadb version"
|
|
410
|
+
#
|
|
411
|
+
# As a comparison, for libmysql the info looks like:
|
|
412
|
+
# * `{:id=>80035, :version=>"8.0.35", :header_version=>"8.0.35"}`
|
|
413
|
+
#
|
|
414
|
+
# Thus our detection is version 4 or older, because libmysqlclient 4 is almost 20 years old so it's most probably
|
|
415
|
+
# not that one + header_version being 10 or newer, since according to https://endoflife.date/mariadb that's a
|
|
416
|
+
# sane range for modern mariadb releases.
|
|
417
|
+
private_class_method def self.looks_like_mariadb?(info, libmysqlclient_version)
|
|
418
|
+
header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
|
|
419
|
+
|
|
420
|
+
!!(header_version &&
|
|
421
|
+
libmysqlclient_version < Gem::Version.new('5.0.0') &&
|
|
422
|
+
header_version >= Gem::Version.new('10.0.0'))
|
|
423
|
+
end
|
|
248
424
|
end
|
|
249
425
|
end
|
|
250
426
|
end
|
|
@@ -23,31 +23,40 @@ module Datadog
|
|
|
23
23
|
:time_provider,
|
|
24
24
|
:last_flush_finish_at,
|
|
25
25
|
:created_at,
|
|
26
|
-
:internal_metadata
|
|
26
|
+
:internal_metadata,
|
|
27
|
+
:info_json
|
|
27
28
|
|
|
28
29
|
public
|
|
29
30
|
|
|
30
31
|
def initialize(
|
|
31
32
|
pprof_recorder:,
|
|
33
|
+
worker:,
|
|
34
|
+
info_collector:,
|
|
32
35
|
code_provenance_collector:,
|
|
33
36
|
internal_metadata:,
|
|
34
37
|
minimum_duration_seconds: PROFILE_DURATION_THRESHOLD_SECONDS,
|
|
35
38
|
time_provider: Time
|
|
36
39
|
)
|
|
37
40
|
@pprof_recorder = pprof_recorder
|
|
41
|
+
@worker = worker
|
|
38
42
|
@code_provenance_collector = code_provenance_collector
|
|
39
43
|
@minimum_duration_seconds = minimum_duration_seconds
|
|
40
44
|
@time_provider = time_provider
|
|
41
45
|
@last_flush_finish_at = nil
|
|
42
46
|
@created_at = time_provider.now.utc
|
|
43
47
|
@internal_metadata = internal_metadata
|
|
48
|
+
# NOTE: At the time of this comment collected info does not change over time so we'll hardcode
|
|
49
|
+
# it on startup to prevent serializing the same info on every flush.
|
|
50
|
+
@info_json = JSON.fast_generate(info_collector.info).freeze
|
|
44
51
|
end
|
|
45
52
|
|
|
46
53
|
def flush
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
worker_stats = @worker.stats_and_reset_not_thread_safe
|
|
55
|
+
serialization_result = pprof_recorder.serialize
|
|
56
|
+
return if serialization_result.nil?
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
start, finish, compressed_pprof, profile_stats = serialization_result
|
|
59
|
+
@last_flush_finish_at = finish
|
|
51
60
|
|
|
52
61
|
if duration_below_threshold?(start, finish)
|
|
53
62
|
Datadog.logger.debug('Skipped exporting profiling events as profile duration is below minimum')
|
|
@@ -60,11 +69,19 @@ module Datadog
|
|
|
60
69
|
start: start,
|
|
61
70
|
finish: finish,
|
|
62
71
|
pprof_file_name: Datadog::Profiling::Ext::Transport::HTTP::PPROF_DEFAULT_FILENAME,
|
|
63
|
-
pprof_data:
|
|
72
|
+
pprof_data: compressed_pprof.to_s,
|
|
64
73
|
code_provenance_file_name: Datadog::Profiling::Ext::Transport::HTTP::CODE_PROVENANCE_FILENAME,
|
|
65
74
|
code_provenance_data: uncompressed_code_provenance,
|
|
66
75
|
tags_as_array: Datadog::Profiling::TagBuilder.call(settings: Datadog.configuration).to_a,
|
|
67
|
-
internal_metadata: internal_metadata
|
|
76
|
+
internal_metadata: internal_metadata.merge(
|
|
77
|
+
{
|
|
78
|
+
worker_stats: worker_stats,
|
|
79
|
+
profile_stats: profile_stats,
|
|
80
|
+
recorder_stats: pprof_recorder.stats,
|
|
81
|
+
gc: GC.stat,
|
|
82
|
+
}
|
|
83
|
+
),
|
|
84
|
+
info_json: info_json,
|
|
68
85
|
)
|
|
69
86
|
end
|
|
70
87
|
|
|
@@ -23,6 +23,8 @@ module Datadog
|
|
|
23
23
|
FORM_FIELD_TAG_RUNTIME_VERSION = 'runtime_version'
|
|
24
24
|
FORM_FIELD_TAG_SERVICE = 'service'
|
|
25
25
|
FORM_FIELD_TAG_VERSION = 'version'
|
|
26
|
+
TAG_GIT_REPOSITORY_URL = 'git.repository_url'
|
|
27
|
+
TAG_GIT_COMMIT_SHA = 'git.commit.sha'
|
|
26
28
|
|
|
27
29
|
PPROF_DEFAULT_FILENAME = 'rubyprofile.pprof'
|
|
28
30
|
CODE_PROVENANCE_FILENAME = 'code-provenance.json'
|
|
@@ -14,7 +14,8 @@ module Datadog
|
|
|
14
14
|
:code_provenance_file_name,
|
|
15
15
|
:code_provenance_data, # gzipped json bytes
|
|
16
16
|
:tags_as_array,
|
|
17
|
-
:internal_metadata_json
|
|
17
|
+
:internal_metadata_json,
|
|
18
|
+
:info_json
|
|
18
19
|
|
|
19
20
|
def initialize(
|
|
20
21
|
start:,
|
|
@@ -24,7 +25,8 @@ module Datadog
|
|
|
24
25
|
code_provenance_file_name:,
|
|
25
26
|
code_provenance_data:,
|
|
26
27
|
tags_as_array:,
|
|
27
|
-
internal_metadata
|
|
28
|
+
internal_metadata:,
|
|
29
|
+
info_json:
|
|
28
30
|
)
|
|
29
31
|
@start = start
|
|
30
32
|
@finish = finish
|
|
@@ -33,7 +35,8 @@ module Datadog
|
|
|
33
35
|
@code_provenance_file_name = code_provenance_file_name
|
|
34
36
|
@code_provenance_data = code_provenance_data
|
|
35
37
|
@tags_as_array = tags_as_array
|
|
36
|
-
@internal_metadata_json = JSON.fast_generate(internal_metadata
|
|
38
|
+
@internal_metadata_json = JSON.fast_generate(internal_metadata)
|
|
39
|
+
@info_json = info_json
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
end
|
|
@@ -43,6 +43,8 @@ module Datadog
|
|
|
43
43
|
|
|
44
44
|
tags_as_array: flush.tags_as_array,
|
|
45
45
|
internal_metadata_json: flush.internal_metadata_json,
|
|
46
|
+
|
|
47
|
+
info_json: flush.info_json
|
|
46
48
|
)
|
|
47
49
|
|
|
48
50
|
if status == :ok
|
|
@@ -117,7 +119,8 @@ module Datadog
|
|
|
117
119
|
code_provenance_file_name:,
|
|
118
120
|
code_provenance_data:,
|
|
119
121
|
tags_as_array:,
|
|
120
|
-
internal_metadata_json
|
|
122
|
+
internal_metadata_json:,
|
|
123
|
+
info_json:
|
|
121
124
|
)
|
|
122
125
|
self.class._native_do_export(
|
|
123
126
|
exporter_configuration,
|
|
@@ -132,6 +135,7 @@ module Datadog
|
|
|
132
135
|
code_provenance_data,
|
|
133
136
|
tags_as_array,
|
|
134
137
|
internal_metadata_json,
|
|
138
|
+
info_json,
|
|
135
139
|
)
|
|
136
140
|
end
|
|
137
141
|
|
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
# This file is used to load the profiling native extension. It works in two steps:
|
|
2
2
|
#
|
|
3
|
-
# 1. Load the
|
|
4
|
-
# a special way that avoids exposing native-level code symbols. See `
|
|
3
|
+
# 1. Load the datadog_profiling_loader extension. This extension will be used to load the actual extension, but in
|
|
4
|
+
# a special way that avoids exposing native-level code symbols. See `datadog_profiling_loader.c` for more details.
|
|
5
5
|
#
|
|
6
|
-
# 2. Use the Datadog::Profiling::Loader exposed by the
|
|
6
|
+
# 2. Use the Datadog::Profiling::Loader exposed by the datadog_profiling_loader extension to load the actual
|
|
7
7
|
# profiling native extension.
|
|
8
8
|
#
|
|
9
9
|
# All code on this file is on-purpose at the top-level; this makes it so this file is executed only once,
|
|
10
10
|
# the first time it gets required, to avoid any issues with the native extension being initialized more than once.
|
|
11
11
|
|
|
12
12
|
begin
|
|
13
|
-
require "
|
|
13
|
+
require "datadog_profiling_loader.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
|
|
14
14
|
rescue LoadError => e
|
|
15
15
|
raise LoadError,
|
|
16
16
|
'Failed to load the profiling loader extension. To fix this, please remove and then reinstall ddtrace ' \
|
|
17
17
|
"(Details: #{e.message})"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
extension_name = "
|
|
21
|
-
|
|
20
|
+
extension_name = "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
|
|
21
|
+
file_name = "#{extension_name}.#{RbConfig::CONFIG['DLEXT']}"
|
|
22
|
+
full_file_path = "#{__dir__}/../../#{file_name}"
|
|
23
|
+
|
|
24
|
+
unless File.exist?(full_file_path)
|
|
25
|
+
extension_dir = Gem.loaded_specs['ddtrace'].extension_dir
|
|
26
|
+
candidate_path = "#{extension_dir}/#{file_name}"
|
|
27
|
+
if File.exist?(candidate_path)
|
|
28
|
+
full_file_path = candidate_path
|
|
29
|
+
else # rubocop:disable Style/EmptyElse
|
|
30
|
+
# We found none of the files. This is unexpected. Let's go ahead anyway, the error is going to be reported further
|
|
31
|
+
# down anyway.
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
22
35
|
init_function_name = "Init_#{extension_name.split('.').first}"
|
|
23
36
|
|
|
24
37
|
status, result = Datadog::Profiling::Loader._native_load(full_file_path, init_function_name)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Datadog
|
|
4
4
|
module Profiling
|
|
5
5
|
# This module contains classes and methods which are implemented using native code in the
|
|
6
|
-
# ext/
|
|
6
|
+
# ext/datadog_profiling_native_extension folder, as well as some Ruby-level utilities that don't make sense to
|
|
7
7
|
# write using C
|
|
8
8
|
module NativeExtension
|
|
9
9
|
private_class_method def self.working?
|
|
@@ -5,12 +5,11 @@ require_relative '../core/workers/polling'
|
|
|
5
5
|
|
|
6
6
|
module Datadog
|
|
7
7
|
module Profiling
|
|
8
|
-
# Periodically (every
|
|
8
|
+
# Periodically (every interval, 60 seconds by default) takes a profile from the `Exporter` and reports it using the
|
|
9
9
|
# configured transport. Runs on its own background thread.
|
|
10
10
|
class Scheduler < Core::Worker
|
|
11
11
|
include Core::Workers::Polling
|
|
12
12
|
|
|
13
|
-
DEFAULT_INTERVAL_SECONDS = 60
|
|
14
13
|
MINIMUM_INTERVAL_SECONDS = 0
|
|
15
14
|
|
|
16
15
|
# We sleep for at most this duration seconds before reporting data to avoid multi-process applications all
|
|
@@ -28,8 +27,7 @@ module Datadog
|
|
|
28
27
|
def initialize(
|
|
29
28
|
exporter:,
|
|
30
29
|
transport:,
|
|
31
|
-
fork_policy: Core::Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default
|
|
32
|
-
interval: DEFAULT_INTERVAL_SECONDS,
|
|
30
|
+
interval:, fork_policy: Core::Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default, # seconds
|
|
33
31
|
enabled: true
|
|
34
32
|
)
|
|
35
33
|
@exporter = exporter
|
|
@@ -115,8 +113,8 @@ module Datadog
|
|
|
115
113
|
#
|
|
116
114
|
# During PR review (https://github.com/DataDog/dd-trace-rb/pull/1807) we discussed the possible alternative of
|
|
117
115
|
# just sleeping before starting the scheduler loop. We ended up not going with that option to avoid the first
|
|
118
|
-
# profile containing up to
|
|
119
|
-
# usual
|
|
116
|
+
# profile containing up to interval + DEFAULT_FLUSH_JITTER_MAXIMUM_SECONDS instead of the
|
|
117
|
+
# usual interval seconds.
|
|
120
118
|
if run_loop?
|
|
121
119
|
jitter_seconds = rand * DEFAULT_FLUSH_JITTER_MAXIMUM_SECONDS # floating point number between (0.0...maximum)
|
|
122
120
|
sleep(jitter_seconds)
|