Module: PostHog::ExceptionCapture Private

Defined in:
lib/posthog/exception_capture.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Builds PostHog exception payloads from Ruby exception objects.

Constant Summary collapse

RUBY_INPUT_FORMAT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

/
  ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
  (\d+)
  (?: :in\s('|`)(?:([\w:]+)\#)?([^']+)')?$
/x

Class Method Summary collapse

Class Method Details

.add_context_lines(frame, file_path, lineno, context_size = 5) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Parameters:

  • frame (Hash)
  • file_path (String)
  • lineno (Integer)
  • context_size (Integer) (defaults to: 5)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/posthog/exception_capture.rb', line 102

def self.add_context_lines(frame, file_path, lineno, context_size = 5)
  lines = File.readlines(file_path)
  return if lines.empty?

  return unless lineno.positive? && lineno <= lines.length

  pre_context_start = [lineno - context_size, 1].max
  post_context_end = [lineno + context_size, lines.length].min

  frame['context_line'] = lines[lineno - 1].chomp

  frame['pre_context'] = lines[(pre_context_start - 1)...(lineno - 1)].map(&:chomp) if pre_context_start < lineno

  frame['post_context'] = lines[lineno...(post_context_end)].map(&:chomp) if post_context_end > lineno
rescue StandardError
  # Silently ignore file read errors
end

.build_parsed_exception(value) ⇒ Hash?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Parsed exception payload, or nil when the input is unsupported.

Parameters:

  • value (Exception, String, Object)

    Exception input to parse.

Returns:

  • (Hash, nil)

    Parsed exception payload, or nil when the input is unsupported.



26
27
28
29
30
31
# File 'lib/posthog/exception_capture.rb', line 26

def self.build_parsed_exception(value)
  title, message, backtrace = coerce_exception_input(value)
  return nil if title.nil?

  build_single_exception_from_data(title, message, backtrace)
end

.build_single_exception_from_data(title, message, backtrace) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • title (String)
  • message (String, nil)
  • backtrace (Array<String>, nil)

Returns:

  • (Hash)


37
38
39
40
41
42
43
44
45
46
47
# File 'lib/posthog/exception_capture.rb', line 37

def self.build_single_exception_from_data(title, message, backtrace)
  {
    'type' => title,
    'value' => message || '',
    'mechanism' => {
      'type' => 'generic',
      'handled' => true
    },
    'stacktrace' => build_stacktrace(backtrace)
  }
end

.build_stacktrace(backtrace) ⇒ Hash?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • backtrace (Array<String>, nil)

Returns:

  • (Hash, nil)


51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/posthog/exception_capture.rb', line 51

def self.build_stacktrace(backtrace)
  return nil unless backtrace && !backtrace.empty?

  frames = backtrace.first(50).map do |line|
    parse_backtrace_line(line)
  end.compact.reverse

  {
    'type' => 'raw',
    'frames' => frames
  }
end

.coerce_exception_input(value) ⇒ Array

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Three-item array of title, message, and backtrace.

Parameters:

  • value (Exception, String, Object)

Returns:

  • (Array)

    Three-item array of title, message, and backtrace.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/posthog/exception_capture.rb', line 122

def self.coerce_exception_input(value)
  if value.is_a?(String)
    title = 'Error'
    message = value
    backtrace = nil
  elsif value.respond_to?(:backtrace) && value.respond_to?(:message)
    title = value.class.to_s
    message = value.message || ''
    backtrace = value.backtrace
  else
    return [nil, nil, nil]
  end

  [title, message, backtrace]
end

.gem_path?(path) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • path (String)

Returns:

  • (Boolean)


90
91
92
93
94
95
# File 'lib/posthog/exception_capture.rb', line 90

def self.gem_path?(path)
  path.include?('/gems/') ||
    path.include?('/ruby/') ||
    path.include?('/.rbenv/') ||
    path.include?('/.rvm/')
end

.parse_backtrace_line(line) ⇒ Hash?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • line (String)

Returns:

  • (Hash, nil)


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/posthog/exception_capture.rb', line 66

def self.parse_backtrace_line(line)
  match = line.match(RUBY_INPUT_FORMAT)
  return nil unless match

  file = match[1]
  lineno = match[2].to_i
  method_name = match[5]

  frame = {
    'filename' => File.basename(file),
    'abs_path' => file,
    'lineno' => lineno,
    'function' => method_name,
    'in_app' => !gem_path?(file),
    'platform' => 'ruby'
  }

  add_context_lines(frame, file, lineno) if frame['in_app'] && File.exist?(file)

  frame
end