class ElasticAPM::StacktraceBuilder

@api private

Constants

JAVA_FORMAT
JRUBY_ORG_REGEX
RUBY_FORMAT
RUBY_VERS_REGEX

Attributes

config[R]

Public Class Methods

new(config) click to toggle source
# File lib/elastic_apm/stacktrace_builder.rb, line 14
def initialize(config)
  @config = config
  @cache = Util::LruCache.new(2048, &method(:build_frame))
end

Public Instance Methods

build(backtrace, type:) click to toggle source
# File lib/elastic_apm/stacktrace_builder.rb, line 21
def build(backtrace, type:)
  Stacktrace.new.tap do |s|
    s.frames = backtrace[0...config.stack_trace_limit].map do |line|
      @cache[[line, type]]
    end
  end
end

Private Instance Methods

build_frame(cache, keys) click to toggle source

rubocop:disable Metrics/AbcSize, Metrics/MethodLength

# File lib/elastic_apm/stacktrace_builder.rb, line 32
def build_frame(cache, keys)
  line, type = keys
  abs_path, lineno, function, _module_name = parse_line(line)

  frame = Stacktrace::Frame.new
  frame.abs_path = abs_path
  frame.filename = strip_load_path(abs_path)
  frame.function = function
  frame.lineno = lineno.to_i
  frame.library_frame = library_frame?(config, abs_path)

  line_count =
    context_lines_for(config, type, library_frame: frame.library_frame)
  frame.build_context line_count

  cache[[line, type]] = frame
end
context_lines_for(config, type, library_frame:) click to toggle source
# File lib/elastic_apm/stacktrace_builder.rb, line 92
def context_lines_for(config, type, library_frame:)
  key = "source_lines_#{type}_#{library_frame ? 'library' : 'app'}_frames"
  config.send(key.to_sym)
end
library_frame?(config, abs_path) click to toggle source
# File lib/elastic_apm/stacktrace_builder.rb, line 66
def library_frame?(config, abs_path)
  return false unless abs_path

  if abs_path.start_with?(config.root_path)
    return true if abs_path.start_with?(config.root_path + '/vendor')
    return false
  end

  return true if abs_path.match(RUBY_VERS_REGEX)
  return true if abs_path.match(JRUBY_ORG_REGEX)

  false
end
parse_line(line) click to toggle source

rubocop:enable Metrics/AbcSize, Metrics/MethodLength

# File lib/elastic_apm/stacktrace_builder.rb, line 51
def parse_line(line)
  ruby_match = line.match(RUBY_FORMAT)

  if ruby_match
    _, file, number, method = ruby_match.to_a
    file.sub!(/\.class$/, '.rb')
    module_name = nil
  else
    java_match = line.match(JAVA_FORMAT)
    _, module_name, method, file, number = java_match.to_a
  end

  [file, number, method, module_name]
end
strip_load_path(path) click to toggle source
# File lib/elastic_apm/stacktrace_builder.rb, line 80
def strip_load_path(path)
  return nil if path.nil?

  prefix =
    $LOAD_PATH
    .map(&:to_s)
    .select { |s| path.start_with?(s) }
    .max_by(&:length)

  prefix ? path[prefix.chomp(File::SEPARATOR).length + 1..-1] : path
end