module Datadog::Profiling::Ext::CPU

Monkey patches Ruby's `Thread` with our `Ext::CThread` to enable CPU-time profiling

Constants

ROLLBAR_INCOMPATIBLE_VERSIONS

We cannot apply our CPU extension if a broken rollbar is around because that can cause customer apps to fail with a SystemStackError: stack level too deep.

This occurs whenever our extensions to Thread are applied BEFORE rollbar applies its own. This happens because a loop forms: our extension tries to call Thread#initialize, but it's intercepted by rollbar, which then tries to call the original Thread#initialize as well, but instead alls our extension, leading to stack exhaustion.

See github.com/rollbar/rollbar-gem/pull/1018 for more details on the issue

Public Class Methods

apply!() click to toggle source
# File lib/ddtrace/profiling/ext/cpu.rb, line 22
def self.apply!
  return false unless supported?

  # Applying CThread to Thread will ensure any new threads
  # will provide a thread/clock ID for CPU timing.
  require 'ddtrace/profiling/ext/cthread'
  ::Thread.prepend(Profiling::Ext::CThread)
  ::Thread.singleton_class.prepend(Datadog::Profiling::Ext::WrapThreadStartFork)
end
supported?() click to toggle source
# File lib/ddtrace/profiling/ext/cpu.rb, line 18
def self.supported?
  unsupported_reason.nil?
end
unsupported_reason() click to toggle source
# File lib/ddtrace/profiling/ext/cpu.rb, line 32
def self.unsupported_reason
  # NOTE: Only the first matching reason is returned, so try to keep a nice order on reasons -- e.g. tell users
  # first that they can't use this on macOS before telling them that they have the wrong ffi version

  if RUBY_ENGINE == 'jruby'
    'JRuby is not supported'
  elsif RUBY_PLATFORM.include?('darwin')
    'Feature requires Linux; macOS is not supported'
  elsif RUBY_PLATFORM =~ /(mswin|mingw)/
    'Feature requires Linux; Windows is not supported'
  elsif !RUBY_PLATFORM.include?('linux')
    "Feature requires Linux; #{RUBY_PLATFORM} is not supported"
  elsif Gem::Specification.find_all_by_name('rollbar', ROLLBAR_INCOMPATIBLE_VERSIONS).any?
    'You have an incompatible rollbar gem version installed; ensure that you have rollbar >= 3.1.2 by ' \
    "adding `gem 'rollbar', '>= 3.1.2'` to your Gemfile or gems.rb file. " \
    'See https://github.com/rollbar/rollbar-gem/pull/1018 for details'
  elsif Gem::Specification.find_all_by_name('logging').any? && logging_inherit_context_enabled?
    'The `logging` gem is installed and its thread inherit context feature is enabled. ' \
    "Please add LOGGING_INHERIT_CONTEXT=false to your application's environment variables to disable the " \
    'conflicting `logging` gem feature. ' \
    'See https://github.com/TwP/logging/pull/230 for details'
  end
end

Private Class Methods

logging_inherit_context_enabled?() click to toggle source
# File lib/ddtrace/profiling/ext/cpu.rb, line 56
                     def self.logging_inherit_context_enabled?
  # The logging gem provides a mechanism to disable the conflicting behavior, see
  # https://github.com/TwP/logging/blob/ae9872d093833b2a5a34cbe1faa4e895a81f6845/lib/logging/diagnostic_context.rb#L418
  # Here we check if the behavior is enabled
  inherit_context_configuration = ENV['LOGGING_INHERIT_CONTEXT']

  inherit_context_configuration.nil? || !%w[false no 0].include?(inherit_context_configuration.downcase)
end