Class: ExisRay::Reporter

Inherits:
ActiveSupport::CurrentAttributes
  • Object
show all
Defined in:
lib/exis_ray/reporter.rb

Overview

Clase base híbrida para reporte de errores. Soporta integración moderna (Sentry SDK) y legacy (Raven/Session).

Class Method Summary collapse

Class Method Details

.add_context(attrs) ⇒ Object



58
59
60
61
62
# File 'lib/exis_ray/reporter.rb', line 58

def self.add_context(attrs)
  return if attrs.blank?

  self.contexts = (contexts || {}).merge(attrs.as_json)
end

.add_fingerprint(value) ⇒ Object

— Builders de Datos —



52
53
54
55
56
# File 'lib/exis_ray/reporter.rb', line 52

def self.add_fingerprint(value)
  current_values = fingerprint || []
  current_values << value
  self.fingerprint = current_values.flatten.compact.uniq
end

.add_tags(attrs) ⇒ Object



64
65
66
67
68
# File 'lib/exis_ray/reporter.rb', line 64

def self.add_tags(attrs)
  return if attrs.blank?

  self.tags = (tags || {}).merge(attrs.as_json)
end

.build_custom_contextObject



70
71
72
# File 'lib/exis_ray/reporter.rb', line 70

def self.build_custom_context
  # Hook para subclases
end

.clean_legacy_session!Object

— Lógica Legacy —



75
76
77
78
79
# File 'lib/exis_ray/reporter.rb', line 75

def self.clean_legacy_session!
  return unless defined?(::Session) && ::Session.respond_to?(:clean!)

  ::Session.clean!
end

.exception(excep, context: {}, tags: {}, fingerprint: [], transaction_name: nil) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/exis_ray/reporter.rb', line 33

def self.exception(excep, context: {}, tags: {}, fingerprint: [], transaction_name: nil)
  prepare_scope(context, tags, fingerprint, transaction_name)
  add_tags(exception: excep.class.to_s)

  Rails.logger.error(excep.full_message) unless Rails.env.production?
rescue StandardError
ensure
  begin
    if report_to_new_sentry?
      exception_to_new_sentry(excep)
    else
      exception_to_old_sentry(excep)
    end
  rescue StandardError
  end
end

.exception_to_new_sentry(exception) ⇒ Object



127
128
129
# File 'lib/exis_ray/reporter.rb', line 127

def self.exception_to_new_sentry(exception)
  send_to_new_sentry { Sentry.capture_exception(exception, level: "error", fingerprint: fingerprint) }
end

.exception_to_old_sentry(exception) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/exis_ray/reporter.rb', line 107

def self.exception_to_old_sentry(exception)
  session_tag!
  session_context!

  return unless defined?(Sentry)

  Sentry.populate_context(contexts) if contexts.present?
  Sentry.notify(exception)
end

.report(message, context: {}, tags: {}, fingerprint: [], transaction_name: nil) ⇒ Object

— Métodos Públicos —



24
25
26
27
28
29
30
31
# File 'lib/exis_ray/reporter.rb', line 24

def self.report(message, context: {}, tags: {}, fingerprint: [], transaction_name: nil)
  prepare_scope(context, tags, fingerprint, transaction_name)
  if report_to_new_sentry?
    report_to_new_sentry(message)
  else
    report_to_old_sentry(message)
  end
end

.report_to_new_sentry(message) ⇒ Object



123
124
125
# File 'lib/exis_ray/reporter.rb', line 123

def self.report_to_new_sentry(message)
  send_to_new_sentry { Sentry.capture_message(message, fingerprint: fingerprint) }
end

.report_to_new_sentry?Boolean

— Lógica Moderna —

Returns:

  • (Boolean)


119
120
121
# File 'lib/exis_ray/reporter.rb', line 119

def self.report_to_new_sentry?
  defined?(::NEW_SENTRY) && ::NEW_SENTRY
end

.report_to_old_sentry(message) ⇒ Object



101
102
103
104
105
# File 'lib/exis_ray/reporter.rb', line 101

def self.report_to_old_sentry(message)
  session_tag!
  session_context!
  Sentry.send_event(message) if defined?(Sentry)
end

.send_to_new_sentryObject



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/exis_ray/reporter.rb', line 131

def self.send_to_new_sentry
  return unless defined?(Sentry)

  Sentry.with_scope do |scope|
    scope.set_transaction_name(transaction_name) if transaction_name.present?
    if contexts.present?
      contexts.each do |key, value|
        val = value.is_a?(Hash) ? value : { value: value }
        scope.set_context(key, val)
      end
    end
    scope.set_tags(tags) if tags.present?
    yield(scope)
  end
end

.sentry_isp_context(current) ⇒ Hash

Hook para que la app host controle qué datos del ISP se envían a Sentry. Por defecto solo se envía el ID.

Parameters:

  • current (Class)

    La clase Current resuelta.

Returns:

  • (Hash)


205
206
207
# File 'lib/exis_ray/reporter.rb', line 205

def self.sentry_isp_context(current)
  { id: current.isp_id }
end

.sentry_user_context(current) ⇒ Hash

Hook para que la app host controle qué datos del usuario se envían a Sentry. Por defecto solo se envía el ID para evitar exponer datos sensibles (password_digest, tokens, etc.).

Examples:

Sobreescribir en la subclase del Reporter de la app

def self.sentry_user_context(current)
  { id: current.user_id, email: current.user&.email }
end

Parameters:

  • current (Class)

    La clase Current resuelta.

Returns:

  • (Hash)


196
197
198
# File 'lib/exis_ray/reporter.rb', line 196

def self.sentry_user_context(current)
  { id: current.user_id }
end

.session_context!Object



94
95
96
97
98
99
# File 'lib/exis_ray/reporter.rb', line 94

def self.session_context!
  return unless contexts.present? && defined?(::Session)

  ::Session.extra_context ||= {}
  ::Session.extra_context.merge!(contexts)
end

.session_tag!Object



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/exis_ray/reporter.rb', line 81

def self.session_tag!
  return unless defined?(::Session)

  ::Session.tags_context ||= {}

  if fingerprint.present?
    str_fingerprint = fingerprint.flatten.join(",")
    ::Session.tags_context.merge!(fingerprint: str_fingerprint)
  end
  ::Session.tags_context.merge!(transaction_name: transaction_name) if transaction_name.present?
  ::Session.tags_context.merge!(tags) if tags.present?
end