class StandardError

Constants

DEFAULT_INSPECTION_VALUE_PROC
DEFAULT_INSPECTION_VARS

Attributes

inspection_value_proc[W]
fingerprint[RW]
level[RW]
raven[W]
sentry_event[R]
tags[RW]
tkey[RW]

Public Class Methods

after_logging(name, &block) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 56
def after_logging(name, &block)
  @after_logging_blocks ||= {}
  @after_logging_blocks[name] = block
end
after_logging_blocks() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 60
def after_logging_blocks
  @after_logging_blocks ||= {}
  superclass <= StandardError ? superclass.after_logging_blocks.merge(@after_logging_blocks) : @after_logging_blocks
end
before_logging(name, &block) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 47
def before_logging(name, &block)
  @before_logging_blocks ||= {}
  @before_logging_blocks[name] = block
end
before_logging_blocks() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 51
def before_logging_blocks
  @before_logging_blocks ||= {}
  superclass <= StandardError ? superclass.before_logging_blocks.merge(@before_logging_blocks) : @before_logging_blocks
end
code()
Alias for: status
digest_message(message) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 31
def digest_message(message)
  m = message.to_s.dup
  mat = m.match(/#\<.*0x(?<object_id>\S+)[\s\>]/)
  m = message.gsub(/#{mat[:object_id]}/, 'X'*mat[:object_id].size) if mat
  m = "#{name} #{m}"
  Digest::MD5.hexdigest(m)[0...6]
end
http_status() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 17
def http_status;  500 end
inspection_value_proc() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 22
def inspection_value_proc; @inspection_value_proc ||= superclass.respond_to?(:inspection_value_proc) ? superclass.inspection_value_proc : DEFAULT_INSPECTION_VALUE_PROC end
inspection_value_simple(val) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 23
def inspection_value_simple(val)
  case val
  when Array then val.map{|v| inspection_value_simple(v)}
  when Hash then Hash[val.map{|k,v| [k, inspection_value_simple(v)]}]
  when String, Numeric, TrueClass, FalseClass then val
  else val.class.name
  end
end
inspection_vars() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 21
def inspection_vars; @inspection_vars ||= DEFAULT_INSPECTION_VARS.dup end
intentional?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 19
def intentional?; false end
new(message = nil, cause = $!) click to toggle source
Calls superclass method
# File lib/coaster/core_ext/standard_error.rb, line 68
def initialize(message = nil, cause = $!)
  @fingerprint = Coaster.default_fingerprint.dup
  @tags = {}
  @level = 'error'
  @attributes = HashWithIndifferentAccess.new
  @tkey = nil
  if cause && cause.is_a?(StandardError)
    @fingerprint = cause.fingerprint.dup
    @tags = cause.tags.dup
    @level = cause.level
    @tkey = cause.tkey
    @attributes = cause.attributes.dup
  end

  case message
  when StandardError
    @fingerprint = [message.fingerprint, @fingerprint].flatten.compact.uniq
    @tags = @tags.merge(message.tags || {})
    @level = message.level
    @tkey = message.tkey
    @attributes = @attributes.merge(message.attributes || {})
    msg = message.message
  when Exception
    msg = message.message
  when Hash then
    @coaster = true # coaster 확장을 사용한 에러임을 확인할 수 있음.
    hash = message.with_indifferent_access rescue message
    msg = hash.delete(:m)
    msg = hash.delete(:msg) || msg
    msg = hash.delete(:message) || msg
    hash[:description] ||= hash.delete(:desc) if hash[:desc].present?
    @fingerprint = hash.delete(:fingerprint) || hash.delete(:fingerprints)
    @tags = hash.delete(:tags) || hash.delete(:tag)
    @level = hash.delete(:level) || hash.delete(:severity) || @level
    @tkey = hash.delete(:tkey)
    @attributes.merge!(hash)
    if @attributes[:description] == :translate
      @attributes.delete(:description)
      @attributes[:description] = _translate
    end
    msg = "#{_translate} (#{msg || self.class.name})"
    msg = "#{msg} cause{#{cause.message}}" if cause
  when String then
    msg = message
  when FalseClass, NilClass then
    msg = nil
  else
    msg = message
  end

  @fingerprint = [] unless @fingerprint.is_a?(Array)
  @tags = {} unless @tags.is_a?(Hash)
  msg = "{#{cause.message}}" if msg.blank? && cause
  super(msg)
  @digest_message = self.class.digest_message(msg)
  set_backtrace(message.backtrace) if message.is_a?(Exception)
  @fingerprint << @digest_message
  @fingerprint << digest_backtrace
  @fingerprint.compact!
  self
end
report?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 18
def report?;      true end
status() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 15
def status; 999999 end
Also aliased as: code
title() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 20
def title; _translate('.title') end
user_digests_with!(&block) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 39
def user_digests_with!(&block)
  define_method(:user_digests, &block)
end
user_digests_with_default!() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 43
def user_digests_with_default!
  define_method(:user_digests) { _user_digests }
end

Public Instance Methods

_translate(*args) click to toggle source
Calls superclass method Object::_translate
# File lib/coaster/core_ext/standard_error.rb, line 176
def _translate(*args)
  return description if description.present?
  super
end
_translate_params() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 181
def _translate_params
  attributes
end
_user_digests() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 133
def _user_digests; "#{[digest_message, digest_backtrace].compact.join(' ')}" end
Also aliased as: user_digests
after_logging_blocks() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 137
def after_logging_blocks; self.class.after_logging_blocks end
attr()
Alias for: attributes
attributes() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 140
def attributes
  return @attributes if defined?(@attributes)
  @attributes = HashWithIndifferentAccess.new
  if cause && cause.respond_to?(:attributes) && cause.attributes.is_a?(Hash)
    @attributes = @attributes.merge(cause.attributes)
  end
  @attributes
end
Also aliased as: attr
before_logging_blocks() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 136
def before_logging_blocks; self.class.before_logging_blocks end
capture(options = {}) click to toggle source
# File lib/coaster/core_ext/standard_error/raven.rb, line 39
def capture(options = {})
  return if options.key?(:report) && !options[:report]
  return unless report?
  nt = notes(options)
  Raven.capture_exception(self, level: nt[:level]) do |event|
    event.user.merge!(nt[:user] || {})
    event.tags.merge!(nt[:tags])
    event.extra.merge!(nt[:extra])
    event.fingerprint = raven_fingerprint
  end
rescue => e
  msg = "#{e.class.name}: #{e.message}"
  msg += "\n\t" + e.backtrace.join("\n\t")
  Raven.logger.error(msg)
end
cleaned_backtrace(options = {}) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 310
def cleaned_backtrace(options = {})
  return unless backtrace
  cl = options[:cleaner] || cleaner
  return backtrace unless cl
  bt = cl.clean(backtrace)
  bt = bt[0..2] if intentional?
  bt
end
code() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 152
def code;         attributes[:code] || status end
code=(value) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 153
def code=(value); attributes[:code] = value end
desc()
Alias for: description
description() click to toggle source

description is user friendly message as a attribute, do not use error’s message error message is not user friendly in many cases.

# File lib/coaster/core_ext/standard_error.rb, line 173
def description; attributes[:description] || attributes[:desc] end
Also aliased as: desc
descriptions() click to toggle source

another user friendly messages

# File lib/coaster/core_ext/standard_error.rb, line 195
def descriptions
  return attributes[:descriptions] if attributes[:descriptions]
  attributes[:descriptions] = {}
  attributes[:descriptions]
end
detail() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 155
def detail;       attributes[:detail] end
digest_backtrace() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 132
def digest_backtrace; @digest_backtrace ||= backtrace ? Digest::MD5.hexdigest(cleaned_backtrace.join("\n"))[0...8] : nil end
digest_message() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 131
def digest_message; @digest_message ||= self.class.digest_message(message) end
http_status() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 150
def http_status;         attributes[:http_status] || self.class.http_status end
http_status=(value) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 151
def http_status=(value); attributes[:http_status] = value end
inspection_value_proc() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 225
def inspection_value_proc
  attributes[:inspection_value_proc] || self.class.inspection_value_proc
end
inspection_vars() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 221
def inspection_vars
  (self.class.inspection_vars + (attributes[:inspection_vars] || [])).map(&:to_sym).compact.uniq
end
intentional?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 163
def intentional? # not logging in test
  return attributes[:intentional] if attributes.key?(:intentional)
  return true if it_should_not_happen?
  self.class.intentional?
end
it_might_happen?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 156
def it_might_happen?;      attributes[:it] == :might_happen      end
it_should_not_happen?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 157
def it_should_not_happen?; attributes[:it] == :should_not_happen end
just_logging(options = {})

options

:logger
:cleaner
:fingerprint
:tags
:level
:extra
:report
and others are merged to extra
Alias for: logging
logging(options = {}) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 319
def logging(options = {})
  before_logging_blocks.values.each { |blk| instance_exec(&blk) }

  if !report? || intentional?
    if defined?(Rails)
      return if Rails.env.test?
    else
      return
    end
  end

  logger = options[:logger] || Coaster.logger
  return unless logger

  msg = to_inspection_s(options: options)

  if level && logger.respond_to?(level)
    logger.send(level, msg)
  else
    logger.error(msg)
  end
  msg
ensure
  after_logging_blocks.values.each { |blk| instance_exec(&blk) }
end
Also aliased as: just_logging, just_logging
notes(options = {}) click to toggle source
# File lib/coaster/core_ext/standard_error/raven.rb, line 26
def notes(options = {})
  opts = options ? options.dup : {}
  extra_opts = opts.slice!(:fingerprint, :tags, :level, :extra)
  opts[:extra] = extra_opts.merge(opts[:extra] || {})
  nt = raven.merge(opts)

  nt[:tags] ||= (tags && tags.merge(nt[:tags] || {})) || {}
  nt[:tags] = nt[:tags].merge(environment: Rails.env) if defined?(Rails)
  nt[:level] ||= self.level
  nt[:extra] = attributes.merge(nt[:extra])
  nt
end
obj()
Alias for: object
object() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 168
def object;       attributes[:object] || attributes[:obj] end
Also aliased as: obj
rails_tag() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 298
def rails_tag
  (fingerprint || Coaster.default_fingerprint).flatten.map do |fp|
    if fp == true || fp == :class
      self.class.name
    elsif fp == :default || fp == '{{ default }}'
      nil
    else
      fp
    end
  end.compact
end
raven() click to toggle source
# File lib/coaster/core_ext/standard_error/raven.rb, line 10
def raven
  @raven ||= {}.with_indifferent_access
end
raven_fingerprint() click to toggle source
# File lib/coaster/core_ext/standard_error/raven.rb, line 14
def raven_fingerprint
  (fingerprint || Coaster.default_fingerprint).flatten.map do |fp|
    if fp == true || fp == :class
      self.class.name
    elsif fp == :default
      '{{ default }}'
    else
      fp
    end
  end.flatten
end
report?() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 158
def report?
  return attributes[:report] if attributes.key?(:report)
  return false if it_might_happen?
  self.class.report?
end
root_cause() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 138
def root_cause;   cause.respond_to?(:root_cause) ? cause.root_cause : self end
safe_message() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 130
def safe_message; message || '' end
sentry_event_id() click to toggle source
# File lib/coaster/core_ext/standard_error/sentry.rb, line 58
def sentry_event_id
  @sentry_event&.event_id
end
status() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 135
def status;       self.class.status end
title() click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 154
def title;        attributes[:title] || self.class.title end
to_detail(options: {}, _dh: nil)
Alias for: to_inspection_s
to_hash(_h: {}.with_indifferent_access, _depth: 0) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 201
def to_hash(_h: {}.with_indifferent_access, _depth: 0)
  _h.merge!(attributes)
  _h.merge!(
    type: self.class.name, status: status,
    http_status: http_status, message: message
  )
  if _depth < 4 && cause
    if cause.respond_to?(:to_hash)
      _h[:cause] = cause.to_hash(_depth: _depth + 1)
    else
      _h[:cause_object] = cause
    end
  end
  _h
end
to_inspection_hash(options: {}, _h: {}.with_indifferent_access, _depth: 0) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 229
def to_inspection_hash(options: {}, _h: {}.with_indifferent_access, _depth: 0)
  _h.merge!(
    type: self.class.name, status: status,
    http_status: http_status, message: message,
    instance_variables: {}.with_indifferent_access
  )
  instance_variables.sort.each do |var|
    if inspection_vars.include?(var)
      val = instance_variable_get(var)
      val = inspection_value_proc.call(val) rescue val.to_s
      _h[:instance_variables][var] = val
    elsif var.to_s.start_with?('@__')
      next
    else
      val = instance_variable_get(var)
      _h[:instance_variables][var] = self.class.inspection_value_simple(val)
    end
  end
  if backtrace.present?
    if respond_to?(:cleaned_backtrace)
      if (bt = cleaned_backtrace(options))
        _h[:backtrace] = bt
      else
        _h[:backtrace] = backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first]
      end
    else
      _h[:backtrace] = backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first]
    end
  end
  if cause
    if _depth < 4
      if cause.respond_to?(:to_inspection_hash)
        _h[:cause] = cause.to_inspection_hash(options: options, _depth: _depth + 1)
      else
        cause_h = {
          type: self.class.name, status: status,
          http_status: http_status, message: message,
        }
        cause_h.merge!(backtrace: cause.backtrace[0...ActiveSupport::BacktraceCleaner.minimum_first])
        _h[:cause] = cause_h
      end
    else
      _h[:cause] = 'and more causes...'
    end
  end
  _h
end
to_inspection_s(options: {}, _dh: nil) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 277
def to_inspection_s(options: {}, _dh: nil)
  dh = _dh || to_inspection_hash(options: options, _h: {}.with_indifferent_access, _depth: 0)
  lg = "[#{dh[:type]}] status:#{dh[:status]}"
  lg += "\n  MESSAGE: #{dh[:message]&.gsub(/\n/, "\n    ")}"
  dh[:instance_variables]&.each do |var, val|
    lg += "\n  #{var}: #{val}"
  end
  if (bt = dh[:backtrace] || [])
    lg += "\n  BACKTRACE:\n    "
    lg += bt.join("\n    ")
  end
  if dh[:cause].is_a?(Hash)
    lg += "\n  CAUSE: "
    lg += to_inspection_s(options: options, _dh: dh[:cause]).strip.gsub(/\n/, "\n  ")
  elsif dh[:cause].is_a?(String)
    lg += dh[:cause]
  end
  lg << "\n"
end
Also aliased as: to_detail
to_json(options = {}) click to toggle source
# File lib/coaster/core_ext/standard_error.rb, line 217
def to_json(options = {})
  Oj.dump(to_hash.with_indifferent_access, mode: :compat)
end
user_digests()
Alias for: _user_digests
user_message() click to toggle source

user friendly message, for overid

# File lib/coaster/core_ext/standard_error.rb, line 186
def user_message
  return _translate if description.present? || tkey.present?
  return "#{_translate} (#{user_digests})" unless defined?(@coaster)
  message
rescue => e
  "#{message} (user_message_error - #{e.class.name} #{e.message})"
end