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/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,78 +1,102 @@
|
|
1
|
-
Airbrake API [](http://travis-ci.org/spagalloco/airbrake-api)
|
2
|
-
======================================================================================================================================
|
1
|
+
# Airbrake API [](http://travis-ci.org/spagalloco/airbrake-api)
|
3
2
|
|
4
|
-
A ruby
|
3
|
+
A ruby client for the [Airbrake API](http://help.airbrake.io/kb/api-2/api-overview)
|
5
4
|
|
6
|
-
|
7
|
-
-----
|
5
|
+
## Changes in 4.0
|
8
6
|
|
9
|
-
|
7
|
+
AirbrakeAPI has been completely rewritten in 4.0. Why the high version number?
|
8
|
+
This was the first gem I ever wrote and it's wandered a path that started with
|
9
|
+
ActiveResource, followed by HTTParty, and now Faraday. Along the way, AirbrakeAPI
|
10
|
+
has lost it's ActiveRecord-like syntax for a more concise and simple API. Instead
|
11
|
+
of using classes such as `AirbrakeAPI::Error`, the entire API is contained within
|
12
|
+
`AirbrakeAPI::Client`.
|
10
13
|
|
11
|
-
|
14
|
+
The following classes are now deprecated:
|
12
15
|
|
13
|
-
|
16
|
+
* `AirbrakeAPI::Error`
|
17
|
+
* `AirbrakeAPI::Notice`
|
18
|
+
* `AirbrakeAPI::Project`
|
14
19
|
|
15
|
-
|
20
|
+
While your code will continue to work using the old API, they will ultimately be removed in favor of `AirbrakeAPI::Client`.
|
16
21
|
|
17
|
-
|
22
|
+
## Configuration
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
Optionally, you can configure through a single method:
|
24
|
+
AirbrakeAPI can be configured by passing a hash to the configure method:
|
22
25
|
|
23
26
|
AirbrakeAPI.configure(:account => 'anapp', :auth_token => 'abcdefg', :secure => true)
|
24
27
|
|
25
|
-
|
28
|
+
or via a block:
|
29
|
+
|
30
|
+
AirbrakeAPI.configure do |config|
|
31
|
+
config.account = 'anapp'
|
32
|
+
config.auth_token = 'abcdefg'
|
33
|
+
config.secure = true
|
34
|
+
end
|
26
35
|
|
27
|
-
Finding Errors
|
28
|
-
--------------
|
36
|
+
## Finding Errors
|
29
37
|
|
30
38
|
Errors are paginated, the API responds with 25 at a time, pass an optional params hash for additional pages:
|
31
39
|
|
32
|
-
AirbrakeAPI
|
33
|
-
AirbrakeAPI
|
40
|
+
AirbrakeAPI.errors
|
41
|
+
AirbrakeAPI.errors(:page => 2)
|
34
42
|
|
35
43
|
To find an individual error, you can find by ID:
|
36
44
|
|
37
|
-
AirbrakeAPI
|
45
|
+
AirbrakeAPI.error(error_id)
|
46
|
+
|
47
|
+
|
48
|
+
## Finding Notices
|
38
49
|
|
39
50
|
Find *all* notices of an error:
|
40
51
|
|
41
|
-
AirbrakeAPI
|
52
|
+
AirbrakeAPI.notices(error_id)
|
42
53
|
|
43
54
|
Find an individual notice:
|
44
55
|
|
45
|
-
AirbrakeAPI
|
56
|
+
AirbrakeAPI.notice(notice_id, error_id)
|
46
57
|
|
47
58
|
To resolve an error via the API:
|
48
59
|
|
49
|
-
AirbrakeAPI
|
60
|
+
AirbrakeAPI.update(1696170, :group => { :resolved => true})
|
50
61
|
|
51
62
|
Recreate an error:
|
52
63
|
|
53
64
|
STDOUT.sync = true
|
54
|
-
AirbrakeAPI
|
65
|
+
AirbrakeAPI.notices(error_id) do |batch|
|
55
66
|
batch.each do |notice|
|
56
67
|
result = system "curl --silent '#{notice.request.url}' > /dev/null"
|
57
68
|
print (result ? '.' : 'F')
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
61
|
-
Projects
|
62
|
-
--------
|
72
|
+
## Projects
|
63
73
|
|
64
74
|
To retrieve a list of projects:
|
65
75
|
|
66
|
-
AirbrakeAPI
|
76
|
+
AirbrakeAPI.projects
|
77
|
+
|
78
|
+
## Deployments
|
79
|
+
|
80
|
+
To retrieve a list of deployments:
|
81
|
+
|
82
|
+
AirbrakeAPI.deployments
|
83
|
+
|
84
|
+
## Connecting to more than one account
|
85
|
+
|
86
|
+
While module-based configuration will work in most cases, if you'd like to simultaneously connect to more than one account at once, you can create instances of `AirbrakeAPI::Client` to do so:
|
67
87
|
|
68
|
-
|
69
|
-
|
88
|
+
client = AirbrakeAPI::Client.new(:account => 'myaccount', :auth_token => 'abcdefg', :secure => true)
|
89
|
+
altclient = AirbrakeAPI::Client.new(:account => 'anotheraccount', :auth_token => '123456789', :secure => false)
|
90
|
+
|
91
|
+
client.errors
|
92
|
+
|
93
|
+
altclient.projects
|
70
94
|
|
71
|
-
|
95
|
+
## Responses
|
72
96
|
|
97
|
+
If an error is returned from the API, an AirbrakeError exception will be raised. Successful responses will return a Hashie::Mash object based on the data from the response.
|
73
98
|
|
74
|
-
Contributors
|
75
|
-
------------
|
99
|
+
## Contributors
|
76
100
|
|
77
101
|
* [Matias Käkelä](https://github.com/massive) - SSL Support
|
78
102
|
* [Jordan Brough](https://github.com/jordan-brough) - Notices
|
data/airbrake-api.gemspec
CHANGED
@@ -14,9 +14,11 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.email = ['steve.agalloco@gmail.com']
|
15
15
|
s.homepage = 'https://github.com/spagalloco/airbrake-api'
|
16
16
|
|
17
|
-
s.add_dependency 'httparty', '~> 0.8.0'
|
18
17
|
s.add_dependency 'hashie', '~> 1.2'
|
19
18
|
s.add_dependency 'parallel', '~> 0.5.0'
|
19
|
+
s.add_dependency 'faraday_middleware', '~> 0.8'
|
20
|
+
s.add_dependency 'multi_xml', '~> 0.4'
|
21
|
+
s.add_dependency 'mash'
|
20
22
|
|
21
23
|
s.add_development_dependency 'rake', '~> 0.9.2'
|
22
24
|
s.add_development_dependency 'rspec', '~> 2.6.0'
|
data/lib/airbrake-api.rb
CHANGED
@@ -1,29 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
require 'httparty'
|
1
|
+
require 'airbrake-api/configuration'
|
3
2
|
|
4
3
|
module AirbrakeAPI
|
5
|
-
extend
|
6
|
-
attr_accessor :account, :auth_token, :secure
|
4
|
+
extend Configuration
|
7
5
|
|
8
6
|
class AirbrakeError < StandardError; end
|
9
|
-
|
10
|
-
def configure(options={})
|
11
|
-
@account = options[:account] if options.has_key?(:account)
|
12
|
-
@auth_token = options[:auth_token] if options.has_key?(:auth_token)
|
13
|
-
@secure = options[:secure] if options.has_key?(:secure)
|
14
|
-
end
|
15
|
-
|
16
|
-
def account_path
|
17
|
-
"#{protocol}://#{@account}.airbrake.io"
|
18
|
-
end
|
19
|
-
|
20
|
-
def protocol
|
21
|
-
secure ? "https" : "http"
|
22
|
-
end
|
23
|
-
|
24
7
|
end
|
25
8
|
|
26
|
-
require 'airbrake-api/core_extensions'
|
27
9
|
require 'airbrake-api/client'
|
28
10
|
require 'airbrake-api/error'
|
29
11
|
require 'airbrake-api/notice'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# placeholder since pre-refactor classes used AirbrakeAPI::Base
|
2
|
+
module AirbrakeAPI
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(path, options)
|
9
|
+
Client.new.get(path, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def deprecate(msg)
|
13
|
+
Kernel.warn("[Deprecation] - #{msg}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/airbrake-api/client.rb
CHANGED
@@ -1,41 +1,164 @@
|
|
1
|
+
require 'faraday_middleware'
|
2
|
+
require 'airbrake-api/middleware/scrub_response'
|
3
|
+
require 'airbrake-api/middleware/raise_server_error'
|
4
|
+
require 'airbrake-api/middleware/raise_response_error'
|
5
|
+
|
1
6
|
module AirbrakeAPI
|
2
|
-
class
|
3
|
-
include HTTParty
|
4
|
-
format :xml
|
7
|
+
class Client
|
5
8
|
|
6
|
-
|
9
|
+
PER_PAGE = 30
|
10
|
+
PARALLEL_WORKERS = 10
|
7
11
|
|
8
|
-
|
9
|
-
base_uri AirbrakeAPI.account_path
|
10
|
-
default_params :auth_token => AirbrakeAPI.auth_token
|
12
|
+
attr_accessor *AirbrakeAPI::Configuration::VALID_OPTIONS_KEYS
|
11
13
|
|
12
|
-
|
14
|
+
def initialize(options={})
|
15
|
+
attrs = AirbrakeAPI.options.merge(options)
|
16
|
+
AirbrakeAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
17
|
+
send("#{key}=", attrs[key])
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
21
|
+
# deploys
|
22
|
+
|
23
|
+
def deploys(project_id, options = {})
|
24
|
+
results = request(:get, deploys_path(project_id), options)
|
25
|
+
results.projects.respond_to?(:deploy) ? results.projects.try(:deploy) : []
|
26
|
+
end
|
27
|
+
|
28
|
+
def deploys_path(project_id)
|
29
|
+
"/projects/#{project_id}/deploys.xml"
|
30
|
+
end
|
31
|
+
|
32
|
+
# projects
|
33
|
+
def projects_path
|
34
|
+
'/data_api/v1/projects.xml'
|
35
|
+
end
|
36
|
+
|
37
|
+
def projects(options = {})
|
38
|
+
results = request(:get, projects_path, options)
|
39
|
+
results.projects.project
|
40
|
+
end
|
41
|
+
|
42
|
+
# errors
|
43
|
+
|
44
|
+
def error_path(error_id)
|
45
|
+
"/errors/#{error_id}.xml"
|
18
46
|
end
|
19
47
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
48
|
+
def errors_path
|
49
|
+
'/errors.xml'
|
50
|
+
end
|
51
|
+
|
52
|
+
def update(error, options = {})
|
53
|
+
results = request(:put, error_path(error), :body => options)
|
54
|
+
results.group
|
55
|
+
end
|
56
|
+
|
57
|
+
def error(error_id, options = {})
|
58
|
+
results = request(:get, error_path(error_id), options)
|
59
|
+
results.group || results.groups
|
60
|
+
end
|
61
|
+
|
62
|
+
def errors(options = {})
|
63
|
+
results = request(:get, errors_path, options)
|
64
|
+
results.group || results.groups
|
65
|
+
end
|
66
|
+
|
67
|
+
# notices
|
68
|
+
|
69
|
+
def notice_path(notice_id, error_id)
|
70
|
+
"/errors/#{error_id}/notices/#{notice_id}.xml"
|
71
|
+
end
|
72
|
+
|
73
|
+
def notices_path(error_id)
|
74
|
+
"/errors/#{error_id}/notices.xml"
|
75
|
+
end
|
76
|
+
|
77
|
+
def notice(notice_id, error_id, options = {})
|
78
|
+
hash = request(:get, notice_path(notice_id, error_id), options)
|
79
|
+
hash.notice
|
80
|
+
end
|
81
|
+
|
82
|
+
def notices(error_id, notice_options = {}, &block)
|
83
|
+
options = {}
|
84
|
+
notices = []
|
85
|
+
page = notice_options[:page]
|
86
|
+
page_count = 0
|
87
|
+
|
88
|
+
# a specific page is requested, only return that page
|
89
|
+
# if no page is specified, start on page 1
|
90
|
+
if page
|
91
|
+
notice_options[:pages] = 1
|
92
|
+
else
|
93
|
+
page = 1
|
24
94
|
end
|
25
95
|
|
26
|
-
|
96
|
+
while !notice_options[:pages] || (page_count + 1) <= notice_options[:pages]
|
97
|
+
options[:page] = page + page_count
|
98
|
+
hash = request(:get, notices_path(error_id), options)
|
99
|
+
|
100
|
+
batch = Parallel.map(hash.notices, :in_threads => PARALLEL_WORKERS) do |notice_stub|
|
101
|
+
notice(notice_stub.id, error_id)
|
102
|
+
end
|
103
|
+
yield batch if block_given?
|
104
|
+
batch.each{|n| notices << n }
|
105
|
+
|
106
|
+
break if batch.size < PER_PAGE
|
107
|
+
page_count += 1
|
108
|
+
end
|
109
|
+
notices
|
27
110
|
end
|
28
111
|
|
29
|
-
|
30
|
-
|
112
|
+
private
|
113
|
+
|
114
|
+
def account_path
|
115
|
+
"#{protocol}://#{@account}.airbrake.io"
|
116
|
+
end
|
117
|
+
|
118
|
+
def protocol
|
119
|
+
@secure ? "https" : "http"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Perform an HTTP request
|
123
|
+
def request(method, path, params = {}, options = {})
|
124
|
+
|
125
|
+
raise AirbrakeError.new('API Token cannot be nil') if @auth_token.nil?
|
126
|
+
raise AirbrakeError.new('Account cannot be nil') if @account.nil?
|
127
|
+
|
128
|
+
params.merge!(:auth_token => @auth_token)
|
129
|
+
|
130
|
+
response = connection(options).run_request(method, nil, nil, nil) do |request|
|
131
|
+
case method.to_sym
|
132
|
+
when :delete, :get
|
133
|
+
request.url(path, params)
|
134
|
+
when :post, :put
|
135
|
+
request.path = path
|
136
|
+
request.body = params unless params.empty?
|
137
|
+
end
|
138
|
+
end
|
139
|
+
response.body
|
140
|
+
end
|
141
|
+
|
142
|
+
def connection(options={})
|
143
|
+
default_options = {
|
144
|
+
:headers => {
|
145
|
+
:accept => 'application/xml',
|
146
|
+
:user_agent => user_agent,
|
147
|
+
},
|
148
|
+
:ssl => {:verify => false},
|
149
|
+
:url => account_path,
|
150
|
+
}
|
151
|
+
@connection ||= Faraday.new(default_options.deep_merge(connection_options)) do |builder|
|
152
|
+
builder.use Faraday::Request::UrlEncoded
|
153
|
+
builder.use AirbrakeAPI::Middleware::RaiseResponseError
|
154
|
+
builder.use FaradayMiddleware::Mashify
|
155
|
+
builder.use FaradayMiddleware::ParseXml
|
156
|
+
builder.use AirbrakeAPI::Middleware::ScrubResponse
|
157
|
+
builder.use AirbrakeAPI::Middleware::RaiseServerError
|
158
|
+
|
159
|
+
builder.adapter adapter
|
160
|
+
end
|
161
|
+
end
|
31
162
|
|
32
|
-
# airbrake sometimes returns broken xml with invalid xml tag names
|
33
|
-
# so we remove them
|
34
|
-
require 'httparty/parser'
|
35
|
-
class HTTParty::Parser
|
36
|
-
def xml
|
37
|
-
body.gsub!(/<__utmz>.*?<\/__utmz>/m,'')
|
38
|
-
body.gsub!(/<[0-9]+.*?>.*?<\/[0-9]+.*?>/m,'')
|
39
|
-
MultiXml.parse(body)
|
40
163
|
end
|
41
164
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'airbrake-api/version'
|
2
|
+
|
3
|
+
module AirbrakeAPI
|
4
|
+
module Configuration
|
5
|
+
VALID_OPTIONS_KEYS = [
|
6
|
+
:account,
|
7
|
+
:auth_token,
|
8
|
+
:secure,
|
9
|
+
:connection_options,
|
10
|
+
:adapter,
|
11
|
+
:user_agent]
|
12
|
+
|
13
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
14
|
+
|
15
|
+
DEFAULT_ADAPTER = :net_http
|
16
|
+
DEFAULT_USER_AGENT = "AirbrakeAPI Ruby Gem #{AirbrakeAPI::VERSION}"
|
17
|
+
DEFAULT_CONNECTION_OPTIONS = {}
|
18
|
+
|
19
|
+
def self.extended(base)
|
20
|
+
base.reset
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(options={})
|
24
|
+
@account = options[:account] if options.has_key?(:account)
|
25
|
+
@auth_token = options[:auth_token] if options.has_key?(:auth_token)
|
26
|
+
@secure = options[:secure] if options.has_key?(:secure)
|
27
|
+
yield self if block_given?
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def options
|
32
|
+
options = {}
|
33
|
+
VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
|
34
|
+
options
|
35
|
+
end
|
36
|
+
|
37
|
+
def account_path
|
38
|
+
"#{protocol}://#{@account}.airbrake.io"
|
39
|
+
end
|
40
|
+
|
41
|
+
def protocol
|
42
|
+
@secure ? "https" : "http"
|
43
|
+
end
|
44
|
+
|
45
|
+
def reset
|
46
|
+
@account = nil
|
47
|
+
@auth_token = nil
|
48
|
+
@secure = false
|
49
|
+
@adapter = DEFAULT_ADAPTER
|
50
|
+
@user_agent = DEFAULT_USER_AGENT
|
51
|
+
@connection_options = DEFAULT_CONNECTION_OPTIONS
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|