airbrake-api 3.3.0 → 4.0.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/.travis.yml +8 -2
- data/README.md +55 -31
- data/airbrake-api.gemspec +3 -1
- data/lib/airbrake-api.rb +2 -20
- data/lib/airbrake-api/base.rb +17 -0
- data/lib/airbrake-api/client.rb +149 -26
- data/lib/airbrake-api/configuration.rb +55 -0
- data/lib/airbrake-api/error.rb +20 -35
- data/lib/airbrake-api/middleware/raise_response_error.rb +17 -0
- data/lib/airbrake-api/middleware/raise_server_error.rb +16 -0
- data/lib/airbrake-api/middleware/scrub_response.rb +15 -0
- data/lib/airbrake-api/notice.rb +21 -49
- data/lib/airbrake-api/project.rb +10 -9
- data/lib/airbrake-api/version.rb +1 -1
- data/spec/airbrake_api/client_spec.rb +178 -0
- data/spec/airbrake_api/notice_spec.rb +9 -1
- data/spec/airbrake_api_spec.rb +27 -3
- data/spec/fixtures/deploys.xml +275 -0
- data/spec/fixtures/empty_deploys.xml +5 -0
- data/spec/fixtures/individual_notice.xml +109 -109
- data/spec/spec_helper.rb +11 -6
- metadata +56 -14
- data/lib/airbrake-api/core_extensions.rb +0 -5
data/lib/airbrake-api/error.rb
CHANGED
@@ -1,58 +1,43 @@
|
|
1
|
+
require 'airbrake-api/base'
|
2
|
+
|
1
3
|
module AirbrakeAPI
|
2
|
-
class Error <
|
4
|
+
class Error < Base
|
3
5
|
|
6
|
+
# @deprecated Please use {AirbrakeAPI::Client::error} and {AirbrakeAPI::Client::errors} instead
|
4
7
|
def self.find(*args)
|
5
|
-
|
8
|
+
deprecate('Error.find has been deprecated; use AibrakeAPI::Client#error and AibrakeAPI::Client#errors instead')
|
6
9
|
|
7
10
|
results = case args.first
|
8
11
|
when Fixnum
|
9
|
-
|
12
|
+
id = args.shift
|
13
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
14
|
+
AirbrakeAPI::Client.new.error(id, options)
|
10
15
|
when :all
|
11
|
-
|
16
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
17
|
+
AirbrakeAPI::Client.new.errors(options)
|
12
18
|
else
|
13
19
|
raise AirbrakeError.new('Invalid argument')
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
raise AirbrakeError.new(results.errors.error) if results.errors
|
18
|
-
|
19
|
-
results.group || results.groups
|
22
|
+
results
|
20
23
|
end
|
21
24
|
|
25
|
+
# @deprecated Please use {AirbrakeAPI::Client::update} instead
|
22
26
|
def self.update(error, options)
|
23
|
-
|
24
|
-
|
25
|
-
response = put(error_path(error), :body => options)
|
26
|
-
if response.code == 403
|
27
|
-
raise AirbrakeError.new('SSL should be enabled - use Airbrake.secure = true in configuration')
|
28
|
-
end
|
29
|
-
results = Hashie::Mash.new(response)
|
30
|
-
|
31
|
-
raise AirbrakeError.new(results.errors.error) if results.errors
|
32
|
-
results.group
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def self.find_all(args)
|
38
|
-
options = args.extract_options!
|
39
|
-
|
40
|
-
fetch(collection_path, options)
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.find_individual(args)
|
44
|
-
id = args.shift
|
45
|
-
options = args.extract_options!
|
46
|
-
|
47
|
-
fetch(error_path(id), options)
|
27
|
+
deprecate('Error.update has been deprecated; use AibrakeAPI::Client#update instead')
|
28
|
+
AirbrakeAPI::Client.new.update(error, options)
|
48
29
|
end
|
49
30
|
|
31
|
+
# @deprecated Please use {AirbrakeAPI::Client::errors_path} instead
|
50
32
|
def self.collection_path
|
51
|
-
'
|
33
|
+
deprecate('Error.collection_path has been deprecated; use AibrakeAPI::Client#errors_path instead')
|
34
|
+
AirbrakeAPI::Client.new.errors_path
|
52
35
|
end
|
53
36
|
|
37
|
+
# @deprecated Please use {AirbrakeAPI::Client::error_path} instead
|
54
38
|
def self.error_path(error_id)
|
55
|
-
|
39
|
+
deprecate('Error.error_path has been deprecated; use AibrakeAPI::Client#error_path instead')
|
40
|
+
AirbrakeAPI::Client.new.error_path(error_id)
|
56
41
|
end
|
57
42
|
|
58
43
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module AirbrakeAPI
|
4
|
+
module Middleware
|
5
|
+
class RaiseResponseError < Faraday::Response::Middleware
|
6
|
+
|
7
|
+
def on_complete(env)
|
8
|
+
raise AirbrakeError.new('No results found.') if env[:body].nil?
|
9
|
+
|
10
|
+
if env[:body].errors && env[:body].errors.error
|
11
|
+
raise AirbrakeError.new(env[:body].errors.error)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module AirbrakeAPI
|
4
|
+
module Middleware
|
5
|
+
class RaiseServerError < Faraday::Response::Middleware
|
6
|
+
|
7
|
+
def on_complete(env)
|
8
|
+
case env[:status].to_i
|
9
|
+
when 403
|
10
|
+
raise AirbrakeError.new('SSL should be enabled - use AirbrakeAPI.secure = true in configuration')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module AirbrakeAPI
|
4
|
+
module Middleware
|
5
|
+
class ScrubResponse < Faraday::Response::Middleware
|
6
|
+
|
7
|
+
def parse(body)
|
8
|
+
body.gsub!(/<__utmz>.*?<\/__utmz>/m,'')
|
9
|
+
body.gsub!(/<[0-9]+.*?>.*?<\/[0-9]+.*?>/m,'')
|
10
|
+
body
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/airbrake-api/notice.rb
CHANGED
@@ -1,66 +1,38 @@
|
|
1
1
|
require 'parallel'
|
2
|
+
require 'airbrake-api/base'
|
2
3
|
|
3
4
|
module AirbrakeAPI
|
4
|
-
class Notice <
|
5
|
-
PER_PAGE = 30
|
6
|
-
PARALLEL_WORKERS = 10
|
5
|
+
class Notice < Base
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
if hash.errors
|
14
|
-
raise AirbrakeError.new(results.errors.error)
|
15
|
-
end
|
16
|
-
|
17
|
-
hash.notice
|
7
|
+
# @deprecated Please use {AirbrakeAPI::Client::notice} instead
|
8
|
+
def self.find(id, error_id, options = {})
|
9
|
+
deprecate('Notice.find has been deprecated; use AibrakeAPI::Client#notice instead')
|
10
|
+
AirbrakeAPI::Client.new.notice(id, error_id, options)
|
18
11
|
end
|
19
12
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
notices = []
|
25
|
-
page = 1
|
26
|
-
while !notice_options[:pages] || page <= notice_options[:pages]
|
27
|
-
options[:page] = page
|
28
|
-
hash = fetch(all_path(error_id), options)
|
29
|
-
if hash.errors
|
30
|
-
raise AirbrakeError.new(hash.errors.error)
|
31
|
-
end
|
32
|
-
|
33
|
-
batch = Parallel.map(hash.notices, :in_threads => PARALLEL_WORKERS) do |notice_stub|
|
34
|
-
find(notice_stub.id, error_id)
|
35
|
-
end
|
36
|
-
yield batch if block_given?
|
37
|
-
batch.each{|n| notices << n }
|
38
|
-
|
39
|
-
break if batch.size < PER_PAGE
|
40
|
-
page += 1
|
41
|
-
end
|
42
|
-
notices
|
13
|
+
# @deprecated Please use {AirbrakeAPI::Client::all_notices} instead
|
14
|
+
def self.find_all_by_error_id(error_id, notice_options = {}, &block)
|
15
|
+
deprecate('Notice.find_all_by_error_id has been deprecated; use AibrakeAPI::Client#all_notices instead')
|
16
|
+
AirbrakeAPI::Client.new.notices(error_id, notice_options, &block)
|
43
17
|
end
|
44
18
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if hash.errors
|
50
|
-
raise AirbrakeError.new(results.errors.error)
|
51
|
-
end
|
52
|
-
|
53
|
-
hash.notices
|
19
|
+
# @deprecated Please use {AirbrakeAPI::Client::notices} instead
|
20
|
+
def self.find_by_error_id(error_id, options = {})
|
21
|
+
deprecate('Notice.find_by_error_id has been deprecated; use AibrakeAPI::Client#notices instead')
|
22
|
+
AirbrakeAPI::Client.new.notices(error_id, options)
|
54
23
|
end
|
55
24
|
|
56
|
-
|
57
|
-
|
25
|
+
# @deprecated Please use {AirbrakeAPI::Client::notice_path} instead
|
58
26
|
def self.find_path(id, error_id)
|
59
|
-
|
27
|
+
deprecate('Notice.find_path has been deprecated; use AibrakeAPI::Client#notice_path instead')
|
28
|
+
AirbrakeAPI::Client.new.notice_path(id, error_id)
|
60
29
|
end
|
61
30
|
|
31
|
+
# @deprecated Please use {AirbrakeAPI::Client::notices_path} instead
|
62
32
|
def self.all_path(error_id)
|
63
|
-
|
33
|
+
deprecate('Notice.all_path has been deprecated; use AibrakeAPI::Client#notices_path instead')
|
34
|
+
AirbrakeAPI::Client.new.notices_path(error_id)
|
64
35
|
end
|
36
|
+
|
65
37
|
end
|
66
38
|
end
|
data/lib/airbrake-api/project.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
+
require 'airbrake-api/base'
|
2
|
+
|
1
3
|
module AirbrakeAPI
|
2
|
-
class Project <
|
4
|
+
class Project < Base
|
3
5
|
|
6
|
+
# @deprecated Please use {AirbrakeAPI::Client::projects} instead
|
4
7
|
def self.find(*args)
|
5
|
-
|
6
|
-
options = args.
|
7
|
-
|
8
|
-
results = fetch(collection_path, options)
|
9
|
-
|
10
|
-
raise AirbrakeError.new(results.errors.error) if results.errors
|
11
|
-
results.projects.project
|
8
|
+
deprecate('Project.find has been deprecated; use AibrakeAPI::Client.projects instead')
|
9
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
10
|
+
AirbrakeAPI::Client.new.projects(options)
|
12
11
|
end
|
13
12
|
|
13
|
+
# @deprecated Please use {AirbrakeAPI::Client::projects_path} instead
|
14
14
|
def self.collection_path
|
15
|
-
'
|
15
|
+
deprecate('Project.collection_path has been deprecated; use AibrakeAPI::Client.projects_path instead')
|
16
|
+
AirbrakeAPI::Client.new.projects_path
|
16
17
|
end
|
17
18
|
|
18
19
|
end
|
data/lib/airbrake-api/version.rb
CHANGED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AirbrakeAPI::Client do
|
4
|
+
describe 'initialization' do
|
5
|
+
before do
|
6
|
+
@keys = AirbrakeAPI::Configuration::VALID_OPTIONS_KEYS
|
7
|
+
end
|
8
|
+
|
9
|
+
context "with module configuration" do
|
10
|
+
before do
|
11
|
+
AirbrakeAPI.configure do |config|
|
12
|
+
@keys.each do |key|
|
13
|
+
config.send("#{key}=", key)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
after do
|
19
|
+
AirbrakeAPI.reset
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should inherit module configuration" do
|
23
|
+
api = AirbrakeAPI::Client.new
|
24
|
+
@keys.each do |key|
|
25
|
+
api.send(key).should == key
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with class configuration" do
|
30
|
+
|
31
|
+
before do
|
32
|
+
@configuration = {
|
33
|
+
:account => 'test',
|
34
|
+
:auth_token => 'token',
|
35
|
+
:secure => true,
|
36
|
+
:connection_options => {},
|
37
|
+
:adapter => :em_http,
|
38
|
+
:user_agent => 'Airbrake API Tests'
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
context "during initialization" do
|
43
|
+
it "should override module configuration" do
|
44
|
+
api = AirbrakeAPI::Client.new(@configuration)
|
45
|
+
@keys.each do |key|
|
46
|
+
api.send(key).should == @configuration[key]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "after initilization" do
|
52
|
+
it "should override module configuration after initialization" do
|
53
|
+
api = AirbrakeAPI::Client.new
|
54
|
+
@configuration.each do |key, value|
|
55
|
+
api.send("#{key}=", value)
|
56
|
+
end
|
57
|
+
@keys.each do |key|
|
58
|
+
api.send(key).should == @configuration[key]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'api requests'do
|
67
|
+
before(:all) do
|
68
|
+
options = { :account => 'myapp', :auth_token => 'abcdefg123456', :secure => false }
|
69
|
+
AirbrakeAPI.configure(options)
|
70
|
+
|
71
|
+
@client = AirbrakeAPI::Client.new
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should fail with errors" do
|
75
|
+
expect {
|
76
|
+
@client.notices(1696172)
|
77
|
+
}.to raise_error(AirbrakeAPI::AirbrakeError, /You are not authorized to see that page/)
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#deploys' do
|
81
|
+
it 'returns an array of deploys' do
|
82
|
+
@client.deploys('12345').should be_kind_of(Array)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns deploy data' do
|
86
|
+
deploys = @client.deploys('12345')
|
87
|
+
first_deploy = deploys.first
|
88
|
+
|
89
|
+
first_deploy.rails_env.should eq('production')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns empty when no data' do
|
93
|
+
@client.deploys('67890').should be_kind_of(Array)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#projects' do
|
98
|
+
it 'returns an array of projects' do
|
99
|
+
@client.projects.should be_kind_of(Array)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns project data' do
|
103
|
+
projects = @client.projects
|
104
|
+
projects.size.should == 4
|
105
|
+
projects.first.id.should == '1'
|
106
|
+
projects.first.name.should == 'Venkman'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#update' do
|
111
|
+
it 'should update the status of an error' do
|
112
|
+
error = @client.update(1696170, :group => { :resolved => true})
|
113
|
+
error.resolved.should be_true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#errors' do
|
118
|
+
it "should find a page of the 30 most recent errors" do
|
119
|
+
errors = @client.errors
|
120
|
+
ordered = errors.sort_by(&:most_recent_notice_at).reverse
|
121
|
+
ordered.should == errors
|
122
|
+
errors.size.should == 30
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should paginate errors" do
|
126
|
+
errors = @client.errors(:page => 2)
|
127
|
+
ordered = errors.sort_by(&:most_recent_notice_at).reverse
|
128
|
+
ordered.should == errors
|
129
|
+
errors.size.should == 2
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#error' do
|
134
|
+
it "should find an individual error" do
|
135
|
+
error = @client.error(1696170)
|
136
|
+
error.action.should == 'index'
|
137
|
+
error.id.should == 1696170
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#notice' do
|
142
|
+
it "finds individual notices" do
|
143
|
+
@client.notice(1234, 1696170).should_not be_nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it "finds broken notices" do
|
147
|
+
@client.notice(666, 1696170).should_not be_nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#notices' do
|
152
|
+
it "finds all error notices" do
|
153
|
+
notices = @client.notices(1696170)
|
154
|
+
notices.size.should == 42
|
155
|
+
end
|
156
|
+
|
157
|
+
it "finds error notices for a specific page" do
|
158
|
+
notices = @client.notices(1696170, :page => 1)
|
159
|
+
notices.size.should == 30
|
160
|
+
notices.first.id.should == 1234
|
161
|
+
end
|
162
|
+
|
163
|
+
it "finds all error notices with a page limit" do
|
164
|
+
notices = @client.notices(1696171, :pages => 2)
|
165
|
+
notices.size.should == 60
|
166
|
+
end
|
167
|
+
|
168
|
+
it "yields batches" do
|
169
|
+
batches = []
|
170
|
+
notices = @client.notices(1696171, :pages => 2) do |batch|
|
171
|
+
batches << batch
|
172
|
+
end
|
173
|
+
notices.size.should == 60
|
174
|
+
batches.map(&:size).should == [30,30]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -9,7 +9,7 @@ describe AirbrakeAPI::Notice do
|
|
9
9
|
|
10
10
|
it "should find error notices" do
|
11
11
|
notices = AirbrakeAPI::Notice.find_by_error_id(1696170)
|
12
|
-
notices.size.should ==
|
12
|
+
notices.size.should == 42
|
13
13
|
notices.first.id.should == 1234
|
14
14
|
end
|
15
15
|
|
@@ -45,4 +45,12 @@ describe AirbrakeAPI::Notice do
|
|
45
45
|
it "should find a broken notices" do
|
46
46
|
AirbrakeAPI::Notice.find(666, 1696170).should_not == nil
|
47
47
|
end
|
48
|
+
|
49
|
+
it 'defines the notices path' do
|
50
|
+
AirbrakeAPI::Notice.all_path(1696170).should eq('/errors/1696170/notices.xml')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'defines the an individual notices path' do
|
54
|
+
AirbrakeAPI::Notice.find_path(666, 1696170).should eq('/errors/1696170/notices/666.xml')
|
55
|
+
end
|
48
56
|
end
|