datadog 2.2.0 → 2.3.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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -2
  3. data/ext/datadog_profiling_loader/extconf.rb +15 -15
  4. data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
  5. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
  6. data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
  7. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +113 -43
  8. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
  10. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
  11. data/ext/datadog_profiling_native_extension/collectors_stack.c +49 -37
  12. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
  17. data/ext/datadog_profiling_native_extension/extconf.rb +65 -60
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
  20. data/ext/datadog_profiling_native_extension/helpers.h +6 -17
  21. data/ext/datadog_profiling_native_extension/http_transport.c +3 -3
  22. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
  23. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
  24. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -172
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -138
  26. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
  27. data/ext/datadog_profiling_native_extension/profiling.c +0 -2
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
  29. data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
  30. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
  31. data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
  32. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
  33. data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
  34. data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
  35. data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +19 -6
  36. data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
  37. data/ext/libdatadog_api/datadog_ruby_common.h +57 -0
  38. data/ext/libdatadog_api/extconf.rb +108 -0
  39. data/ext/libdatadog_api/macos_development.md +26 -0
  40. data/ext/libdatadog_extconf_helpers.rb +130 -0
  41. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +49 -0
  42. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
  43. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
  44. data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -0
  45. data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
  46. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
  47. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
  48. data/lib/datadog/appsec/processor/actions.rb +1 -1
  49. data/lib/datadog/appsec/response.rb +15 -1
  50. data/lib/datadog/appsec.rb +1 -0
  51. data/lib/datadog/core/configuration/components.rb +14 -12
  52. data/lib/datadog/core/configuration/settings.rb +54 -7
  53. data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
  54. data/lib/datadog/core/crashtracking/component.rb +111 -0
  55. data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
  56. data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
  57. data/lib/datadog/core/telemetry/component.rb +49 -2
  58. data/lib/datadog/core/telemetry/emitter.rb +9 -11
  59. data/lib/datadog/core/telemetry/event.rb +32 -1
  60. data/lib/datadog/core/telemetry/ext.rb +1 -0
  61. data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
  62. data/lib/datadog/core/telemetry/http/ext.rb +3 -0
  63. data/lib/datadog/core/telemetry/http/transport.rb +38 -9
  64. data/lib/datadog/core/telemetry/logging.rb +35 -0
  65. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
  66. data/lib/datadog/kit/appsec/events.rb +2 -4
  67. data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
  68. data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
  69. data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
  70. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +17 -17
  71. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
  72. data/lib/datadog/profiling/collectors/info.rb +3 -3
  73. data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
  74. data/lib/datadog/profiling/component.rb +69 -91
  75. data/lib/datadog/profiling/exporter.rb +3 -3
  76. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
  77. data/lib/datadog/profiling/ext.rb +21 -21
  78. data/lib/datadog/profiling/flush.rb +1 -1
  79. data/lib/datadog/profiling/http_transport.rb +8 -6
  80. data/lib/datadog/profiling/load_native_extension.rb +5 -5
  81. data/lib/datadog/profiling/preload.rb +1 -1
  82. data/lib/datadog/profiling/profiler.rb +5 -8
  83. data/lib/datadog/profiling/scheduler.rb +31 -25
  84. data/lib/datadog/profiling/tag_builder.rb +2 -2
  85. data/lib/datadog/profiling/tasks/exec.rb +5 -5
  86. data/lib/datadog/profiling/tasks/setup.rb +16 -35
  87. data/lib/datadog/profiling.rb +4 -5
  88. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  89. data/lib/datadog/tracing/contrib/ext.rb +14 -0
  90. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +1 -1
  91. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +4 -1
  92. data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -0
  93. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
  94. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
  95. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  96. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
  97. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
  98. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
  99. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
  100. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
  101. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
  102. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
  103. data/lib/datadog/tracing/metadata/errors.rb +9 -1
  104. data/lib/datadog/tracing/metadata/ext.rb +4 -0
  105. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  106. data/lib/datadog/tracing/span.rb +9 -2
  107. data/lib/datadog/tracing/span_event.rb +41 -0
  108. data/lib/datadog/tracing/span_operation.rb +6 -2
  109. data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
  110. data/lib/datadog/version.rb +1 -1
  111. metadata +28 -10
  112. data/lib/datadog/profiling/crashtracker.rb +0 -91
  113. data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'trace/span'
4
4
  require_relative '../../tracing/span_link'
5
+ require_relative '../../tracing/span_event'
5
6
  require_relative '../../tracing/trace_digest'
6
7
 
7
8
  module Datadog
@@ -31,6 +32,15 @@ module Datadog
31
32
  #
32
33
  # @param [Span] span the {Span} that just ended.
33
34
  def on_finish(span)
35
+ unless span.events.nil?
36
+ span.datadog_span.span_events = span.events.map do |event|
37
+ Datadog::Tracing::SpanEvent.new(
38
+ event.name,
39
+ attributes: event.attributes,
40
+ time_unix_nano: event.timestamp
41
+ )
42
+ end
43
+ end
34
44
  span.datadog_span.finish(ns_to_time(span.end_timestamp))
35
45
  end
36
46
 
@@ -15,6 +15,29 @@ module Datadog
15
15
  res
16
16
  end
17
17
 
18
+ # Record an exception during the execution of this span. Multiple exceptions
19
+ # can be recorded on a span.
20
+ #
21
+ # @param [Exception] exception The exception to recorded
22
+ # @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
23
+ # attributes One or more key:value pairs, where the keys must be
24
+ # strings and the values may be (array of) string, boolean or numeric
25
+ # type.
26
+ #
27
+ # @return [void]
28
+ def record_exception(exception, attributes: nil)
29
+ res = super
30
+ if (span = datadog_span)
31
+ # Sets the exception attributes as span error tags. The values in the attribute hash MUST
32
+ # take precedence over the type, message and stacktrace inferred from the exception object
33
+ type = attributes&.[]('exception.type') || exception.class.to_s
34
+ message = attributes&.[]('exception.message') || exception.message
35
+ stacktrace = attributes&.[]('exception.stacktrace') || exception.full_message(highlight: false, order: :top)
36
+ span.set_error_tags([type, message, stacktrace])
37
+ end
38
+ res
39
+ end
40
+
18
41
  # `alias` performed to match {OpenTelemetry::SDK::Trace::Span} aliasing upstream
19
42
  alias []= set_attribute
20
43
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'json'
3
+ require "set"
4
+ require "json"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
@@ -14,7 +14,7 @@ module Datadog
14
14
  #
15
15
  # This class acts both as a collector (collecting data) as well as a recorder (records/serializes it)
16
16
  class CodeProvenance
17
- def initialize(standard_library_path: RbConfig::CONFIG.fetch('rubylibdir'))
17
+ def initialize(standard_library_path: RbConfig::CONFIG.fetch("rubylibdir"))
18
18
  @libraries_by_name = {}
19
19
  @libraries_by_path = {}
20
20
  @seen_files = Set.new
@@ -22,8 +22,8 @@ module Datadog
22
22
 
23
23
  record_library(
24
24
  Library.new(
25
- kind: 'standard library',
26
- name: 'stdlib',
25
+ kind: "standard library",
26
+ name: "stdlib",
27
27
  version: RUBY_VERSION,
28
28
  path: standard_library_path,
29
29
  )
@@ -79,7 +79,7 @@ module Datadog
79
79
  loaded_specs.each do |spec|
80
80
  next if libraries_by_name.key?(spec.name)
81
81
 
82
- record_library(Library.new(kind: 'library', name: spec.name, version: spec.version, path: spec.gem_dir))
82
+ record_library(Library.new(kind: "library", name: spec.name, version: spec.version, path: spec.gem_dir))
83
83
  recorded_library = true
84
84
  end
85
85
 
@@ -119,7 +119,7 @@ module Datadog
119
119
  end
120
120
 
121
121
  def to_json(arg = nil)
122
- { kind: @kind, name: @name, version: @version, paths: @paths }.to_json(arg)
122
+ {kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
123
123
  end
124
124
 
125
125
  def path
@@ -21,6 +21,7 @@ module Datadog
21
21
  thread_context_collector:,
22
22
  dynamic_sampling_rate_overhead_target_percentage:,
23
23
  allocation_profiling_enabled:,
24
+ allocation_counting_enabled:,
24
25
  # **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the
25
26
  # profiler overhead!
26
27
  dynamic_sampling_rate_enabled: true,
@@ -29,7 +30,7 @@ module Datadog
29
30
  )
30
31
  unless dynamic_sampling_rate_enabled
31
32
  Datadog.logger.warn(
32
- 'Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!'
33
+ "Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!"
33
34
  )
34
35
  end
35
36
 
@@ -42,6 +43,7 @@ module Datadog
42
43
  dynamic_sampling_rate_enabled,
43
44
  dynamic_sampling_rate_overhead_target_percentage,
44
45
  allocation_profiling_enabled,
46
+ allocation_counting_enabled,
45
47
  skip_idle_samples_for_testing,
46
48
  )
47
49
  @worker_thread = nil
@@ -54,27 +56,25 @@ module Datadog
54
56
 
55
57
  def start(on_failure_proc: nil)
56
58
  @start_stop_mutex.synchronize do
57
- return if @worker_thread && @worker_thread.alive?
59
+ return if @worker_thread&.alive?
58
60
 
59
61
  Datadog.logger.debug { "Starting thread for: #{self}" }
60
62
 
61
63
  @idle_sampling_helper.start
62
64
 
63
65
  @worker_thread = Thread.new do
64
- begin
65
- Thread.current.name = self.class.name
66
-
67
- self.class._native_sampling_loop(self)
68
-
69
- Datadog.logger.debug('CpuAndWallTimeWorker thread stopping cleanly')
70
- rescue Exception => e # rubocop:disable Lint/RescueException
71
- @failure_exception = e
72
- Datadog.logger.warn(
73
- 'CpuAndWallTimeWorker thread error. ' \
74
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
75
- )
76
- on_failure_proc&.call
77
- end
66
+ Thread.current.name = self.class.name
67
+
68
+ self.class._native_sampling_loop(self)
69
+
70
+ Datadog.logger.debug("CpuAndWallTimeWorker thread stopping cleanly")
71
+ rescue Exception => e # rubocop:disable Lint/RescueException
72
+ @failure_exception = e
73
+ Datadog.logger.warn(
74
+ "CpuAndWallTimeWorker thread error. " \
75
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
76
+ )
77
+ on_failure_proc&.call
78
78
  end
79
79
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
80
80
  @worker_thread.thread_variable_set(:fork_safe, true)
@@ -85,7 +85,7 @@ module Datadog
85
85
 
86
86
  def stop
87
87
  @start_stop_mutex.synchronize do
88
- Datadog.logger.debug('Requesting CpuAndWallTimeWorker thread shut down')
88
+ Datadog.logger.debug("Requesting CpuAndWallTimeWorker thread shut down")
89
89
 
90
90
  @idle_sampling_helper.stop
91
91
 
@@ -21,7 +21,7 @@ module Datadog
21
21
 
22
22
  def start
23
23
  @start_stop_mutex.synchronize do
24
- return if @worker_thread && @worker_thread.alive?
24
+ return if @worker_thread&.alive?
25
25
 
26
26
  Datadog.logger.debug { "Starting thread for: #{self}" }
27
27
 
@@ -30,19 +30,17 @@ module Datadog
30
30
  self.class._native_reset(self)
31
31
 
32
32
  @worker_thread = Thread.new do
33
- begin
34
- Thread.current.name = self.class.name
33
+ Thread.current.name = self.class.name
35
34
 
36
- self.class._native_idle_sampling_loop(self)
35
+ self.class._native_idle_sampling_loop(self)
37
36
 
38
- Datadog.logger.debug('IdleSamplingHelper thread stopping cleanly')
39
- rescue Exception => e # rubocop:disable Lint/RescueException
40
- @failure_exception = e
41
- Datadog.logger.warn(
42
- 'IdleSamplingHelper thread error. ' \
43
- "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
44
- )
45
- end
37
+ Datadog.logger.debug("IdleSamplingHelper thread stopping cleanly")
38
+ rescue Exception => e # rubocop:disable Lint/RescueException
39
+ @failure_exception = e
40
+ Datadog.logger.warn(
41
+ "IdleSamplingHelper thread error. " \
42
+ "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
43
+ )
46
44
  end
47
45
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
48
46
  @worker_thread.thread_variable_set(:fork_safe, true)
@@ -53,7 +51,7 @@ module Datadog
53
51
 
54
52
  def stop
55
53
  @start_stop_mutex.synchronize do
56
- Datadog.logger.debug('Requesting IdleSamplingHelper thread shut down')
54
+ Datadog.logger.debug("Requesting IdleSamplingHelper thread shut down")
57
55
 
58
56
  return unless @worker_thread
59
57
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
- require 'time'
3
+ require "set"
4
+ require "time"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
@@ -61,7 +61,7 @@ module Datadog
61
61
 
62
62
  def collect_profiler_info(settings)
63
63
  unless @profiler_info
64
- lib_datadog_gem = ::Gem.loaded_specs['libdatadog']
64
+ lib_datadog_gem = ::Gem.loaded_specs["libdatadog"]
65
65
  @profiler_info = {
66
66
  # TODO: If profiling is extracted and its version diverges from the datadog gem, this is inaccurate.
67
67
  # Update if this ever occurs.
@@ -48,12 +48,14 @@ module Datadog
48
48
  private
49
49
 
50
50
  def safely_extract_context_key_from(tracer)
51
- provider = tracer && tracer.respond_to?(:provider) && tracer.provider
51
+ return unless tracer
52
+
53
+ provider = tracer.respond_to?(:provider) && tracer.provider
52
54
 
53
55
  return unless provider
54
56
 
55
57
  context = provider.instance_variable_get(:@context)
56
- context && context.instance_variable_get(:@key)
58
+ context&.instance_variable_get(:@key)
57
59
  end
58
60
  end
59
61
  end
@@ -8,7 +8,7 @@ module Datadog
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
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
11
+ return [nil, {profiling_enabled: false}] unless settings.profiling.enabled
12
12
 
13
13
  # Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
14
14
  # dependency on individual products, in this case the Profiler.
@@ -27,9 +27,9 @@ module Datadog
27
27
  # On the other hand, if datadog/core is loaded by a different product and no general `require 'datadog'` is
28
28
  # done, then profiling may not be loaded, and thus to avoid this issue we do a require here (which is a
29
29
  # no-op if profiling is already loaded).
30
- require_relative '../profiling'
30
+ require_relative "../profiling"
31
31
 
32
- return [nil, { profiling_enabled: false }] unless Profiling.supported?
32
+ return [nil, {profiling_enabled: false}] unless Profiling.supported?
33
33
 
34
34
  # Activate forking extensions
35
35
  Profiling::Tasks::Setup.new.run
@@ -47,7 +47,7 @@ module Datadog
47
47
  upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
48
48
 
49
49
  recorder = Datadog::Profiling::StackRecorder.new(
50
- cpu_time_enabled: RUBY_PLATFORM.include?('linux'), # Only supported on Linux currently
50
+ cpu_time_enabled: RUBY_PLATFORM.include?("linux"), # Only supported on Linux currently
51
51
  alloc_samples_enabled: allocation_profiling_enabled,
52
52
  heap_samples_enabled: heap_profiling_enabled,
53
53
  heap_size_enabled: heap_size_profiling_enabled,
@@ -61,6 +61,7 @@ module Datadog
61
61
  thread_context_collector: thread_context_collector,
62
62
  dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
63
63
  allocation_profiling_enabled: allocation_profiling_enabled,
64
+ allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
64
65
  )
65
66
 
66
67
  internal_metadata = {
@@ -72,14 +73,13 @@ module Datadog
72
73
  exporter = build_profiler_exporter(settings, recorder, worker, internal_metadata: internal_metadata)
73
74
  transport = build_profiler_transport(settings, agent_settings)
74
75
  scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
75
- crashtracker = build_crashtracker(settings, transport)
76
- profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler, optional_crashtracker: crashtracker)
76
+ profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler)
77
77
 
78
78
  if dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
79
79
  Datadog::Profiling::Ext::DirMonkeyPatches.apply!
80
80
  end
81
81
 
82
- [profiler, { profiling_enabled: true }]
82
+ [profiler, {profiling_enabled: true}]
83
83
  end
84
84
 
85
85
  private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
@@ -116,28 +116,6 @@ module Datadog
116
116
  )
117
117
  end
118
118
 
119
- private_class_method def self.build_crashtracker(settings, transport)
120
- return unless settings.profiling.advanced.experimental_crash_tracking_enabled
121
-
122
- # By default, the transport is an instance of HttpTransport, which validates the configuration and makes
123
- # it available for us to use here.
124
- # But we support overriding the transport with a user-specific one, which may e.g. write stuff to a file,
125
- # and thus can't really provide a valid configuration to talk to a Datadog agent. Thus, in this situation,
126
- # we can't use the crashtracker, even if enabled.
127
- unless transport.respond_to?(:exporter_configuration)
128
- Datadog.logger.warn(
129
- 'Cannot enable profiling crash tracking as a custom settings.profiling.exporter.transport is configured'
130
- )
131
- return
132
- end
133
-
134
- Datadog::Profiling::Crashtracker.new(
135
- exporter_configuration: transport.exporter_configuration,
136
- tags: Datadog::Profiling::TagBuilder.call(settings: settings),
137
- upload_timeout_seconds: settings.profiling.upload.timeout_seconds,
138
- )
139
- end
140
-
141
119
  private_class_method def self.enable_gc_profiling?(settings)
142
120
  return false unless settings.profiling.advanced.gc_enabled
143
121
 
@@ -146,19 +124,19 @@ module Datadog
146
124
  # that causes a segmentation fault during garbage collection of Ractors
147
125
  # (https://bugs.ruby-lang.org/issues/18464). We don't allow enabling gc profiling on such Rubies.
148
126
  # This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
149
- if RUBY_VERSION.start_with?('3.0.') ||
150
- (RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION < '3.1.4') ||
151
- (RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3')
127
+ if RUBY_VERSION.start_with?("3.0.") ||
128
+ (RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
129
+ (RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
152
130
  Datadog.logger.warn(
153
- "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause "\
154
- 'crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled.'
131
+ "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause " \
132
+ "crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled."
155
133
  )
156
134
  return false
157
- elsif RUBY_VERSION.start_with?('3.')
135
+ elsif RUBY_VERSION.start_with?("3.")
158
136
  Datadog.logger.debug(
159
- 'In all known versions of Ruby 3.x, using Ractors may result in GC profiling unexpectedly ' \
160
- 'stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your ' \
161
- 'application stability or performance. This does not happen if Ractors are not used.'
137
+ "In all known versions of Ruby 3.x, using Ractors may result in GC profiling unexpectedly " \
138
+ "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
139
+ "application stability or performance. This does not happen if Ractors are not used."
162
140
  )
163
141
  end
164
142
 
@@ -182,11 +160,11 @@ module Datadog
182
160
  # Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
183
161
  # https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
184
162
  # fixed on Ruby versions 3.2.3 and 3.3.0.
185
- if RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3'
163
+ if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3"
186
164
  Datadog.logger.warn(
187
- 'Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly '\
188
- 'disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). '\
189
- 'Other Ruby versions do not suffer from this issue.'
165
+ "Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
166
+ "disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). " \
167
+ "Other Ruby versions do not suffer from this issue."
190
168
  )
191
169
  return false
192
170
  end
@@ -196,26 +174,26 @@ module Datadog
196
174
  # that causes a segmentation fault during garbage collection of Ractors
197
175
  # (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
198
176
  # This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
199
- if RUBY_VERSION.start_with?('3.0.') ||
200
- (RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION < '3.1.4') ||
201
- (RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3')
177
+ if RUBY_VERSION.start_with?("3.0.") ||
178
+ (RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
179
+ (RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
202
180
  Datadog.logger.warn(
203
- "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using "\
204
- 'Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). '\
205
- 'This does not happen if Ractors are not used.'
181
+ "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using " \
182
+ "Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). " \
183
+ "This does not happen if Ractors are not used."
206
184
  )
207
185
  # ANNOYANCE - Only with Ractors
208
186
  # On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
209
187
  # garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
210
- elsif RUBY_VERSION.start_with?('3.')
188
+ elsif RUBY_VERSION.start_with?("3.")
211
189
  Datadog.logger.warn(
212
- 'In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly ' \
213
- 'stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your ' \
214
- 'application stability or performance. This does not happen if Ractors are not used.'
190
+ "In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly " \
191
+ "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
192
+ "application stability or performance. This does not happen if Ractors are not used."
215
193
  )
216
194
  end
217
195
 
218
- Datadog.logger.debug('Enabled allocation profiling')
196
+ Datadog.logger.debug("Enabled allocation profiling")
219
197
 
220
198
  true
221
199
  end
@@ -225,33 +203,33 @@ module Datadog
225
203
 
226
204
  return false unless heap_profiling_enabled
227
205
 
228
- if RUBY_VERSION.start_with?('2.') && RUBY_VERSION < '2.7'
206
+ if RUBY_VERSION.start_with?("2.") && RUBY_VERSION < "2.7"
229
207
  Datadog.logger.warn(
230
- 'Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. '\
231
- 'Please upgrade to Ruby >= 2.7 in order to use this feature.'
208
+ "Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. " \
209
+ "Please upgrade to Ruby >= 2.7 in order to use this feature."
232
210
  )
233
211
  return false
234
212
  end
235
213
 
236
- if RUBY_VERSION < '3.1'
214
+ if RUBY_VERSION < "3.1"
237
215
  Datadog.logger.debug(
238
216
  "Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
239
- 'heap profiler is forced to work around to remain accurate. This workaround requires force-setting '\
217
+ "heap profiler is forced to work around to remain accurate. This workaround requires force-setting " \
240
218
  "the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
241
- 'https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be ' \
242
- 'bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling ' \
243
- 'was completely removed (https://bugs.ruby-lang.org/issues/18290).'
219
+ "https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be " \
220
+ "bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling " \
221
+ "was completely removed (https://bugs.ruby-lang.org/issues/18290)."
244
222
  )
245
223
  end
246
224
 
247
225
  unless allocation_profiling_enabled
248
226
  raise ArgumentError,
249
- 'Heap profiling requires allocation profiling to be enabled'
227
+ "Heap profiling requires allocation profiling to be enabled"
250
228
  end
251
229
 
252
230
  Datadog.logger.warn(
253
231
  "Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
254
- 'recommended, and will increase overhead!'
232
+ "recommended, and will increase overhead!"
255
233
  )
256
234
 
257
235
  true
@@ -263,7 +241,7 @@ module Datadog
263
241
  return false unless heap_profiling_enabled && heap_size_profiling_enabled
264
242
 
265
243
  Datadog.logger.warn(
266
- 'Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!'
244
+ "Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
267
245
  )
268
246
 
269
247
  true
@@ -271,12 +249,12 @@ module Datadog
271
249
 
272
250
  private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
273
251
  setting_value = settings.profiling.advanced.no_signals_workaround_enabled
274
- legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?('2.5.')
252
+ legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?("2.5.")
275
253
 
276
254
  unless [true, false, :auto].include?(setting_value)
277
255
  Datadog.logger.error(
278
256
  "Ignoring invalid value for profiling no_signals_workaround_enabled setting: #{setting_value.inspect}. " \
279
- 'Valid options are `true`, `false` or (default) `:auto`.'
257
+ "Valid options are `true`, `false` or (default) `:auto`."
280
258
  )
281
259
 
282
260
  setting_value = :auto
@@ -286,10 +264,10 @@ module Datadog
286
264
  if legacy_ruby_that_should_use_workaround
287
265
  Datadog.logger.warn(
288
266
  'The profiling "no signals" workaround has been disabled via configuration on a legacy Ruby version ' \
289
- '(< 2.6). This is not recommended ' \
290
- 'in production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes ' \
291
- 'in very rare situations. Please report any issues you run into to Datadog support or ' \
292
- 'via <https://github.com/datadog/dd-trace-rb/issues/new>!'
267
+ "(< 2.6). This is not recommended " \
268
+ "in production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes " \
269
+ "in very rare situations. Please report any issues you run into to Datadog support or " \
270
+ "via <https://github.com/datadog/dd-trace-rb/issues/new>!"
293
271
  )
294
272
  else
295
273
  Datadog.logger.warn('Profiling "no signals" workaround disabled via configuration')
@@ -311,30 +289,30 @@ module Datadog
311
289
  # We don't warn users in this situation because "upgrade your Ruby" is not a great warning
312
290
  return true if legacy_ruby_that_should_use_workaround
313
291
 
314
- if Gem.loaded_specs['mysql2'] && incompatible_libmysqlclient_version?(settings)
292
+ if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings)
315
293
  Datadog.logger.warn(
316
294
  'Enabling the profiling "no signals" workaround because an incompatible version of the mysql2 gem is ' \
317
- 'installed. Profiling data will have lower quality. ' \
318
- 'To fix this, upgrade the libmysqlclient in your OS image to version 8.0.0 or above.'
295
+ "installed. Profiling data will have lower quality. " \
296
+ "To fix this, upgrade the libmysqlclient in your OS image to version 8.0.0 or above."
319
297
  )
320
298
  return true
321
299
  end
322
300
 
323
- if Gem.loaded_specs['rugged']
301
+ if Gem.loaded_specs["rugged"]
324
302
  Datadog.logger.warn(
325
303
  'Enabling the profiling "no signals" workaround because the rugged gem is installed. ' \
326
- 'This is needed because some operations on this gem are currently incompatible with the normal working mode ' \
327
- 'of the profiler, as detailed in <https://github.com/datadog/dd-trace-rb/issues/2721>. ' \
328
- 'Profiling data will have lower quality.'
304
+ "This is needed because some operations on this gem are currently incompatible with the normal working mode " \
305
+ "of the profiler, as detailed in <https://github.com/datadog/dd-trace-rb/issues/2721>. " \
306
+ "Profiling data will have lower quality."
329
307
  )
330
308
  return true
331
309
  end
332
310
 
333
- if (defined?(::PhusionPassenger) || Gem.loaded_specs['passenger']) && incompatible_passenger_version?
311
+ if (defined?(::PhusionPassenger) || Gem.loaded_specs["passenger"]) && incompatible_passenger_version?
334
312
  Datadog.logger.warn(
335
313
  'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
336
- 'installed. Profiling data will have lower quality.' \
337
- 'To fix this, upgrade the passenger gem to version 6.0.19 or above.'
314
+ "installed. Profiling data will have lower quality." \
315
+ "To fix this, upgrade the passenger gem to version 6.0.19 or above."
338
316
  )
339
317
  return true
340
318
  end
@@ -355,11 +333,11 @@ module Datadog
355
333
  return true if settings.profiling.advanced.skip_mysql2_check
356
334
 
357
335
  Datadog.logger.debug(
358
- 'Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling'
336
+ "Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling"
359
337
  )
360
338
 
361
339
  begin
362
- require 'mysql2'
340
+ require "mysql2"
363
341
 
364
342
  # The mysql2-aurora gem likes to monkey patch itself in replacement of Mysql2::Client, and uses
365
343
  # `method_missing` to delegate to the original BUT unfortunately does not implement `respond_to_missing?` and
@@ -380,18 +358,18 @@ module Datadog
380
358
  libmysqlclient_version = Gem::Version.new(info[:version])
381
359
 
382
360
  compatible =
383
- libmysqlclient_version >= Gem::Version.new('8.0.0') ||
361
+ libmysqlclient_version >= Gem::Version.new("8.0.0") ||
384
362
  looks_like_mariadb?(info, libmysqlclient_version)
385
363
 
386
364
  Datadog.logger.debug(
387
- "The `mysql2` gem is using #{compatible ? 'a compatible' : 'an incompatible'} version of " \
365
+ "The `mysql2` gem is using #{compatible ? "a compatible" : "an incompatible"} version of " \
388
366
  "the `libmysqlclient` library (#{libmysqlclient_version})"
389
367
  )
390
368
 
391
369
  !compatible
392
370
  rescue StandardError, LoadError => e
393
371
  Datadog.logger.warn(
394
- 'Failed to probe `mysql2` gem information. ' \
372
+ "Failed to probe `mysql2` gem information. " \
395
373
  "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
396
374
  )
397
375
 
@@ -401,10 +379,10 @@ module Datadog
401
379
 
402
380
  # See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
403
381
  private_class_method def self.incompatible_passenger_version?
404
- first_compatible_version = Gem::Version.new('6.0.19')
382
+ first_compatible_version = Gem::Version.new("6.0.19")
405
383
 
406
- if Gem.loaded_specs['passenger']
407
- Gem.loaded_specs['passenger'].version < first_compatible_version
384
+ if Gem.loaded_specs["passenger"]
385
+ Gem.loaded_specs["passenger"].version < first_compatible_version
408
386
  elsif defined?(PhusionPassenger::VERSION_STRING)
409
387
  Gem::Version.new(PhusionPassenger::VERSION_STRING) < first_compatible_version
410
388
  else
@@ -417,7 +395,7 @@ module Datadog
417
395
  overhead_target_percentage
418
396
  else
419
397
  Datadog.logger.error(
420
- 'Ignoring invalid value for profiling overhead_target_percentage setting: ' \
398
+ "Ignoring invalid value for profiling overhead_target_percentage setting: " \
421
399
  "#{overhead_target_percentage.inspect}. Falling back to default value."
422
400
  )
423
401
 
@@ -450,8 +428,8 @@ module Datadog
450
428
  header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
451
429
 
452
430
  !!(header_version &&
453
- libmysqlclient_version < Gem::Version.new('5.0.0') &&
454
- header_version >= Gem::Version.new('10.0.0'))
431
+ libmysqlclient_version < Gem::Version.new("5.0.0") &&
432
+ header_version >= Gem::Version.new("10.0.0"))
455
433
  end
456
434
 
457
435
  private_class_method def self.dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'ext'
4
- require_relative 'tag_builder'
3
+ require_relative "ext"
4
+ require_relative "tag_builder"
5
5
 
6
6
  module Datadog
7
7
  module Profiling
@@ -61,7 +61,7 @@ module Datadog
61
61
  @last_flush_finish_at = finish
62
62
 
63
63
  if duration_below_threshold?(start, finish)
64
- Datadog.logger.debug('Skipped exporting profiling events as profile duration is below minimum')
64
+ Datadog.logger.debug("Skipped exporting profiling events as profile duration is below minimum")
65
65
  return
66
66
  end
67
67