Class: Radar::Reporter::HoptoadReporter

Inherits:
Object
  • Object
show all
Defined in:
lib/radar/reporter/hoptoad_reporter.rb

Overview

Reports exceptions to the Hoptoad server (http://hoptoadapp.com). Enabling this in your Radar application is easy:

app.reporters.use :hoptoad, :api_key => "hoptoad-api-key"

The API key is your project's API key which can be found on the Hoptoad website. There are many additional options which can be set, but the most useful are probably project_root and environment_name. These will be auto-detected in a Rails application but for all others, its helpful to set them:

app.reporters.use :hoptoad do |r|
  r.api_key          = "api-key"
  r.project_root     = File.expand_path("../../", __FILE__)
  r.environment_name = "development"
end

Constant Summary collapse

API_VERSION =
"2.0"
NOTICES_URL =
"/notifier_api/v2/notices/"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = nil) ⇒ HoptoadReporter

Returns a new instance of HoptoadReporter.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 56

def initialize(opts=nil)
  (opts || {}).each do |k,v|
    send("#{k}=", v)
  end

  @project_root      ||= defined?(Rails) ? Rails.root.to_s : '/not/set'
  @environment_name  ||= defined?(Rails) ? Rails.env.to_s  : 'radar'

  @host              ||= 'hoptoadapp.com'
  @headers           ||= { 'Content-type' => 'text/xml', 'Accept' => 'text/xml, application/xml' }
  @secure            ||= false
  @http_open_timeout ||= 2
  @http_read_timeout ||= 5

  @notifier_name     ||= "Radar"
  @notifier_version  ||= Radar::VERSION
  @notifier_url      ||= "http://radargem.com"
end

Instance Attribute Details

#api_keyObject

Options which should be set:



33
34
35
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 33

def api_key
  @api_key
end

#environment_nameObject

Returns the value of attribute environment_name.



35
36
37
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 35

def environment_name
  @environment_name
end

#headersObject

Returns the value of attribute headers.



40
41
42
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 40

def headers
  @headers
end

#hostObject

The rest can probably be left alone: HTTP settings



39
40
41
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 39

def host
  @host
end

#http_open_timeoutObject

Returns the value of attribute http_open_timeout.



42
43
44
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 42

def http_open_timeout
  @http_open_timeout
end

#http_read_timeoutObject

Returns the value of attribute http_read_timeout.



43
44
45
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 43

def http_read_timeout
  @http_read_timeout
end

#notifier_nameObject

Notifier information. This defaults to Radar information.



52
53
54
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 52

def notifier_name
  @notifier_name
end

#notifier_urlObject

Returns the value of attribute notifier_url.



54
55
56
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 54

def notifier_url
  @notifier_url
end

#notifier_versionObject

Returns the value of attribute notifier_version.



53
54
55
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 53

def notifier_version
  @notifier_version
end

#project_rootObject

Returns the value of attribute project_root.



34
35
36
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 34

def project_root
  @project_root
end

#proxy_hostObject

Proxy settings



46
47
48
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 46

def proxy_host
  @proxy_host
end

#proxy_passObject

Returns the value of attribute proxy_pass.



49
50
51
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 49

def proxy_pass
  @proxy_pass
end

#proxy_portObject

Returns the value of attribute proxy_port.



47
48
49
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 47

def proxy_port
  @proxy_port
end

#proxy_userObject

Returns the value of attribute proxy_user.



48
49
50
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 48

def proxy_user
  @proxy_user
end

#secureObject

Returns the value of attribute secure.



41
42
43
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 41

def secure
  @secure
end

Instance Method Details

#event_xml(event) ⇒ Object

Converts an event to the properly formatted XML for transmission to Hoptoad.



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
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 97

def event_xml(event)
  request_data = request_info(event)

  builder = Builder::XmlMarkup.new
  builder.instruct!
  xml = builder.notice(:version => API_VERSION) do |notice|
    notice.tag!("api-key", api_key)

    notice.notifier do |notifier|
      notifier.name(notifier_name)
      notifier.version(notifier_version)
      notifier.url(notifier_url)
    end

    notice.error do |error|
      error.tag!("class", event.exception.class.to_s)
      error.message(event.exception.message)
      error.backtrace do |backtrace|
        event.backtrace.each do |entry|
          backtrace.line(:number => entry.line, :file => entry.file, :method => entry.method)
        end
      end
    end

    if !request_data.empty?
      notice.request do |request|
        request.url(request_data[:url])
        request.component(request_data[:controller])
        request.action(request_data[:action])

        if !request_data[:parameters].empty?
          request.params do |params|
            xml_vars_for_hash(params, request_data[:parameters])
          end
        end

        if !request_data[:session].empty?
          request.session do |session|
            xml_vars_for_hash(session, request_data[:session])
          end
        end

        if !request_data[:cgi_data].empty?
          request.tag!("cgi-data") do |cgi|
            xml_vars_for_hash(cgi, request_data[:cgi_data])
          end
        end
      end
    end

    notice.tag!("server-environment") do |env|
      env.tag!("project-root", project_root)
      env.tag!("environment-name", environment_name)
    end
  end

  xml.to_s
end

#report(event) ⇒ Object

Raises:

  • (ArgumentError)


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 75

def report(event)
  raise ArgumentError.new("`api_key` is required.") if !api_key

  http = Net::HTTP.Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).new(url.host, url.port)
  http.read_timeout = http_read_timeout
  http.open_timeout = http_open_timeout
  http.use_ssl      = secure

  response = begin
               http.post(url.path, event_xml(event), headers)
             rescue TimeoutError => e
               event.application.logger.error("#{self.class}: POST timeout.")
               nil
             end

  if !response.is_a?(Net::HTTPSuccess)
    event.application.logger.error("#{self.class}: Failed to send: #{response.body}")
  end
end

#request_info(event) ⇒ Object

Returns information about the request based on the event, such as URL, controller, action, parameters, etc.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 167

def request_info(event)
  return @_request_info if @_request_info

  # Use the hash of the event so that if any filters deleted data, it is properly
  # removed.
  hash = event.to_hash.dup
  hash[:request] ||= {}
  hash[:request][:rack_env] ||= {}

  @_request_info = {}

  if hash[:request]
    @_request_info[:url]        = hash[:request][:url]
    @_request_info[:parameters] = hash[:request][:rack_env]['action_dispatch.request.parameters'] ||
      hash[:request][:parameters] ||
      {}
    @_request_info[:controller] = @_request_info[:parameters]['controller']
    @_request_info[:action]     = @_request_info[:parameters]['action']
    @_request_info[:cgi_data]   = hash[:request][:rack_env] || hash[:request][:headers] || {}
    @_request_info[:session]    = hash[:request][:rack_env]['rack.session'] || {}
  end

  @_request_info
end

#urlObject

Returns a URI object pointed to the proper endpoint for the Hoptoad API.



158
159
160
161
162
163
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 158

def url
  protocol = secure ? 'https' : 'http'
  port     = secure ? 443 : 80

  URI.parse("#{protocol}://#{host}:#{port}").merge(NOTICES_URL)
end

#xml_vars_for_hash(builder, hash) ⇒ Object

Turns a hash into the proper XML vars



193
194
195
196
197
198
199
200
201
# File 'lib/radar/reporter/hoptoad_reporter.rb', line 193

def xml_vars_for_hash(builder, hash)
  hash.each do |k,v|
    if v.is_a?(Hash)
      builder.var(:key => k.to_s) { |b| xml_vars_for_hash(b, v) }
    else
      builder.var(v.to_s, :key => k.to_s)
    end
  end
end