Module: Bugsnag::Stacktrace

Defined in:
lib/bugsnag/stacktrace.rb

Constant Summary collapse

BACKTRACE_LINE_REGEX =

e.g. “org/jruby/RubyKernel.java:1264:in ‘catch’”

/^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/
JAVA_BACKTRACE_REGEX =

e.g. “org.jruby.Ruby.runScript(Ruby.java:807)”

/^(.*)\((.*)(?::([0-9]+))?\)$/

Class Method Summary collapse

Class Method Details

.process(backtrace, configuration) ⇒ Array

Process a backtrace and the configuration into a parsed stacktrace.

Parameters:

  • backtrace (Array, nil)

    If nil, ‘caller’ will be used instead

  • configuration (Configuration)

Returns:

  • (Array)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/bugsnag/stacktrace.rb', line 17

def self.process(backtrace, configuration)
  code_extractor = CodeExtractor.new(configuration)

  backtrace = caller if !backtrace || backtrace.empty?

  processed_backtrace = backtrace.map do |trace|
    # Parse the stacktrace line
    if trace.match(BACKTRACE_LINE_REGEX)
      file, line_str, method = [$1, $2, $3]
    elsif trace.match(JAVA_BACKTRACE_REGEX)
      method, file, line_str = [$1, $2, $3]
    end

    next if file.nil?

    # Expand relative paths
    file = File.realpath(file) rescue file

    # Generate the stacktrace line hash
    trace_hash = { lineNumber: line_str.to_i }

    # Save a copy of the file path as we're about to modify it but need the
    # raw version when extracting code (otherwise we can't open the file)
    raw_file_path = file.dup

    # Clean up the file path in the stacktrace
    if defined?(configuration.project_root) && configuration.project_root.to_s != ''
      trace_hash[:inProject] = true if file.start_with?(configuration.project_root.to_s)
      file.sub!(/#{configuration.project_root}\//, "")
      trace_hash.delete(:inProject) if vendor_path?(configuration, file)
    end

    # Strip common gem path prefixes
    if defined?(Gem)
      file = Gem.path.inject(file) {|line, path| line.sub(/#{path}\//, "") }
    end

    trace_hash[:file] = file

    # Add a method if we have it
    trace_hash[:method] = method if method && (method =~ /^__bind/).nil?

    # If we're going to send code then record the raw file path and the
    # trace_hash, so we can extract from it later
    code_extractor.add_file(raw_file_path, trace_hash) if configuration.send_code

    trace_hash
  end.compact

  code_extractor.extract! if configuration.send_code

  processed_backtrace
end