File: stacktrace_builder.rb

package info (click to toggle)
ruby-sentry-ruby-core 5.28.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 672 kB
  • sloc: ruby: 6,118; makefile: 8; sh: 4
file content (100 lines) | stat: -rw-r--r-- 3,011 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# frozen_string_literal: true

module Sentry
  class StacktraceBuilder
    # @return [String]
    attr_reader :project_root

    # @return [Regexp, nil]
    attr_reader :app_dirs_pattern

    # @return [LineCache]
    attr_reader :linecache

    # @return [Integer, nil]
    attr_reader :context_lines

    # @return [Proc, nil]
    attr_reader :backtrace_cleanup_callback

    # @return [Boolean]
    attr_reader :strip_backtrace_load_path

    # @param project_root [String]
    # @param app_dirs_pattern [Regexp, nil]
    # @param linecache [LineCache]
    # @param context_lines [Integer, nil]
    # @param backtrace_cleanup_callback [Proc, nil]
    # @param strip_backtrace_load_path [Boolean]
    # @see Configuration#project_root
    # @see Configuration#app_dirs_pattern
    # @see Configuration#linecache
    # @see Configuration#context_lines
    # @see Configuration#backtrace_cleanup_callback
    # @see Configuration#strip_backtrace_load_path
    def initialize(
      project_root:,
      app_dirs_pattern:,
      linecache:,
      context_lines:,
      backtrace_cleanup_callback: nil,
      strip_backtrace_load_path: true
    )
      @project_root = project_root
      @app_dirs_pattern = app_dirs_pattern
      @linecache = linecache
      @context_lines = context_lines
      @backtrace_cleanup_callback = backtrace_cleanup_callback
      @strip_backtrace_load_path = strip_backtrace_load_path
    end

    # Generates a StacktraceInterface with the given backtrace.
    # You can pass a block to customize/exclude frames:
    #
    # @example
    #   builder.build(backtrace) do |frame|
    #     if frame.module.match?(/a_gem/)
    #       nil
    #     else
    #       frame
    #     end
    #   end
    # @param backtrace [Array<String>]
    # @param frame_callback [Proc]
    # @yieldparam frame [StacktraceInterface::Frame]
    # @return [StacktraceInterface]
    def build(backtrace:, &frame_callback)
      parsed_lines = parse_backtrace_lines(backtrace).select(&:file)

      frames = parsed_lines.reverse.map do |line|
        frame = convert_parsed_line_into_frame(line)
        frame = frame_callback.call(frame) if frame_callback
        frame
      end.compact

      StacktraceInterface.new(frames: frames)
    end

    # Get the code location hash for a single line for where metrics where added.
    # @return [Hash]
    def metrics_code_location(unparsed_line)
      parsed_line = Backtrace::Line.parse(unparsed_line)
      frame = convert_parsed_line_into_frame(parsed_line)
      frame.to_hash.reject { |k, _| %i[project_root in_app].include?(k) }
    end

    private

    def convert_parsed_line_into_frame(line)
      frame = StacktraceInterface::Frame.new(project_root, line, strip_backtrace_load_path)
      frame.set_context(linecache, context_lines) if context_lines
      frame
    end

    def parse_backtrace_lines(backtrace)
      Backtrace.parse(
        backtrace, project_root, app_dirs_pattern, &backtrace_cleanup_callback
      ).lines
    end
  end
end