Class: APMErrorHandler

Inherits:
Object
  • Object
show all
Defined in:
app/my_lib/apm_error_handler.rb

Defined Under Namespace

Classes: Reporter

Class Method Summary collapse

Class Method Details

.report(message_or_exception, **attrs) ⇒ Object

Handles error reporting to the Application Performance Monitoring (APM) system.

This class provides methods to report exceptions and custom messages to APM. It supports contextual information and flags indicating whether the error has been handled.

Example usage: APMErrorHandler.report('An error occurred on V5 API') APMErrorHandler.report(exception) APMErrorHandler.report('An error occurred on V5 API', exception: exception) APMErrorHandler.report(exception, context: 123, handled: false)

Parameters:

  • message_or_exception (String, Exception)

    The message or exception to report.

    • Can be a custom message (String) or an exception (Exception).

    • If a message and an exception are both provided (e.g., via attrs), they will both be reported.

  • attrs (Hash)

    Additional attributes to include in the custom context.

    • :context [Hash, nil] Optional contextual information to include.

    • :exception [Exception, nil] Optional exception passed via attributes, overriding the message.

    • :handled [Boolean] Indicates if the error has been handled. Defaults to true.

Raises:

  • (ArgumentError)

    Raised when the first argument is neither a String nor an Exception.



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
101
102
103
104
105
106
107
108
109
110
# File 'app/my_lib/apm_error_handler.rb', line 51

def self.report(message_or_exception, **attrs)
  if Rails.env.development? && !ElasticAPM.running?
    raise message_or_exception if message_or_exception.is_a?(Exception)

    custom_backtrace = if Rails.respond_to?(:backtrace_cleaner)
                         Rails.backtrace_cleaner.clean(caller)
                       else
                         caller
                       end
    raise Reporter.new(message_or_exception, custom_backtrace)
  end

  # Previously we report any errors to Rollbar too while testing ElasticAPM
  # This is no longer necessary, since ElasticAPM looks good now
  # Rollbar.error(message_or_exception, attrs)

  # Extract context and handled status from attrs
  context = attrs.delete(:context) || {}
  handled = attrs.fetch(:handled, true)

  # If an exception is provided in attrs, it will be prioritized for reporting
  exception = attrs.delete(:exception) || attrs.delete(:error) || attrs.delete(:e) || attrs.delete(:ex)

  # Merge any additional attrs into context
  context.merge!(attrs)

  # Initialize labels if not already present
  context[:labels] ||= {}

  # Handle different combinations of message_or_exception and exception
  if exception.is_a?(Exception)
    # When both message and exception are provided, add both to labels
    context[:labels][:message] = message_or_exception if message_or_exception.is_a?(String)
    context[:labels][:exception_message] = exception.message
  elsif message_or_exception.is_a?(Exception)
    # If only an exception is passed as the first argument
    context[:labels][:message] = message_or_exception.message
  elsif message_or_exception.is_a?(String)
    # If a string message is passed without an exception
    context[:labels][:message] = message_or_exception
  else
    raise ArgumentError, 'First argument must be a String or Exception'
  end

  set_default_context_and_labels(context)

  # Report to APM based on the provided data
  if exception.is_a?(Exception)
    ElasticAPM.report(exception, handled: handled)
  elsif message_or_exception.is_a?(Exception)
    ElasticAPM.report(message_or_exception, handled: handled)
  elsif message_or_exception.is_a?(String)
    exception = ::APMErrorHandler::Reporter.new(message_or_exception, caller)
    ElasticAPM.report(exception, handled: handled)
  else
    raise NotImplementedError, 'Invalid combination of arguments'
  end
rescue StandardError => e
  Rollbar.error(e)
end

.report_retriable_event(name) ⇒ Proc

retriable gem use this Proc object to call when an error occurs.

Returns:

  • (Proc)

    A Proc object that reports the retriable event to APM.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/my_lib/apm_error_handler.rb', line 17

def self.report_retriable_event(name)
  Proc.new do |exception, try, elapsed_time, next_interval|
    report_name = "Retriable retrying #{name} attempt #{try}"
     = {
      exception: exception,
      try: try,
      elapsed_time: elapsed_time,
      next_interval: next_interval,
    }
    APMErrorHandler.report(report_name, )
  end
end

.set_default_context_and_labels(context) ⇒ Object

Sets default labels and custom context if not provided

This method ensures that any provided attributes are properly set as labels or context when sending the error or message to APM.

Example usage: set_default_context_and_labels({service: 'API V5', user_id: 123})

Parameters:

  • context (Hash)

    The custom context to enrich with default values if necessary.



122
123
124
125
126
127
128
129
130
131
132
# File 'app/my_lib/apm_error_handler.rb', line 122

def self.set_default_context_and_labels(context)
  custom_labels = context.delete(:labels) || {}

  # Set all labels passed in custom_labels
  custom_labels.each do |key, value|
    ElasticAPM.set_label(key, value)
  end

  # Set the custom context, if any attributes remain
  ElasticAPM.set_custom_context(context) if context.present?
end