notice.rb
3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
require 'recurse'
class Notice
MESSAGE_LENGTH_LIMIT = 1000
include Mongoid::Document
include Mongoid::Timestamps
field :message
field :server_environment, type: Hash
field :request, type: Hash
field :notifier, type: Hash
field :user_attributes, type: Hash
field :framework
field :error_class
delegate :lines, to: :backtrace, prefix: true
delegate :problem, to: :err
belongs_to :app
belongs_to :err
belongs_to :backtrace, index: true
index(created_at: 1)
index(err_id: 1, created_at: 1, _id: 1)
before_save :sanitize
before_destroy :problem_recache
validates :backtrace_id, :server_environment, :notifier, presence: true
scope :ordered, -> { order_by(:created_at.asc) }
scope :reverse_ordered, -> { order_by(:created_at.desc) }
scope :for_errs, lambda { |errs|
where(:err_id.in => errs.all.map(&:id))
}
# Overwrite the default setter to make sure the message length is no longer
# than the limit we impose
def message=(m)
super(m.is_a?(String) ? m[0, MESSAGE_LENGTH_LIMIT] : m)
end
def user_agent
agent_string = env_vars['HTTP_USER_AGENT']
agent_string.blank? ? nil : UserAgent.parse(agent_string)
end
def user_agent_string
if user_agent.nil? || user_agent.none?
"N/A"
else
"#{user_agent.browser} #{user_agent.version} (#{user_agent.os})"
end
end
def environment_name
n = server_environment['server-environment'] || server_environment['environment-name']
n.blank? ? 'development' : n
end
def component
request['component']
end
def action
request['action']
end
def where
where = component.to_s.dup
where << "##{action}" if action.present?
where
end
def request
super || {}
end
def url
request['url']
end
def host
uri = url && URI.parse(url)
uri && uri.host || "N/A"
rescue URI::InvalidURIError
"N/A"
end
def to_curl
return "N/A" if url.blank?
headers = %w(Accept Accept-Encoding Accept-Language Cookie Referer User-Agent).each_with_object([]) do |name, h|
if (value = env_vars["HTTP_#{name.underscore.upcase}"])
h << "-H '#{name}: #{value}'"
end
end
"curl -X #{env_vars['REQUEST_METHOD'] || 'GET'} #{headers.join(' ')} #{url}"
end
def env_vars
vars = request['cgi-data']
vars.is_a?(Hash) ? vars : {}
end
def params
request['params'] || {}
end
def session
request['session'] || {}
end
##
# TODO: Move on decorator maybe
#
def project_root
server_environment['project-root'] || '' if server_environment
end
def app_version
server_environment['app-version'] || '' if server_environment
end
# filter memory addresses out of object strings
# example: "#<Object:0x007fa2b33d9458>" becomes "#<Object>"
def filtered_message
message.gsub(/(#<.+?):[0-9a-f]x[0-9a-f]+(>)/, '\1\2')
end
protected
def problem_recache
problem.uncache_notice(self)
end
def sanitize
[:server_environment, :request, :notifier].each do |h|
send("#{h}=", sanitize_hash(send(h)))
end
end
def sanitize_hash(hash)
hash.recurse do |recurse_hash|
recurse_hash.inject({}) do |h, (k, v)|
if k.is_a?(String)
h[k.gsub(/\./, '.').gsub(/^\$/, '$')] = v
else
h[k] = v
end
h
end
end
end
end