Class: NeverForget::Exception

Inherits:
Mingo
  • Object
show all
Extended by:
ActiveSupport::Memoizable
Includes:
Mingo::Timestamps
Defined in:
lib/never_forget/exception.rb

Constant Summary collapse

KEEP =
%w[rack.url_scheme action_dispatch.remote_ip]
EXCLUDE =
%w[HTTP_COOKIE QUERY_STRING SERVER_ADDR]
KNOWN_MODULES =
%w[
  ActiveSupport::Dependencies::Blamable
  JSON::Ext::Generator::GeneratorMethods::Object
  ActiveSupport::Dependencies::Loadable
  PP::ObjectMixin
  Kernel
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env.



45
46
47
# File 'lib/never_forget/exception.rb', line 45

def env
  @env
end

#exceptionObject (readonly)

Returns the value of attribute exception.



45
46
47
# File 'lib/never_forget/exception.rb', line 45

def exception
  @exception
end

Class Method Details

.collectionObject



12
13
14
15
16
17
# File 'lib/never_forget/exception.rb', line 12

def self.collection
  unless defined? @collection
    db.create_collection collection_name, capped: true, size: 1.megabyte
  end
  super
end

.collection_nameObject



11
# File 'lib/never_forget/exception.rb', line 11

def self.collection_name() "NeverForget" end

.create(error, env) ⇒ Object



22
23
24
25
26
27
28
29
# File 'lib/never_forget/exception.rb', line 22

def self.create(error, env)
  if connected?
    record = new.init(error, env)
    yield record if block_given?
    record.save
    record
  end
end

.recentObject



31
32
33
# File 'lib/never_forget/exception.rb', line 31

def self.recent
  find.sort('$natural', :desc).limit(20)
end

Instance Method Details

#clean_unserializable_data(data, stack = []) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/never_forget/exception.rb', line 163

def clean_unserializable_data(data, stack = [])
  return "[possible infinite recursion halted]" if stack.any?{|item| item == data.object_id }

  if data.respond_to?(:to_hash)
    data.to_hash.each_with_object({}) do |(key, value), result|
      result[sanitize_key(key)] = clean_unserializable_data(value, stack + [data.object_id])
    end
  elsif data.respond_to?(:to_ary)
    data.collect do |value|
      clean_unserializable_data(value, stack + [data.object_id])
    end
  else
    data.to_s
  end
end

#discard_env?(key) ⇒ Boolean

Returns:

  • (Boolean)


154
155
156
157
# File 'lib/never_forget/exception.rb', line 154

def discard_env?(key)
  EXCLUDE.include?(key) or
    ( key == 'REMOTE_ADDR' and env['action_dispatch.remote_ip'] )
end

#exclude_paramsObject



123
124
125
# File 'lib/never_forget/exception.rb', line 123

def exclude_params
  Array(env['action_dispatch.parameter_filter']).map(&:to_s)
end

#extract_cookiesObject



137
138
139
140
141
142
143
144
# File 'lib/never_forget/exception.rb', line 137

def extract_cookies
  if cookies = env['rack.request.cookie_hash']
    if options = env['rack.session.options']
      cookies = cookies.except(options[:key])
    end
    clean_unserializable_data cookies
  end
end

#extract_paramsObject



128
129
130
131
132
133
134
135
# File 'lib/never_forget/exception.rb', line 128

def extract_params
  if params = request.params and params.any?
    filtered = params.each_with_object({}) { |(key, value), keep|
      keep[key] = exclude_params.include?(key.to_s) ? '[FILTERED]' : value
    }
    clean_unserializable_data filtered.except('utf8')
  end
end

#extract_sessionObject



116
117
118
119
120
121
# File 'lib/never_forget/exception.rb', line 116

def extract_session
  if session = env['rack.session']
    session_hash = session.to_hash.stringify_keys.except('session_id', '_csrf_token')
    clean_unserializable_data session_hash
  end
end

#get_request?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/never_forget/exception.rb', line 89

def get_request?
  'GET' == request_method
end

#init(ex, env_hash) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/never_forget/exception.rb', line 47

def init(ex, env_hash)
  @exception = unwrap_exception(ex)
  @env = env_hash
  self['name'] = exception.class.name
  self['modules'] = tag_modules
  self['backtrace'] = exception.backtrace.join("\n")
  self['message'] = exception.message

  if env['REQUEST_METHOD']
    self['env'] = sanitized_env
    self['params'] = extract_params
    self['session'] = extract_session
    self['cookies'] = extract_cookies
  else
    self['params'] = clean_unserializable_data(env)
  end
  self
end

#keep_env?(key) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/never_forget/exception.rb', line 150

def keep_env?(key)
  ( key !~ /[a-z]/ or KEEP.include?(key) ) and not discard_env?(key)
end

#remote_ipObject



97
98
99
# File 'lib/never_forget/exception.rb', line 97

def remote_ip
  self['env']['action_dispatch::remote_ip'] || self['env']['REMOTE_ADDR']
end

#requestObject



66
67
68
# File 'lib/never_forget/exception.rb', line 66

def request
  @request ||= Rack::Request.new(env)
end

#request?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/never_forget/exception.rb', line 70

def request?
  self['env'].present?
end

#request_methodObject



85
86
87
# File 'lib/never_forget/exception.rb', line 85

def request_method
  self['env']['REQUEST_METHOD']
end

#request_urlObject



74
75
76
77
78
79
80
81
82
83
# File 'lib/never_forget/exception.rb', line 74

def request_url
  env = self['env']
  scheme = env['rack::url_scheme']
  host, port = env['HTTP_HOST'], env['SERVER_PORT'].to_i
  host += ":#{port}" if 'http' == scheme && port != 80 or 'https' == scheme && port != 443

  url = scheme + '://' + File.join(host, env['SCRIPT_NAME'], env['PATH_INFO'])
  url << '?' << Rack::Utils::build_nested_query(self['params']) if get_request? and self['params'].present?
  url
end

#sanitize_key(key) ⇒ Object



159
160
161
# File 'lib/never_forget/exception.rb', line 159

def sanitize_key(key)
  key.to_s.gsub('.', '::').sub(/^\$/, 'DOLLAR::')
end

#sanitized_envObject



146
147
148
# File 'lib/never_forget/exception.rb', line 146

def sanitized_env
  clean_unserializable_data env.select { |key, _| keep_env? key }
end

#tag_modulesObject



101
102
103
# File 'lib/never_forget/exception.rb', line 101

def tag_modules
  Array(exception.singleton_class.included_modules).map(&:to_s) - KNOWN_MODULES
end

#unwrap_exception(exception) ⇒ Object



106
107
108
109
110
111
112
113
114
# File 'lib/never_forget/exception.rb', line 106

def unwrap_exception(exception)
  if exception.respond_to?(:original_exception)
    exception.original_exception
  elsif exception.respond_to?(:continued_exception)
    exception.continued_exception
  else
    exception
  end
end

#xhr?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/never_forget/exception.rb', line 93

def xhr?
  self['env']['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
end