airbrake_user_attributes 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/Gemfile +5 -0
- data/README.md +11 -0
- data/Rakefile +16 -0
- data/airbrake_user_attributes.gemspec +27 -0
- data/lib/airbrake_overrides/notice.rb +85 -0
- data/lib/airbrake_overrides/rails/controller_methods.rb +31 -0
- data/lib/airbrake_user_attributes/version.rb +3 -0
- data/lib/airbrake_user_attributes.rb +3 -0
- data/test/airbrake_2_2.xsd +79 -0
- data/test/helper.rb +262 -0
- data/test/notice_test.rb +131 -0
- metadata +222 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Airbrake - User Attributes
|
2
|
+
=======================
|
3
|
+
|
4
|
+
Adds information about the current user to error reports.
|
5
|
+
This information can only be processed and displayed by
|
6
|
+
[Errbit, the open source error catcher](https://github.com/errbit/errbit).
|
7
|
+
|
8
|
+
This gem can be used as a replacement for the `airbrake` gem,
|
9
|
+
since it loads `airbrake` as a dependency.
|
10
|
+
|
11
|
+
Copyright (c) 2012 Cloudfuji
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler/gem_helper'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the airbrake_user_attributes gem.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
Bundler::GemHelper.install_tasks
|
16
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'airbrake_user_attributes/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'airbrake_user_attributes'
|
7
|
+
s.authors = ['Nathan Broadbent']
|
8
|
+
s.email = 'nathan.f77@gmail.com'
|
9
|
+
s.homepage = 'http://cloudfuji.com'
|
10
|
+
s.summary = 'Send Airbrake notifications with user attributes'
|
11
|
+
s.description = 'Adds information about the current user to error reports'
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.version = AirbrakeUserAttributes::VERSION
|
14
|
+
|
15
|
+
s.add_development_dependency("actionpack", "~> 2.3.8")
|
16
|
+
s.add_development_dependency("activerecord", "~> 2.3.8")
|
17
|
+
s.add_development_dependency("activesupport", "~> 2.3.8")
|
18
|
+
s.add_development_dependency("bourne", ">= 1.0")
|
19
|
+
s.add_development_dependency("fakeweb", "~> 1.3.0")
|
20
|
+
s.add_development_dependency("nokogiri", "~> 1.4.3.1")
|
21
|
+
s.add_development_dependency("rspec", "~> 2.6.0")
|
22
|
+
s.add_development_dependency("sham_rack", "~> 1.3.0")
|
23
|
+
s.add_development_dependency("shoulda", "~> 2.11.3")
|
24
|
+
|
25
|
+
s.add_dependency 'airbrake', '>= 3.0.9'
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'airbrake/notice'
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
class Notice
|
5
|
+
# User information
|
6
|
+
# - Provides information about the currently logged in user
|
7
|
+
attr_reader :user_attributes
|
8
|
+
|
9
|
+
def initialize_with_user_attributes(args)
|
10
|
+
self.user_attributes = args[:user_attributes] || {}
|
11
|
+
initialize_without_user_attributes(args)
|
12
|
+
end
|
13
|
+
alias_method_chain :initialize, :user_attributes
|
14
|
+
|
15
|
+
# Converts the given notice to XML
|
16
|
+
# Need to override whole builder to add user-attributes at end.
|
17
|
+
def to_xml
|
18
|
+
builder = Builder::XmlMarkup.new
|
19
|
+
builder.instruct!
|
20
|
+
xml = builder.notice(:version => Airbrake::API_VERSION) do |notice|
|
21
|
+
notice.tag!("api-key", api_key)
|
22
|
+
notice.notifier do |notifier|
|
23
|
+
notifier.name(notifier_name)
|
24
|
+
notifier.version(notifier_version)
|
25
|
+
notifier.url(notifier_url)
|
26
|
+
end
|
27
|
+
notice.error do |error|
|
28
|
+
error.tag!('class', error_class)
|
29
|
+
error.message(error_message)
|
30
|
+
error.backtrace do |backtrace|
|
31
|
+
self.backtrace.lines.each do |line|
|
32
|
+
backtrace.line(:number => line.number,
|
33
|
+
:file => line.file,
|
34
|
+
:method => line.method)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if url ||
|
39
|
+
controller ||
|
40
|
+
action ||
|
41
|
+
!parameters.blank? ||
|
42
|
+
!cgi_data.blank? ||
|
43
|
+
!session_data.blank?
|
44
|
+
notice.request do |request|
|
45
|
+
request.url(url)
|
46
|
+
request.component(controller)
|
47
|
+
request.action(action)
|
48
|
+
unless parameters.nil? || parameters.empty?
|
49
|
+
request.params do |params|
|
50
|
+
xml_vars_for(params, parameters)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
unless session_data.nil? || session_data.empty?
|
54
|
+
request.session do |session|
|
55
|
+
xml_vars_for(session, session_data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
unless cgi_data.nil? || cgi_data.empty?
|
59
|
+
request.tag!("cgi-data") do |cgi_datum|
|
60
|
+
xml_vars_for(cgi_datum, cgi_data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
notice.tag!("server-environment") do |env|
|
66
|
+
env.tag!("project-root", project_root)
|
67
|
+
env.tag!("environment-name", environment_name)
|
68
|
+
env.tag!("hostname", hostname)
|
69
|
+
end
|
70
|
+
|
71
|
+
if user_attributes.present?
|
72
|
+
notice.tag!("user-attributes") do |user|
|
73
|
+
xml_vars_for(user, user_attributes)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
xml.to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
attr_writer :user_attributes
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'airbrake/rails/controller_methods'
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rails
|
5
|
+
module ControllerMethods
|
6
|
+
|
7
|
+
def airbrake_request_data_with_user_attributes
|
8
|
+
data = airbrake_request_data_without_user_attributes
|
9
|
+
data[:user_attributes] = current_user_filtered_attributes if respond_to?(:current_user)
|
10
|
+
data
|
11
|
+
end
|
12
|
+
alias_method_chain :airbrake_request_data, :user_attributes
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Returns filtered attributes for current user (removes auth-related fields)
|
17
|
+
def current_user_filtered_attributes
|
18
|
+
attributes = current_user.attributes.reject do |k, v|
|
19
|
+
/password|token|login|sign_in|per_page|_at$/ =~ k
|
20
|
+
end
|
21
|
+
# Try to include a URL for the user, if possible.
|
22
|
+
if url_method = [:user_url, :admin_user_url].detect {|m| respond_to?(m) }
|
23
|
+
attributes[:url] = send(url_method, current_user)
|
24
|
+
end
|
25
|
+
attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
3
|
+
|
4
|
+
<xs:element name="notice">
|
5
|
+
<xs:complexType>
|
6
|
+
<xs:all>
|
7
|
+
<xs:element name="api-key" type="xs:string"/>
|
8
|
+
<xs:element name="notifier" type="notifier"/>
|
9
|
+
<xs:element name="error" type="error"/>
|
10
|
+
<xs:element name="request" type="request" minOccurs="0"/>
|
11
|
+
<xs:element name="server-environment" type="serverEnvironment"/>
|
12
|
+
<xs:element name="user-attributes" type="varList" minOccurs="0"/>
|
13
|
+
</xs:all>
|
14
|
+
<xs:attribute name="version" type="xs:string" use="required"/>
|
15
|
+
</xs:complexType>
|
16
|
+
</xs:element>
|
17
|
+
|
18
|
+
<xs:complexType name="notifier">
|
19
|
+
<xs:all>
|
20
|
+
<xs:element name="name" type="xs:string"/>
|
21
|
+
<xs:element name="version" type="xs:string"/>
|
22
|
+
<xs:element name="url" type="xs:string"/>
|
23
|
+
</xs:all>
|
24
|
+
</xs:complexType>
|
25
|
+
|
26
|
+
<xs:complexType name="error">
|
27
|
+
<xs:all>
|
28
|
+
<xs:element name="class" type="xs:string"/>
|
29
|
+
<xs:element name="message" type="xs:string" minOccurs="0"/>
|
30
|
+
<xs:element name="backtrace" type="backtrace"/>
|
31
|
+
</xs:all>
|
32
|
+
</xs:complexType>
|
33
|
+
|
34
|
+
<xs:complexType name="backtrace">
|
35
|
+
<xs:sequence>
|
36
|
+
<xs:element name="line" maxOccurs="unbounded">
|
37
|
+
<xs:complexType>
|
38
|
+
<xs:attribute name="file" type="xs:string" use="required"/>
|
39
|
+
<xs:attribute name="number" type="xs:string" use="required"/>
|
40
|
+
<xs:attribute name="method" type="xs:string" use="optional"/>
|
41
|
+
</xs:complexType>
|
42
|
+
</xs:element>
|
43
|
+
</xs:sequence>
|
44
|
+
</xs:complexType>
|
45
|
+
|
46
|
+
<xs:complexType name="request">
|
47
|
+
<xs:all>
|
48
|
+
<xs:element name="url" type="xs:string"/>
|
49
|
+
<xs:element name="component" type="xs:string"/>
|
50
|
+
<xs:element name="action" type="xs:string" minOccurs="0"/>
|
51
|
+
<xs:element name="params" type="varList" minOccurs="0"/>
|
52
|
+
<xs:element name="session" type="varList" minOccurs="0"/>
|
53
|
+
<xs:element name="cgi-data" type="varList" minOccurs="0"/>
|
54
|
+
</xs:all>
|
55
|
+
</xs:complexType>
|
56
|
+
|
57
|
+
<xs:complexType name="varList">
|
58
|
+
<xs:sequence>
|
59
|
+
<xs:element name="var" type="var" maxOccurs="unbounded"/>
|
60
|
+
</xs:sequence>
|
61
|
+
</xs:complexType>
|
62
|
+
|
63
|
+
<xs:complexType name="var" mixed="true">
|
64
|
+
<xs:sequence>
|
65
|
+
<xs:element name="var" type="var" minOccurs="0" maxOccurs="unbounded"/>
|
66
|
+
</xs:sequence>
|
67
|
+
<xs:attribute name="key" type="xs:string" use="required"/>
|
68
|
+
</xs:complexType>
|
69
|
+
|
70
|
+
<xs:complexType name="serverEnvironment">
|
71
|
+
<xs:sequence>
|
72
|
+
<xs:element name="project-root" type="xs:string" minOccurs="0"/>
|
73
|
+
<xs:element name="environment-name" type="xs:string"/>
|
74
|
+
<xs:element name="app-version" type="xs:string" minOccurs="0"/>
|
75
|
+
<xs:element name="hostname" type="xs:string" minOccurs="0"/>
|
76
|
+
</xs:sequence>
|
77
|
+
</xs:complexType>
|
78
|
+
|
79
|
+
</xs:schema>
|
data/test/helper.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
5
|
+
|
6
|
+
require 'thread'
|
7
|
+
|
8
|
+
require "bundler/setup"
|
9
|
+
|
10
|
+
require 'shoulda'
|
11
|
+
require 'mocha'
|
12
|
+
|
13
|
+
require 'action_controller'
|
14
|
+
require 'action_controller/test_process'
|
15
|
+
require 'active_record'
|
16
|
+
require 'active_support'
|
17
|
+
require 'nokogiri'
|
18
|
+
require 'rack'
|
19
|
+
require 'bourne'
|
20
|
+
require 'sham_rack'
|
21
|
+
|
22
|
+
require "airbrake"
|
23
|
+
require "airbrake_user_attributes"
|
24
|
+
|
25
|
+
begin require 'redgreen'; rescue LoadError; end
|
26
|
+
|
27
|
+
module TestMethods
|
28
|
+
def rescue_action e
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_raise
|
33
|
+
raise "Airbrake"
|
34
|
+
end
|
35
|
+
|
36
|
+
def do_not_raise
|
37
|
+
render :text => "Success"
|
38
|
+
end
|
39
|
+
|
40
|
+
def do_raise_ignored
|
41
|
+
raise ActiveRecord::RecordNotFound.new("404")
|
42
|
+
end
|
43
|
+
|
44
|
+
def do_raise_not_ignored
|
45
|
+
raise ActiveRecord::StatementInvalid.new("Statement invalid")
|
46
|
+
end
|
47
|
+
|
48
|
+
def manual_notify
|
49
|
+
notify_airbrake(Exception.new)
|
50
|
+
render :text => "Success"
|
51
|
+
end
|
52
|
+
|
53
|
+
def manual_notify_ignored
|
54
|
+
notify_airbrake(ActiveRecord::RecordNotFound.new("404"))
|
55
|
+
render :text => "Success"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Test::Unit::TestCase
|
60
|
+
def request(action = nil, method = :get, user_agent = nil, params = {})
|
61
|
+
@request = ActionController::TestRequest.new
|
62
|
+
@request.action = action ? action.to_s : ""
|
63
|
+
|
64
|
+
if user_agent
|
65
|
+
if @request.respond_to?(:user_agent=)
|
66
|
+
@request.user_agent = user_agent
|
67
|
+
else
|
68
|
+
@request.env["HTTP_USER_AGENT"] = user_agent
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@request.query_parameters = @request.query_parameters.merge(params)
|
72
|
+
@response = ActionController::TestResponse.new
|
73
|
+
@controller.process(@request, @response)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Borrowed from ActiveSupport 2.3.2
|
77
|
+
def assert_difference(expression, difference = 1, message = nil, &block)
|
78
|
+
b = block.send(:binding)
|
79
|
+
exps = Array.wrap(expression)
|
80
|
+
before = exps.map { |e| eval(e, b) }
|
81
|
+
|
82
|
+
yield
|
83
|
+
|
84
|
+
exps.each_with_index do |e, i|
|
85
|
+
error = "#{e.inspect} didn't change by #{difference}"
|
86
|
+
error = "#{message}.\n#{error}" if message
|
87
|
+
assert_equal(before[i] + difference, eval(e, b), error)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_no_difference(expression, message = nil, &block)
|
92
|
+
assert_difference expression, 0, message, &block
|
93
|
+
end
|
94
|
+
|
95
|
+
def stub_sender
|
96
|
+
stub('sender', :send_to_airbrake => nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
def stub_sender!
|
100
|
+
Airbrake.sender = stub_sender
|
101
|
+
end
|
102
|
+
|
103
|
+
def stub_notice
|
104
|
+
stub('notice', :to_xml => 'some yaml', :ignore? => false)
|
105
|
+
end
|
106
|
+
|
107
|
+
def stub_notice!
|
108
|
+
stub_notice.tap do |notice|
|
109
|
+
Airbrake::Notice.stubs(:new => notice)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_dummy
|
114
|
+
Airbrake::DummySender.new
|
115
|
+
end
|
116
|
+
|
117
|
+
def reset_config
|
118
|
+
Airbrake.configuration = nil
|
119
|
+
Airbrake.configure do |config|
|
120
|
+
config.api_key = 'abc123'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def clear_backtrace_filters
|
125
|
+
Airbrake.configuration.backtrace_filters.clear
|
126
|
+
end
|
127
|
+
|
128
|
+
def build_exception(opts = {})
|
129
|
+
backtrace = ["airbrake/test/helper.rb:132:in `build_exception'",
|
130
|
+
"airbrake/test/backtrace.rb:4:in `build_notice_data'",
|
131
|
+
"/var/lib/gems/1.8/gems/airbrake-2.4.5/rails/init.rb:2:in `send_exception'"]
|
132
|
+
opts = {:backtrace => backtrace}.merge(opts)
|
133
|
+
BacktracedException.new(opts)
|
134
|
+
end
|
135
|
+
|
136
|
+
class BacktracedException < Exception
|
137
|
+
attr_accessor :backtrace
|
138
|
+
def initialize(opts)
|
139
|
+
@backtrace = opts[:backtrace]
|
140
|
+
end
|
141
|
+
def set_backtrace(bt)
|
142
|
+
@backtrace = bt
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def build_notice_data(exception = nil)
|
147
|
+
exception ||= build_exception
|
148
|
+
{
|
149
|
+
:api_key => 'abc123',
|
150
|
+
:error_class => exception.class.name,
|
151
|
+
:error_message => "#{exception.class.name}: #{exception.message}",
|
152
|
+
:backtrace => exception.backtrace,
|
153
|
+
:environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
|
154
|
+
:request => {
|
155
|
+
:params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
|
156
|
+
:rails_root => '/path/to/application',
|
157
|
+
:url => "http://test.host/users/1"
|
158
|
+
},
|
159
|
+
:session => {
|
160
|
+
:key => '123abc',
|
161
|
+
:data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def assert_caught_and_sent
|
167
|
+
assert !Airbrake.sender.collected.empty?
|
168
|
+
end
|
169
|
+
|
170
|
+
def assert_caught_and_not_sent
|
171
|
+
assert Airbrake.sender.collected.empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
def assert_array_starts_with(expected, actual)
|
175
|
+
assert_respond_to actual, :to_ary
|
176
|
+
array = actual.to_ary.reverse
|
177
|
+
expected.reverse.each_with_index do |value, i|
|
178
|
+
assert_equal value, array[i]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def assert_valid_node(document, xpath, content)
|
183
|
+
nodes = document.xpath(xpath)
|
184
|
+
assert nodes.any?{|node| node.content == content },
|
185
|
+
"Expected xpath #{xpath} to have content #{content}, " +
|
186
|
+
"but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
|
187
|
+
"Document:\n#{document.to_s}"
|
188
|
+
end
|
189
|
+
|
190
|
+
def assert_logged(expected)
|
191
|
+
assert_received(Airbrake, :write_verbose_log) do |expect|
|
192
|
+
expect.with {|actual| actual =~ expected }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def assert_not_logged(expected)
|
197
|
+
assert_received(Airbrake, :write_verbose_log) do |expect|
|
198
|
+
expect.with {|actual| actual =~ expected }.never
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
module DefinesConstants
|
206
|
+
def setup
|
207
|
+
@defined_constants = []
|
208
|
+
end
|
209
|
+
|
210
|
+
def teardown
|
211
|
+
@defined_constants.each do |constant|
|
212
|
+
Object.__send__(:remove_const, constant)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def define_constant(name, value)
|
217
|
+
Object.const_set(name, value)
|
218
|
+
@defined_constants << name
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Also stolen from AS 2.3.2
|
223
|
+
class Array
|
224
|
+
# Wraps the object in an Array unless it's an Array. Converts the
|
225
|
+
# object to an Array using #to_ary if it implements that.
|
226
|
+
def self.wrap(object)
|
227
|
+
case object
|
228
|
+
when nil
|
229
|
+
[]
|
230
|
+
when self
|
231
|
+
object
|
232
|
+
else
|
233
|
+
if object.respond_to?(:to_ary)
|
234
|
+
object.to_ary
|
235
|
+
else
|
236
|
+
[object]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
class CollectingSender
|
244
|
+
attr_reader :collected
|
245
|
+
|
246
|
+
def initialize
|
247
|
+
@collected = []
|
248
|
+
end
|
249
|
+
|
250
|
+
def send_to_airbrake(data)
|
251
|
+
@collected << data
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class FakeLogger
|
256
|
+
def info(*args); end
|
257
|
+
def debug(*args); end
|
258
|
+
def warn(*args); end
|
259
|
+
def error(*args); end
|
260
|
+
def fatal(*args); end
|
261
|
+
end
|
262
|
+
|
data/test/notice_test.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class NoticeTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include DefinesConstants
|
6
|
+
|
7
|
+
def configure
|
8
|
+
Airbrake::Configuration.new.tap do |config|
|
9
|
+
config.api_key = 'abc123def456'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_notice(args = {})
|
14
|
+
configuration = args.delete(:configuration) || configure
|
15
|
+
Airbrake::Notice.new(configuration.merge(args))
|
16
|
+
end
|
17
|
+
|
18
|
+
def stub_request(attrs = {})
|
19
|
+
stub('request', { :parameters => { 'one' => 'two' },
|
20
|
+
:protocol => 'http',
|
21
|
+
:host => 'some.host',
|
22
|
+
:request_uri => '/some/uri',
|
23
|
+
:session => { :to_hash => { 'a' => 'b' } },
|
24
|
+
:env => { 'three' => 'four' } }.update(attrs))
|
25
|
+
end
|
26
|
+
|
27
|
+
def hostname
|
28
|
+
`hostname`.chomp
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_valid_notice_document(document)
|
32
|
+
xsd_path = File.join(File.dirname(__FILE__), "airbrake_2_2.xsd")
|
33
|
+
schema = Nokogiri::XML::Schema.new(IO.read(xsd_path))
|
34
|
+
errors = schema.validate(document)
|
35
|
+
assert errors.empty?, errors.collect{|e| e.message }.join
|
36
|
+
end
|
37
|
+
|
38
|
+
context "a Notice turned into XML" do
|
39
|
+
setup do
|
40
|
+
Airbrake.configure do |config|
|
41
|
+
config.api_key = "1234567890"
|
42
|
+
end
|
43
|
+
|
44
|
+
@exception = build_exception
|
45
|
+
|
46
|
+
@notice = build_notice({
|
47
|
+
:notifier_name => 'a name',
|
48
|
+
:notifier_version => '1.2.3',
|
49
|
+
:notifier_url => 'http://some.url/path',
|
50
|
+
:exception => @exception,
|
51
|
+
:controller => "controller",
|
52
|
+
:action => "action",
|
53
|
+
:url => "http://url.com",
|
54
|
+
:parameters => { "paramskey" => "paramsvalue",
|
55
|
+
"nestparentkey" => { "nestkey" => "nestvalue" } },
|
56
|
+
:session_data => { "sessionkey" => "sessionvalue" },
|
57
|
+
:cgi_data => { "cgikey" => "cgivalue" },
|
58
|
+
:user_attributes => { "id" => 1234, "username" => "jsmith", "url" => "http://www.example.com/users/1234" },
|
59
|
+
:project_root => "RAILS_ROOT",
|
60
|
+
:environment_name => "RAILS_ENV"
|
61
|
+
})
|
62
|
+
|
63
|
+
@xml = @notice.to_xml
|
64
|
+
|
65
|
+
@document = Nokogiri::XML::Document.parse(@xml)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "validate against the XML schema" do
|
69
|
+
assert_valid_notice_document @document
|
70
|
+
end
|
71
|
+
|
72
|
+
should "serialize a Notice to XML when sent #to_xml" do
|
73
|
+
assert_valid_node(@document, "//api-key", @notice.api_key)
|
74
|
+
|
75
|
+
assert_valid_node(@document, "//notifier/name", @notice.notifier_name)
|
76
|
+
assert_valid_node(@document, "//notifier/version", @notice.notifier_version)
|
77
|
+
assert_valid_node(@document, "//notifier/url", @notice.notifier_url)
|
78
|
+
|
79
|
+
assert_valid_node(@document, "//error/class", @notice.error_class)
|
80
|
+
assert_valid_node(@document, "//error/message", @notice.error_message)
|
81
|
+
|
82
|
+
assert_valid_node(@document, "//error/backtrace/line/@number", @notice.backtrace.lines.first.number)
|
83
|
+
assert_valid_node(@document, "//error/backtrace/line/@file", @notice.backtrace.lines.first.file)
|
84
|
+
assert_valid_node(@document, "//error/backtrace/line/@method", @notice.backtrace.lines.first.method)
|
85
|
+
|
86
|
+
assert_valid_node(@document, "//request/url", @notice.url)
|
87
|
+
assert_valid_node(@document, "//request/component", @notice.controller)
|
88
|
+
assert_valid_node(@document, "//request/action", @notice.action)
|
89
|
+
|
90
|
+
assert_valid_node(@document, "//request/params/var/@key", "paramskey")
|
91
|
+
assert_valid_node(@document, "//request/params/var", "paramsvalue")
|
92
|
+
assert_valid_node(@document, "//request/params/var/@key", "nestparentkey")
|
93
|
+
assert_valid_node(@document, "//request/params/var/var/@key", "nestkey")
|
94
|
+
assert_valid_node(@document, "//request/params/var/var", "nestvalue")
|
95
|
+
assert_valid_node(@document, "//request/session/var/@key", "sessionkey")
|
96
|
+
assert_valid_node(@document, "//request/session/var", "sessionvalue")
|
97
|
+
assert_valid_node(@document, "//request/cgi-data/var/@key", "cgikey")
|
98
|
+
assert_valid_node(@document, "//request/cgi-data/var", "cgivalue")
|
99
|
+
|
100
|
+
assert_valid_node(@document, "//server-environment/project-root", "RAILS_ROOT")
|
101
|
+
assert_valid_node(@document, "//server-environment/environment-name", "RAILS_ENV")
|
102
|
+
assert_valid_node(@document, "//server-environment/hostname", hostname)
|
103
|
+
|
104
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "id")
|
105
|
+
assert_valid_node(@document, "//user-attributes/var", "1234")
|
106
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "username")
|
107
|
+
assert_valid_node(@document, "//user-attributes/var", "jsmith")
|
108
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "url")
|
109
|
+
assert_valid_node(@document, "//user-attributes/var", "http://www.example.com/users/1234")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
should "not send empty request data" do
|
114
|
+
notice = build_notice
|
115
|
+
assert_nil notice.url
|
116
|
+
assert_nil notice.controller
|
117
|
+
assert_nil notice.action
|
118
|
+
assert_empty notice.user_attributes
|
119
|
+
|
120
|
+
xml = notice.to_xml
|
121
|
+
document = Nokogiri::XML.parse(xml)
|
122
|
+
assert_nil document.at('//request/url')
|
123
|
+
assert_nil document.at('//request/component')
|
124
|
+
assert_nil document.at('//request/action')
|
125
|
+
assert_nil document.at('//user-attributes')
|
126
|
+
|
127
|
+
assert_valid_notice_document document
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: airbrake_user_attributes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Broadbent
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: actionpack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.3.8
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.3.8
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activerecord
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.3.8
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.3.8
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activesupport
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.3.8
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.8
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bourne
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: fakeweb
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.3.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: nokogiri
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.4.3.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.4.3.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.6.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 2.6.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: sham_rack
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.3.0
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.3.0
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: shoulda
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 2.11.3
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 2.11.3
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: airbrake
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 3.0.9
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 3.0.9
|
174
|
+
description: Adds information about the current user to error reports
|
175
|
+
email: nathan.f77@gmail.com
|
176
|
+
executables: []
|
177
|
+
extensions: []
|
178
|
+
extra_rdoc_files: []
|
179
|
+
files:
|
180
|
+
- .gitignore
|
181
|
+
- Gemfile
|
182
|
+
- README.md
|
183
|
+
- Rakefile
|
184
|
+
- airbrake_user_attributes.gemspec
|
185
|
+
- lib/airbrake_overrides/notice.rb
|
186
|
+
- lib/airbrake_overrides/rails/controller_methods.rb
|
187
|
+
- lib/airbrake_user_attributes.rb
|
188
|
+
- lib/airbrake_user_attributes/version.rb
|
189
|
+
- test/airbrake_2_2.xsd
|
190
|
+
- test/helper.rb
|
191
|
+
- test/notice_test.rb
|
192
|
+
homepage: http://cloudfuji.com
|
193
|
+
licenses: []
|
194
|
+
post_install_message:
|
195
|
+
rdoc_options: []
|
196
|
+
require_paths:
|
197
|
+
- lib
|
198
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
+
none: false
|
200
|
+
requirements:
|
201
|
+
- - ! '>='
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
segments:
|
205
|
+
- 0
|
206
|
+
hash: 311172291318117201
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
+
none: false
|
209
|
+
requirements:
|
210
|
+
- - ! '>='
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
segments:
|
214
|
+
- 0
|
215
|
+
hash: 311172291318117201
|
216
|
+
requirements: []
|
217
|
+
rubyforge_project:
|
218
|
+
rubygems_version: 1.8.24
|
219
|
+
signing_key:
|
220
|
+
specification_version: 3
|
221
|
+
summary: Send Airbrake notifications with user attributes
|
222
|
+
test_files: []
|