hydraulic_brake 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rbenv-version +1 -0
- data/.rvmrc +1 -0
- data/.yardopts +2 -0
- data/Gemfile +16 -0
- data/INSTALL +20 -0
- data/MIT-LICENSE +22 -0
- data/README.md +103 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/features/rake.feature +27 -0
- data/features/step_definitions/rake_steps.rb +17 -0
- data/features/support/matchers.rb +35 -0
- data/features/support/rake/Rakefile +61 -0
- data/features/support/terminal.rb +107 -0
- data/hydraulic_brake.gemspec +102 -0
- data/lib/hydraulic_brake/backtrace.rb +108 -0
- data/lib/hydraulic_brake/configuration.rb +242 -0
- data/lib/hydraulic_brake/notice.rb +321 -0
- data/lib/hydraulic_brake/sender.rb +128 -0
- data/lib/hydraulic_brake/version.rb +5 -0
- data/lib/hydraulic_brake.rb +148 -0
- data/lib/hydraulic_brake_tasks.rb +63 -0
- data/resources/README.md +34 -0
- data/resources/ca-bundle.crt +3376 -0
- data/script/integration_test.rb +36 -0
- data/test/airbrake_2_3.xsd +88 -0
- data/test/backtrace_test.rb +162 -0
- data/test/configuration_test.rb +178 -0
- data/test/helper.rb +239 -0
- data/test/logger_test.rb +79 -0
- data/test/notice_test.rb +324 -0
- data/test/notifier_test.rb +220 -0
- data/test/recursion_test.rb +10 -0
- data/test/sender_test.rb +288 -0
- metadata +259 -0
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p194
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3-p194@airbrake --create
|
data/.yardopts
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "builder"
|
4
|
+
|
5
|
+
group "development" do
|
6
|
+
gem "bourne", ">= 1.0"
|
7
|
+
gem "cucumber", "~> 0.10.6"
|
8
|
+
gem "fakeweb", "~> 1.3.0"
|
9
|
+
gem "jeweler"
|
10
|
+
gem "nokogiri", "~> 1.4.3.1"
|
11
|
+
gem "rake"
|
12
|
+
gem "rspec", "~> 2.6.0"
|
13
|
+
gem "shoulda", "~> 2.11.3"
|
14
|
+
gem "simplecov"
|
15
|
+
gem "yard"
|
16
|
+
end
|
data/INSTALL
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
=== Configuration
|
2
|
+
|
3
|
+
You should have something like this in config/initializers/hydraulic_brake.rb.
|
4
|
+
|
5
|
+
HydraulicBrake.configure do |config|
|
6
|
+
config.api_key = '1234567890abcdef'
|
7
|
+
end
|
8
|
+
|
9
|
+
(Please note that this configuration should be in a global configuration, and
|
10
|
+
is *not* environment-specific. HydraulicBrake is smart enough to know what
|
11
|
+
errors are caused by what environments, so your staging errors don't get mixed
|
12
|
+
in with your production errors.)
|
13
|
+
|
14
|
+
You can test that HydraulicBrake is working in your production environment by
|
15
|
+
using this rake task:
|
16
|
+
|
17
|
+
rake hydraulicbrake:test
|
18
|
+
|
19
|
+
If everything is configured properly, that task will send a notice to Airbrake
|
20
|
+
which will be visible immediately.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007 - 2012, Exceptional DBA Airbrake.io
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
HydraulicBrake
|
2
|
+
========
|
3
|
+
|
4
|
+
This is a replacement notifier gem for the [Airbrake
|
5
|
+
gem](https://github.com/airbrake/airbrake) which is used
|
6
|
+
for integrating ruby apps with [Airbrake](http://airbrake.io).
|
7
|
+
|
8
|
+
### Transitioning from Airbrake to HydraulicBrake
|
9
|
+
|
10
|
+
HydraulicBrake is a lighter weight alternative to the [Airbrake
|
11
|
+
gem](https://github.com/airbrake/airbrake) and takes a different design
|
12
|
+
approach. HydraulicBrake doesn't attempt to integrate with any
|
13
|
+
frameworks and has few dependencies. HydraulicBrake doesn't change
|
14
|
+
anything outside its own namespace. It doesn't do any automatic
|
15
|
+
exception handling or configuration.
|
16
|
+
|
17
|
+
Configuration
|
18
|
+
-------------
|
19
|
+
|
20
|
+
Configure HydraulicBrake when your app starts with a configuration block
|
21
|
+
like this one:
|
22
|
+
|
23
|
+
HydraulicBrake.configure do |config|
|
24
|
+
config.host = "api.airbrake.io"
|
25
|
+
config.port = "443"
|
26
|
+
config.secure = true
|
27
|
+
config.environment_name = "staging"
|
28
|
+
config.api_key = "<api-key-from-your-airbrake-server>"
|
29
|
+
end
|
30
|
+
|
31
|
+
Usage
|
32
|
+
-----
|
33
|
+
|
34
|
+
Wherever you want to notify an Airbrake server, just call
|
35
|
+
HydraulicBrake#notify
|
36
|
+
|
37
|
+
begin
|
38
|
+
params = {
|
39
|
+
# params that you pass to a method that can throw an exception
|
40
|
+
}
|
41
|
+
my_unpredicable_method(params)
|
42
|
+
rescue => e
|
43
|
+
HydraulicBrake.notify(
|
44
|
+
:error_class => "Special Error",
|
45
|
+
:error_message => "Special Error: #{e.message}",
|
46
|
+
:parameters => params
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
HydraulicBrake merges the hash you pass with these default options:
|
51
|
+
|
52
|
+
{
|
53
|
+
:api_key => HydraulicBrake.api_key,
|
54
|
+
:error_message => 'Notification',
|
55
|
+
:backtrace => caller,
|
56
|
+
:parameters => {},
|
57
|
+
:session => {}
|
58
|
+
}
|
59
|
+
|
60
|
+
You can override any of those parameters.
|
61
|
+
|
62
|
+
Async Notifications
|
63
|
+
-------------------
|
64
|
+
|
65
|
+
HydraulicBrake doesn't provide anything for async notifications, and
|
66
|
+
that's a good thing. Just wrap your calls to Airbrake#notify in the
|
67
|
+
async library of your choice.
|
68
|
+
|
69
|
+
Proxy Support
|
70
|
+
-------------
|
71
|
+
|
72
|
+
The notifier supports using a proxy, if your server is not able to
|
73
|
+
directly reach the Airbrake servers. To configure the proxy settings,
|
74
|
+
added the following information to your HydraulicBrake configuration
|
75
|
+
block.
|
76
|
+
|
77
|
+
HydraulicBrake.configure do |config|
|
78
|
+
config.proxy_host = proxy.host.com
|
79
|
+
config.proxy_port = 4038
|
80
|
+
config.proxy_user = foo # optional
|
81
|
+
config.proxy_pass = bar # optional
|
82
|
+
|
83
|
+
Logging
|
84
|
+
------------
|
85
|
+
|
86
|
+
HydraulicBrake uses STDOUT by default. If you don't like HydraulicBrake
|
87
|
+
scribbling to your standard output, just pass another `Logger` instance
|
88
|
+
inside your configuration:
|
89
|
+
|
90
|
+
HydraulicBrake.configure do |config|
|
91
|
+
...
|
92
|
+
config.logger = Logger.new("path/to/your/log/file")
|
93
|
+
end
|
94
|
+
|
95
|
+
Credits
|
96
|
+
-------
|
97
|
+
|
98
|
+
Thank you to all [the airbrake contributors](https://github.com/airbrake/airbrake/contributors)!
|
99
|
+
|
100
|
+
License
|
101
|
+
-------
|
102
|
+
|
103
|
+
Airbrake is Copyright © 2008-2012 Airbrake. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
gem.name = "hydraulic_brake"
|
17
|
+
gem.homepage = "http://github.com/stevecrozz/hydraulic_brake"
|
18
|
+
gem.license = "MIT"
|
19
|
+
gem.summary = "Simple Airbrake client"
|
20
|
+
gem.description = %Q{Sends notifications to an Airbrake server}
|
21
|
+
gem.email = "stevecrozz@gmail.com"
|
22
|
+
gem.authors = ["Stephen Crosby"]
|
23
|
+
gem.require_paths = ["lib"]
|
24
|
+
end
|
25
|
+
Jeweler::RubygemsDotOrgTasks.new
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'yard'
|
35
|
+
YARD::Rake::YardocTask.new do |t|
|
36
|
+
t.files = ['lib/**/*.rb']
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: Use the Gem to catch errors in a Rake application
|
2
|
+
Background:
|
3
|
+
Given I have built and installed the "airbrake" gem
|
4
|
+
|
5
|
+
Scenario: Catching exceptions in Rake
|
6
|
+
When I run rake with airbrake
|
7
|
+
Then Airbrake should catch the exception
|
8
|
+
|
9
|
+
Scenario: Falling back to default handler before Airbrake is configured
|
10
|
+
When I run rake with airbrake not yet configured
|
11
|
+
Then Airbrake should not catch the exception
|
12
|
+
|
13
|
+
Scenario: Disabling Rake exception catcher
|
14
|
+
When I run rake with airbrake disabled
|
15
|
+
Then Airbrake should not catch the exception
|
16
|
+
|
17
|
+
Scenario: Autodetect, running from terminal
|
18
|
+
When I run rake with airbrake autodetect from terminal
|
19
|
+
Then Airbrake should not catch the exception
|
20
|
+
|
21
|
+
Scenario: Autodetect, not running from terminal
|
22
|
+
When I run rake with airbrake autodetect not from terminal
|
23
|
+
Then Airbrake should catch the exception
|
24
|
+
|
25
|
+
Scenario: Sending the correct component name
|
26
|
+
When I run rake with airbrake
|
27
|
+
Then Airbrake should send the rake command line as the component name
|
@@ -0,0 +1,17 @@
|
|
1
|
+
When /I run rake with (.+)/ do |command|
|
2
|
+
@rake_command = "rake #{command.gsub(' ','_')}"
|
3
|
+
@rake_result = `cd features/support/rake && GEM_HOME=#{BUILT_GEM_ROOT} #{@rake_command} 2>&1`
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /Airbrake should (|not) ?catch the exception/ do |condition|
|
7
|
+
if condition=='not'
|
8
|
+
@rake_result.should_not =~ /^airbrake/
|
9
|
+
else
|
10
|
+
@rake_result.should =~ /^airbrake/
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /Airbrake should send the rake command line as the component name/ do
|
15
|
+
component = @rake_result.match(/^airbrake (.*)$/)[1]
|
16
|
+
component.should == @rake_command
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RSpec::Matchers.define :have_content do |xpath, content|
|
2
|
+
match do |document|
|
3
|
+
@elements = document.search(xpath)
|
4
|
+
|
5
|
+
if @elements.empty?
|
6
|
+
false
|
7
|
+
else
|
8
|
+
element_with_content = document.at("#{xpath}[contains(.,'#{content}')]")
|
9
|
+
|
10
|
+
if element_with_content.nil?
|
11
|
+
@found = @elements.collect { |element| element.content }
|
12
|
+
|
13
|
+
false
|
14
|
+
else
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
failure_message_for_should do |document|
|
21
|
+
if @elements.empty?
|
22
|
+
"In XML:\n#{document}\nNo element at #{xpath}"
|
23
|
+
else
|
24
|
+
"In XML:\n#{document}\nGot content #{@found.inspect} at #{xpath} instead of #{content.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
failure_message_for_should_not do |document|
|
29
|
+
unless @elements.empty?
|
30
|
+
"In XML:\n#{document}\nExpcted no content #{content.inspect} at #{xpath}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
World(RSpec::Matchers)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# A test harness for RakeHandler
|
2
|
+
#
|
3
|
+
require 'rake'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'hydraulic_brake'
|
6
|
+
require 'hydraulic_brake/rake_handler'
|
7
|
+
|
8
|
+
HydraulicBrake.configure do |c|
|
9
|
+
end
|
10
|
+
|
11
|
+
# Should catch exception
|
12
|
+
task :hydraulic_brake do
|
13
|
+
HydraulicBrake.configuration.rescue_rake_exceptions = true
|
14
|
+
stub_tty_output(true)
|
15
|
+
raise_exception
|
16
|
+
end
|
17
|
+
|
18
|
+
# Should not catch exception
|
19
|
+
task :hydraulic_brake_disabled do
|
20
|
+
HydraulicBrake.configuration.rescue_rake_exceptions = false
|
21
|
+
stub_tty_output(true)
|
22
|
+
raise_exception
|
23
|
+
end
|
24
|
+
|
25
|
+
# Should not catch exception as tty_output is true
|
26
|
+
task :hydraulic_brake_autodetect_from_terminal do
|
27
|
+
HydraulicBrake.configuration.rescue_rake_exceptions = nil
|
28
|
+
stub_tty_output(true)
|
29
|
+
raise_exception
|
30
|
+
end
|
31
|
+
|
32
|
+
# Should catch exception as tty_output is false
|
33
|
+
task :hydraulic_brake_autodetect_not_from_terminal do
|
34
|
+
HydraulicBrake.configuration.rescue_rake_exceptions = nil
|
35
|
+
stub_tty_output(false)
|
36
|
+
raise_exception
|
37
|
+
end
|
38
|
+
|
39
|
+
task :hydraulic_brake_not_yet_configured do
|
40
|
+
HydraulicBrake.configuration.rescue_rake_exceptions = true
|
41
|
+
stub_tty_output(true)
|
42
|
+
stub_empty_sender
|
43
|
+
raise_exception
|
44
|
+
end
|
45
|
+
|
46
|
+
def stub_empty_sender
|
47
|
+
HydraulicBrake.sender = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def stub_tty_output(value)
|
51
|
+
Rake.application.instance_eval do
|
52
|
+
@tty_output_stub = value
|
53
|
+
def tty_output?
|
54
|
+
@tty_output_stub
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def raise_exception
|
60
|
+
raise 'TEST'
|
61
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
Before do
|
4
|
+
@terminal = Terminal.new
|
5
|
+
end
|
6
|
+
|
7
|
+
After do |story|
|
8
|
+
if story.failed?
|
9
|
+
# puts @terminal.output
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Terminal
|
14
|
+
attr_reader :output, :status
|
15
|
+
attr_accessor :environment_variables, :invoke_heroku_rake_tasks_locally
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@cwd = FileUtils.pwd
|
19
|
+
@output = ""
|
20
|
+
@status = 0
|
21
|
+
@logger = Logger.new(File.join(TEMP_DIR, 'terminal.log'))
|
22
|
+
|
23
|
+
@invoke_heroku_rake_tasks_locally = false
|
24
|
+
|
25
|
+
@environment_variables = {
|
26
|
+
"GEM_HOME" => LOCAL_GEM_ROOT,
|
27
|
+
"GEM_PATH" => "#{LOCAL_GEM_ROOT}:#{BUILT_GEM_ROOT}",
|
28
|
+
"PATH" => "#{gem_bin_path}:#{ENV['PATH']}"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def cd(directory)
|
33
|
+
@cwd = directory
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(command)
|
37
|
+
command = optionally_invoke_heroku_rake_tasks_locally(command)
|
38
|
+
|
39
|
+
output << "#{command}\n"
|
40
|
+
FileUtils.cd(@cwd) do
|
41
|
+
# The ; forces ruby to shell out so the env settings work right
|
42
|
+
cmdline = "#{environment_settings} #{command} 2>&1 ; "
|
43
|
+
logger.debug(cmdline)
|
44
|
+
result = `#{cmdline}`
|
45
|
+
logger.debug(result)
|
46
|
+
output << result
|
47
|
+
end
|
48
|
+
@status = $?
|
49
|
+
end
|
50
|
+
|
51
|
+
def optionally_invoke_heroku_rake_tasks_locally(command)
|
52
|
+
if invoke_heroku_rake_tasks_locally
|
53
|
+
command.sub(/^heroku /, '')
|
54
|
+
else
|
55
|
+
command
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def echo(string)
|
60
|
+
logger.debug(string)
|
61
|
+
end
|
62
|
+
|
63
|
+
def flush!
|
64
|
+
@output = ""
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_and_install_gem(gemspec)
|
68
|
+
pkg_dir = File.join(TEMP_DIR, 'pkg')
|
69
|
+
FileUtils.mkdir_p(pkg_dir)
|
70
|
+
output = `gem build #{gemspec} 2>&1`
|
71
|
+
gem_file = Dir.glob("*.gem").first
|
72
|
+
unless gem_file
|
73
|
+
raise "Gem didn't build:\n#{output}"
|
74
|
+
end
|
75
|
+
target = File.join(pkg_dir, gem_file)
|
76
|
+
FileUtils.mv(gem_file, target)
|
77
|
+
install_gem_to(LOCAL_GEM_ROOT, target)
|
78
|
+
end
|
79
|
+
|
80
|
+
def install_gem(gem)
|
81
|
+
install_gem_to(LOCAL_GEM_ROOT, gem)
|
82
|
+
end
|
83
|
+
|
84
|
+
def uninstall_gem(gem)
|
85
|
+
`gem uninstall -i #{LOCAL_GEM_ROOT} #{gem}`
|
86
|
+
end
|
87
|
+
|
88
|
+
def prepend_path(path)
|
89
|
+
@environment_variables['PATH'] = path + ":" + @environment_variables['PATH']
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def install_gem_to(root, gem)
|
95
|
+
`gem install -i #{root} --no-ri --no-rdoc #{gem}`
|
96
|
+
end
|
97
|
+
|
98
|
+
def environment_settings
|
99
|
+
@environment_variables.map { |key, value| "#{key}=#{value}" }.join(' ')
|
100
|
+
end
|
101
|
+
|
102
|
+
def gem_bin_path
|
103
|
+
File.join(LOCAL_GEM_ROOT, "bin")
|
104
|
+
end
|
105
|
+
|
106
|
+
attr_reader :logger
|
107
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "hydraulic_brake"
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Stephen Crosby"]
|
12
|
+
s.date = "2013-07-14"
|
13
|
+
s.description = "Sends notifications to an Airbrake server"
|
14
|
+
s.email = "stevecrozz@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".rbenv-version",
|
20
|
+
".rvmrc",
|
21
|
+
".yardopts",
|
22
|
+
"Gemfile",
|
23
|
+
"INSTALL",
|
24
|
+
"MIT-LICENSE",
|
25
|
+
"README.md",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"features/rake.feature",
|
29
|
+
"features/step_definitions/rake_steps.rb",
|
30
|
+
"features/support/matchers.rb",
|
31
|
+
"features/support/rake/Rakefile",
|
32
|
+
"features/support/terminal.rb",
|
33
|
+
"hydraulic_brake.gemspec",
|
34
|
+
"lib/hydraulic_brake.rb",
|
35
|
+
"lib/hydraulic_brake/backtrace.rb",
|
36
|
+
"lib/hydraulic_brake/configuration.rb",
|
37
|
+
"lib/hydraulic_brake/notice.rb",
|
38
|
+
"lib/hydraulic_brake/sender.rb",
|
39
|
+
"lib/hydraulic_brake/version.rb",
|
40
|
+
"lib/hydraulic_brake_tasks.rb",
|
41
|
+
"resources/README.md",
|
42
|
+
"resources/ca-bundle.crt",
|
43
|
+
"script/integration_test.rb",
|
44
|
+
"test/airbrake_2_3.xsd",
|
45
|
+
"test/backtrace_test.rb",
|
46
|
+
"test/configuration_test.rb",
|
47
|
+
"test/helper.rb",
|
48
|
+
"test/logger_test.rb",
|
49
|
+
"test/notice_test.rb",
|
50
|
+
"test/notifier_test.rb",
|
51
|
+
"test/recursion_test.rb",
|
52
|
+
"test/sender_test.rb"
|
53
|
+
]
|
54
|
+
s.homepage = "http://github.com/stevecrozz/hydraulic_brake"
|
55
|
+
s.licenses = ["MIT"]
|
56
|
+
s.require_paths = ["lib"]
|
57
|
+
s.rubygems_version = "1.8.23"
|
58
|
+
s.summary = "Simple Airbrake client"
|
59
|
+
|
60
|
+
if s.respond_to? :specification_version then
|
61
|
+
s.specification_version = 3
|
62
|
+
|
63
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
64
|
+
s.add_runtime_dependency(%q<builder>, [">= 0"])
|
65
|
+
s.add_development_dependency(%q<bourne>, [">= 1.0"])
|
66
|
+
s.add_development_dependency(%q<cucumber>, ["~> 0.10.6"])
|
67
|
+
s.add_development_dependency(%q<fakeweb>, ["~> 1.3.0"])
|
68
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
69
|
+
s.add_development_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
|
70
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
71
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
72
|
+
s.add_development_dependency(%q<shoulda>, ["~> 2.11.3"])
|
73
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
74
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<builder>, [">= 0"])
|
77
|
+
s.add_dependency(%q<bourne>, [">= 1.0"])
|
78
|
+
s.add_dependency(%q<cucumber>, ["~> 0.10.6"])
|
79
|
+
s.add_dependency(%q<fakeweb>, ["~> 1.3.0"])
|
80
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
81
|
+
s.add_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
|
82
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
83
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
84
|
+
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
85
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
86
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
87
|
+
end
|
88
|
+
else
|
89
|
+
s.add_dependency(%q<builder>, [">= 0"])
|
90
|
+
s.add_dependency(%q<bourne>, [">= 1.0"])
|
91
|
+
s.add_dependency(%q<cucumber>, ["~> 0.10.6"])
|
92
|
+
s.add_dependency(%q<fakeweb>, ["~> 1.3.0"])
|
93
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
94
|
+
s.add_dependency(%q<nokogiri>, ["~> 1.4.3.1"])
|
95
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
96
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
97
|
+
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
98
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
99
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module HydraulicBrake
|
2
|
+
# Front end to parsing the backtrace for each notice
|
3
|
+
class Backtrace
|
4
|
+
|
5
|
+
# Handles backtrace parsing line by line
|
6
|
+
class Line
|
7
|
+
|
8
|
+
# regexp (optionnally allowing leading X: for windows support)
|
9
|
+
INPUT_FORMAT = %r{^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$}.freeze
|
10
|
+
|
11
|
+
# The file portion of the line (such as app/models/user.rb)
|
12
|
+
attr_reader :file
|
13
|
+
|
14
|
+
# The line number portion of the line
|
15
|
+
attr_reader :number
|
16
|
+
|
17
|
+
# The method of the line (such as index)
|
18
|
+
attr_reader :method
|
19
|
+
|
20
|
+
# Parses a single line of a given backtrace
|
21
|
+
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
22
|
+
# @return [Line] The parsed backtrace line
|
23
|
+
def self.parse(unparsed_line)
|
24
|
+
_, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
|
25
|
+
new(file, number, method)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(file, number, method)
|
29
|
+
self.file = file
|
30
|
+
self.number = number
|
31
|
+
self.method = method
|
32
|
+
end
|
33
|
+
|
34
|
+
# Reconstructs the line in a readable fashion
|
35
|
+
def to_s
|
36
|
+
"#{file}:#{number}:in `#{method}'"
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(other)
|
40
|
+
to_s == other.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
"<Line:#{to_s}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_writer :file, :number, :method
|
50
|
+
end
|
51
|
+
|
52
|
+
# holder for an Array of Backtrace::Line instances
|
53
|
+
attr_reader :lines
|
54
|
+
|
55
|
+
def self.parse(ruby_backtrace, opts = {})
|
56
|
+
ruby_lines = split_multiline_backtrace(ruby_backtrace)
|
57
|
+
|
58
|
+
filters = opts[:filters] || []
|
59
|
+
filtered_lines = ruby_lines.to_a.map do |line|
|
60
|
+
filters.inject(line) do |line, proc|
|
61
|
+
proc.call(line)
|
62
|
+
end
|
63
|
+
end.compact
|
64
|
+
|
65
|
+
lines = filtered_lines.collect do |unparsed_line|
|
66
|
+
Line.parse(unparsed_line)
|
67
|
+
end
|
68
|
+
|
69
|
+
instance = new(lines)
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(lines)
|
73
|
+
self.lines = lines
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
"<Backtrace: " + lines.collect { |line| line.inspect }.join(", ") + ">"
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_s
|
81
|
+
content = []
|
82
|
+
lines.each do |line|
|
83
|
+
content << line
|
84
|
+
end
|
85
|
+
content.join("\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
def ==(other)
|
89
|
+
if other.respond_to?(:lines)
|
90
|
+
lines == other.lines
|
91
|
+
else
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
attr_writer :lines
|
99
|
+
|
100
|
+
def self.split_multiline_backtrace(backtrace)
|
101
|
+
if backtrace.to_a.size == 1
|
102
|
+
backtrace.to_a.first.split(/\n\s*/)
|
103
|
+
else
|
104
|
+
backtrace
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|