honeybadger 1.1.0 → 1.2.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/Gemfile.lock +11 -11
- data/README.md +26 -5
- data/Rakefile +9 -0
- data/SUPPORTED_RAILS_VERSIONS +11 -0
- data/features/rails.feature +11 -0
- data/features/step_definitions/rails_application_steps.rb +2 -2
- data/generators/honeybadger/honeybadger_generator.rb +1 -1
- data/honeybadger.gemspec +2 -2
- data/lib/honeybadger.rb +1 -1
- data/lib/honeybadger/backtrace.rb +54 -18
- data/lib/honeybadger/configuration.rb +10 -2
- data/lib/honeybadger/notice.rb +37 -4
- data/lib/honeybadger/rails/controller_methods.rb +13 -1
- data/lib/honeybadger/rails/middleware/exceptions_catcher.rb +1 -1
- data/lib/honeybadger/shared_tasks.rb +1 -1
- data/lib/honeybadger_tasks.rb +7 -2
- data/lib/rails/generators/honeybadger/honeybadger_generator.rb +1 -1
- data/test/unit/backtrace_test.rb +61 -0
- data/test/unit/capistrano_test.rb +1 -1
- data/test/unit/configuration_test.rb +3 -0
- data/test/unit/honeybadger_tasks_test.rb +2 -2
- data/test/unit/notice_test.rb +65 -19
- data/test/unit/rails/action_controller_catcher_test.rb +24 -0
- metadata +2 -2
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
honeybadger (1.
|
4
|
+
honeybadger (1.2.0)
|
5
5
|
activesupport
|
6
6
|
json
|
7
7
|
|
@@ -23,7 +23,7 @@ GEM
|
|
23
23
|
net-sftp (>= 2.0.0)
|
24
24
|
net-ssh (>= 2.0.14)
|
25
25
|
net-ssh-gateway (>= 1.1.0)
|
26
|
-
coderay (1.0.
|
26
|
+
coderay (1.0.7)
|
27
27
|
cucumber (0.10.7)
|
28
28
|
builder (>= 2.1.2)
|
29
29
|
diff-lcs (>= 1.1.2)
|
@@ -35,7 +35,7 @@ GEM
|
|
35
35
|
ffi (1.0.11)
|
36
36
|
gherkin (2.4.21)
|
37
37
|
json (>= 1.4.6)
|
38
|
-
guard (1.2.
|
38
|
+
guard (1.2.3)
|
39
39
|
listen (>= 0.4.2)
|
40
40
|
thor (>= 0.14.6)
|
41
41
|
guard-test (0.5.0)
|
@@ -43,12 +43,12 @@ GEM
|
|
43
43
|
test-unit (~> 2.2)
|
44
44
|
highline (1.6.13)
|
45
45
|
json (1.7.3)
|
46
|
-
listen (0.4.
|
46
|
+
listen (0.4.7)
|
47
47
|
rb-fchange (~> 0.0.5)
|
48
48
|
rb-fsevent (~> 0.9.1)
|
49
49
|
rb-inotify (~> 0.8.8)
|
50
50
|
metaclass (0.0.1)
|
51
|
-
method_source (0.
|
51
|
+
method_source (0.8)
|
52
52
|
mocha (0.10.5)
|
53
53
|
metaclass (~> 0.0.1)
|
54
54
|
multi_json (1.3.6)
|
@@ -59,10 +59,10 @@ GEM
|
|
59
59
|
net-ssh (2.5.2)
|
60
60
|
net-ssh-gateway (1.1.0)
|
61
61
|
net-ssh (>= 1.99.1)
|
62
|
-
pry (0.9.
|
62
|
+
pry (0.9.10)
|
63
63
|
coderay (~> 1.0.5)
|
64
|
-
method_source (~> 0.
|
65
|
-
slop (
|
64
|
+
method_source (~> 0.8)
|
65
|
+
slop (~> 3.3.1)
|
66
66
|
rack (1.1.3)
|
67
67
|
rake (0.9.2.2)
|
68
68
|
rb-fchange (0.0.5)
|
@@ -85,10 +85,10 @@ GEM
|
|
85
85
|
multi_json (~> 1.0)
|
86
86
|
simplecov-html (~> 0.5.3)
|
87
87
|
simplecov-html (0.5.3)
|
88
|
-
slop (
|
88
|
+
slop (3.3.2)
|
89
89
|
term-ansicolor (1.0.7)
|
90
|
-
test-unit (2.5.
|
91
|
-
thor (0.15.
|
90
|
+
test-unit (2.5.1)
|
91
|
+
thor (0.15.4)
|
92
92
|
|
93
93
|
PLATFORMS
|
94
94
|
ruby
|
data/README.md
CHANGED
@@ -14,8 +14,12 @@ Add the Honeybadger gem to your gemfile:
|
|
14
14
|
|
15
15
|
gem 'honeybadger'
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
Then generate the initializer:
|
18
|
+
|
19
|
+
rails generate honeybadger --api-key <Your Api Key>
|
20
|
+
|
21
|
+
If you prefer to manually create the initializer, that's simple enough.
|
22
|
+
Just put the code below in config/initializers/honeybadger.rb
|
19
23
|
|
20
24
|
# Uncomment the following line if running lower than Rails 3.2
|
21
25
|
# require 'honeybadger/rails'
|
@@ -30,7 +34,7 @@ That's it!
|
|
30
34
|
Add the honeybadger gem to your app. In config/environment.rb:
|
31
35
|
|
32
36
|
config.gem 'honeybadger'
|
33
|
-
|
37
|
+
|
34
38
|
or if you are using bundler:
|
35
39
|
|
36
40
|
gem 'honeybadger', :require => 'honeybadger/rails'
|
@@ -67,7 +71,7 @@ middleware:
|
|
67
71
|
app = Rack::Builder.app do
|
68
72
|
run lambda { |env| raise "Rack down" }
|
69
73
|
end
|
70
|
-
|
74
|
+
|
71
75
|
use Honeybadger::Rack
|
72
76
|
run app
|
73
77
|
|
@@ -90,7 +94,7 @@ Using honeybadger in a Sinatra app is just like a Rack app:
|
|
90
94
|
|
91
95
|
## Usage
|
92
96
|
|
93
|
-
For the most part, Honeybadger works for itself.
|
97
|
+
For the most part, Honeybadger works for itself.
|
94
98
|
|
95
99
|
It intercepts the exception middleware calls, sends notifications and continues the middleware call chain.
|
96
100
|
|
@@ -120,6 +124,23 @@ this rake task (from RAILS_ROOT):
|
|
120
124
|
If everything is configured properly, that task will send a notice to Honeybadger
|
121
125
|
which will be visible immediately.
|
122
126
|
|
127
|
+
## User Tracking
|
128
|
+
|
129
|
+
Honeybadger will automatically try to associate errors and notices with the current user.
|
130
|
+
|
131
|
+
By default, it tries to call `current_user` when rescuing exceptions in ActionController.
|
132
|
+
If you want to use a different method, you may do so in the honeybadger initializer:
|
133
|
+
|
134
|
+
Honeybadger.configure do |config|
|
135
|
+
...
|
136
|
+
# The current user method to call for errors rescued in ActionController
|
137
|
+
config.current_user_method = :a_controller_method_which_returns_the_user
|
138
|
+
end
|
139
|
+
|
140
|
+
Honeybadger assumes that the object returned by `current_user` will respond to `#id`,
|
141
|
+
and will optionally include the user's email address if the user object also responds
|
142
|
+
to `#email`.
|
143
|
+
|
123
144
|
## Going beyond exceptions
|
124
145
|
|
125
146
|
You can also pass a hash to `Honeybadger.notify` method and store whatever you want,
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
require 'date'
|
4
|
+
require 'json'
|
4
5
|
begin
|
5
6
|
require 'cucumber/rake/task'
|
6
7
|
rescue LoadError
|
@@ -193,6 +194,14 @@ namespace :cucumber do
|
|
193
194
|
end
|
194
195
|
end
|
195
196
|
|
197
|
+
desc "Update supported versions: Run this to pull down latest rails versions from rubygems"
|
198
|
+
task :update_supported_versions do
|
199
|
+
down_to = Gem::Version.new('3.0.0')
|
200
|
+
versions = JSON.parse `curl https://rubygems.org/api/v1/versions/rails.json 2> /dev/null`
|
201
|
+
supported_versions = versions.map { |v| Gem::Version.new(v['number']) }.reject { |v| v < down_to || v.prerelease? }.sort
|
202
|
+
`echo '#{supported_versions.join("\n")}' > SUPPORTED_RAILS_VERSIONS`
|
203
|
+
end
|
204
|
+
|
196
205
|
#############################################################################
|
197
206
|
#
|
198
207
|
# Packaging tasks
|
data/SUPPORTED_RAILS_VERSIONS
CHANGED
@@ -11,11 +11,20 @@
|
|
11
11
|
3.0.10
|
12
12
|
3.0.11
|
13
13
|
3.0.12
|
14
|
+
3.0.13
|
15
|
+
3.0.14
|
16
|
+
3.0.15
|
17
|
+
3.0.16
|
18
|
+
3.0.17
|
14
19
|
3.1.0
|
15
20
|
3.1.1
|
16
21
|
3.1.2
|
17
22
|
3.1.3
|
18
23
|
3.1.4
|
24
|
+
3.1.5
|
25
|
+
3.1.6
|
26
|
+
3.1.7
|
27
|
+
3.1.8
|
19
28
|
3.2.0
|
20
29
|
3.2.1
|
21
30
|
3.2.2
|
@@ -23,3 +32,5 @@
|
|
23
32
|
3.2.4
|
24
33
|
3.2.5
|
25
34
|
3.2.6
|
35
|
+
3.2.7
|
36
|
+
3.2.8
|
data/features/rails.feature
CHANGED
@@ -199,6 +199,17 @@ Feature: Install the Gem in a Rails application
|
|
199
199
|
And I perform a request to "http://example.com:123/test/index?param=value"
|
200
200
|
Then I should receive a Honeybadger notification
|
201
201
|
|
202
|
+
Scenario: Notify honeybadger within a metal controller
|
203
|
+
When I configure the Honeybadger shim
|
204
|
+
And I configure usage of Honeybadger
|
205
|
+
And I define a metal response for "TestController#index":
|
206
|
+
"""
|
207
|
+
raise RuntimeError, "some message"
|
208
|
+
"""
|
209
|
+
And I route "/test/index" to "test#index"
|
210
|
+
And I perform a request to "http://example.com:123/test/index?param=value"
|
211
|
+
Then I should receive a Honeybadger notification
|
212
|
+
|
202
213
|
Scenario: Reporting 404s
|
203
214
|
When I configure the Honeybadger shim
|
204
215
|
And I configure usage of Honeybadger
|
@@ -195,12 +195,12 @@ When /^I install the "([^\"]*)" plugin$/ do |plugin_name|
|
|
195
195
|
FileUtils.mkdir_p("#{rails_root}/vendor/plugins/#{plugin_name}")
|
196
196
|
end
|
197
197
|
|
198
|
-
When /^I define a response for "([^\"]*)":$/ do |controller_and_action, definition|
|
198
|
+
When /^I define a( metal)? response for "([^\"]*)":$/ do |metal, controller_and_action, definition|
|
199
199
|
controller_class_name, action = controller_and_action.split('#')
|
200
200
|
controller_name = controller_class_name.underscore
|
201
201
|
controller_file_name = File.join(rails_root, 'app', 'controllers', "#{controller_name}.rb")
|
202
202
|
File.open(controller_file_name, "w") do |file|
|
203
|
-
file.puts "class #{controller_class_name} < ApplicationController"
|
203
|
+
file.puts "class #{controller_class_name} < #{ metal ? 'ActionController::Metal' : 'ApplicationController'}"
|
204
204
|
file.puts "def consider_all_requests_local; false; end"
|
205
205
|
file.puts "def local_request?; false; end"
|
206
206
|
file.puts "def #{action}"
|
@@ -66,7 +66,7 @@ class HoneybadgerGenerator < Rails::Generator::Base
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def heroku_api_key
|
69
|
-
heroku_var("(
|
69
|
+
heroku_var("(honeybadger)_api_key",options[:app]).split.find {|x| x unless x.blank?}
|
70
70
|
end
|
71
71
|
|
72
72
|
def heroku?
|
data/honeybadger.gemspec
CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.rubygems_version = '1.3.5'
|
5
5
|
|
6
6
|
s.name = 'honeybadger'
|
7
|
-
s.version = '1.
|
8
|
-
s.date = '2012-
|
7
|
+
s.version = '1.2.0'
|
8
|
+
s.date = '2012-09-21'
|
9
9
|
|
10
10
|
s.summary = "Error reports you can be happy about."
|
11
11
|
s.description = "Make managing application errors a more pleasant experience."
|
data/lib/honeybadger.rb
CHANGED
@@ -16,25 +16,42 @@ module Honeybadger
|
|
16
16
|
# Public: The method of the line (such as index)
|
17
17
|
attr_reader :method
|
18
18
|
|
19
|
+
# Public: Filtered representations
|
20
|
+
attr_reader :filtered_file, :filtered_number, :filtered_method
|
21
|
+
|
19
22
|
# Public: Parses a single line of a given backtrace
|
20
23
|
#
|
21
24
|
# unparsed_line - The raw line from +caller+ or some backtrace
|
22
25
|
#
|
23
26
|
# Returns the parsed backtrace line
|
24
|
-
def self.parse(unparsed_line)
|
25
|
-
|
26
|
-
|
27
|
+
def self.parse(unparsed_line, opts = {})
|
28
|
+
filters = opts[:filters] || []
|
29
|
+
filtered_line = filters.inject(unparsed_line) do |line, proc|
|
30
|
+
proc.call(line)
|
31
|
+
end
|
32
|
+
|
33
|
+
if filtered_line
|
34
|
+
_, file, number, method = unparsed_line.match(INPUT_FORMAT).to_a
|
35
|
+
_, *filtered_args = filtered_line.match(INPUT_FORMAT).to_a
|
36
|
+
new(file, number, method, *filtered_args)
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
27
40
|
end
|
28
41
|
|
29
|
-
def initialize(file, number, method
|
30
|
-
|
31
|
-
self.
|
32
|
-
self.
|
42
|
+
def initialize(file, number, method, filtered_file = file,
|
43
|
+
filtered_number = number, filtered_method = method)
|
44
|
+
self.filtered_file = filtered_file
|
45
|
+
self.filtered_number = filtered_number
|
46
|
+
self.filtered_method = filtered_method
|
47
|
+
self.file = file
|
48
|
+
self.number = number
|
49
|
+
self.method = method
|
33
50
|
end
|
34
51
|
|
35
52
|
# Public: Reconstructs the line in a readable fashion
|
36
53
|
def to_s
|
37
|
-
"#{
|
54
|
+
"#{filtered_file}:#{filtered_number}:in `#{filtered_method}'"
|
38
55
|
end
|
39
56
|
|
40
57
|
def ==(other)
|
@@ -45,9 +62,35 @@ module Honeybadger
|
|
45
62
|
"<Line:#{to_s}>"
|
46
63
|
end
|
47
64
|
|
65
|
+
# Public: An excerpt from the source file, lazily loaded to preserve
|
66
|
+
# performance
|
67
|
+
def source(radius = 2)
|
68
|
+
@source ||= get_source(file, number, radius)
|
69
|
+
end
|
70
|
+
|
48
71
|
private
|
49
72
|
|
50
|
-
attr_writer :file, :number, :method
|
73
|
+
attr_writer :file, :number, :method, :filtered_file, :filtered_number, :filtered_method
|
74
|
+
|
75
|
+
# Private: Open source file and read line(s)
|
76
|
+
#
|
77
|
+
# Returns an array of line(s) from source file
|
78
|
+
def get_source(file, number, radius = 2)
|
79
|
+
if file && File.exists?(file)
|
80
|
+
before = after = radius
|
81
|
+
start = (number.to_i - 1) - before
|
82
|
+
start = 0 and before = 1 if start <= 0
|
83
|
+
duration = before + 1 + after
|
84
|
+
|
85
|
+
l = 0
|
86
|
+
File.open(file) do |f|
|
87
|
+
start.times { f.gets ; l += 1 }
|
88
|
+
return Hash[duration.times.map { (line = f.gets) ? [(l += 1), line] : nil }.compact]
|
89
|
+
end
|
90
|
+
else
|
91
|
+
{}
|
92
|
+
end
|
93
|
+
end
|
51
94
|
end
|
52
95
|
|
53
96
|
# Public: holder for an Array of Backtrace::Line instances
|
@@ -56,17 +99,10 @@ module Honeybadger
|
|
56
99
|
def self.parse(ruby_backtrace, opts = {})
|
57
100
|
ruby_lines = split_multiline_backtrace(ruby_backtrace)
|
58
101
|
|
59
|
-
|
60
|
-
|
61
|
-
filters.inject(line) do |line, proc|
|
62
|
-
proc.call(line)
|
63
|
-
end
|
102
|
+
lines = ruby_lines.collect do |unparsed_line|
|
103
|
+
Line.parse(unparsed_line, opts)
|
64
104
|
end.compact
|
65
105
|
|
66
|
-
lines = filtered_lines.collect do |unparsed_line|
|
67
|
-
Line.parse(unparsed_line)
|
68
|
-
end
|
69
|
-
|
70
106
|
instance = new(lines)
|
71
107
|
end
|
72
108
|
|
@@ -5,7 +5,7 @@ module Honeybadger
|
|
5
5
|
:ignore_user_agent, :notifier_name, :notifier_url, :notifier_version,
|
6
6
|
:params_filters, :project_root, :port, :protocol, :proxy_host, :proxy_pass,
|
7
7
|
:proxy_port, :proxy_user, :secure, :use_system_ssl_cert_chain, :framework,
|
8
|
-
:user_information, :rescue_rake_exceptions].freeze
|
8
|
+
:user_information, :rescue_rake_exceptions, :source_extract_radius].freeze
|
9
9
|
|
10
10
|
# The API key for your project, found on the project edit form.
|
11
11
|
attr_accessor :api_key
|
@@ -84,15 +84,21 @@ module Honeybadger
|
|
84
84
|
# The framework Honeybadger is configured to use
|
85
85
|
attr_accessor :framework
|
86
86
|
|
87
|
+
# The current user method to call for errors rescued in ActionController
|
88
|
+
attr_accessor :current_user_method
|
89
|
+
|
87
90
|
# Should Honeybadger catch exceptions from Rake tasks?
|
88
91
|
# (boolean or nil; set to nil to catch exceptions when rake isn't running from a terminal; default is nil)
|
89
92
|
attr_accessor :rescue_rake_exceptions
|
90
93
|
|
94
|
+
# The radius around trace line to include in source excerpt
|
95
|
+
attr_accessor :source_extract_radius
|
96
|
+
|
91
97
|
DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
|
92
98
|
|
93
99
|
DEFAULT_BACKTRACE_FILTERS = [
|
94
100
|
lambda { |line|
|
95
|
-
if defined?(Honeybadger.configuration.project_root) && Honeybadger.configuration.project_root.to_s != ''
|
101
|
+
if defined?(Honeybadger.configuration.project_root) && Honeybadger.configuration.project_root.to_s != ''
|
96
102
|
line.sub(/#{Honeybadger.configuration.project_root}/, "[PROJECT_ROOT]")
|
97
103
|
else
|
98
104
|
line
|
@@ -138,6 +144,8 @@ module Honeybadger
|
|
138
144
|
@framework = 'Standalone'
|
139
145
|
@user_information = 'Honeybadger Error {{error_id}}'
|
140
146
|
@rescue_rake_exceptions = nil
|
147
|
+
@current_user_method = :current_user
|
148
|
+
@source_extract_radius = 2
|
141
149
|
end
|
142
150
|
|
143
151
|
# Public: Takes a block and adds it to the list of backtrace filters. When
|
data/lib/honeybadger/notice.rb
CHANGED
@@ -11,6 +11,12 @@ module Honeybadger
|
|
11
11
|
# The name of the class of error (such as RuntimeError)
|
12
12
|
attr_reader :error_class
|
13
13
|
|
14
|
+
# Excerpt from source file
|
15
|
+
attr_reader :source_extract
|
16
|
+
|
17
|
+
# The number of lines of context to include before and after source excerpt
|
18
|
+
attr_reader :source_extract_radius
|
19
|
+
|
14
20
|
# The name of the server environment (such as "production")
|
15
21
|
attr_reader :environment_name
|
16
22
|
|
@@ -64,6 +70,9 @@ module Honeybadger
|
|
64
70
|
# The host name where this error occurred (if any)
|
65
71
|
attr_reader :hostname
|
66
72
|
|
73
|
+
# The user affected by the exception, if available
|
74
|
+
attr_reader :user
|
75
|
+
|
67
76
|
def initialize(args)
|
68
77
|
self.args = args
|
69
78
|
self.exception = args[:exception]
|
@@ -87,13 +96,17 @@ module Honeybadger
|
|
87
96
|
|
88
97
|
self.environment_name = args[:environment_name]
|
89
98
|
self.cgi_data = args[:cgi_data] || args[:rack_env]
|
99
|
+
self.user = args[:user]
|
90
100
|
self.backtrace = Backtrace.parse(exception_attribute(:backtrace, caller), :filters => self.backtrace_filters)
|
91
101
|
self.error_class = exception_attribute(:error_class) {|exception| exception.class.name }
|
92
102
|
self.error_message = exception_attribute(:error_message, 'Notification') do |exception|
|
93
103
|
"#{exception.class.name}: #{exception.message}"
|
94
104
|
end
|
95
105
|
|
96
|
-
self.hostname
|
106
|
+
self.hostname = local_hostname
|
107
|
+
|
108
|
+
self.source_extract_radius = args[:source_extract_radius] || 2
|
109
|
+
self.source_extract = extract_source_from_backtrace
|
97
110
|
|
98
111
|
also_use_rack_params_filters
|
99
112
|
find_session_data
|
@@ -114,7 +127,8 @@ module Honeybadger
|
|
114
127
|
:error => {
|
115
128
|
:class => error_class,
|
116
129
|
:message => error_message,
|
117
|
-
:backtrace => backtrace
|
130
|
+
:backtrace => backtrace,
|
131
|
+
:source => source_extract
|
118
132
|
},
|
119
133
|
:request => {
|
120
134
|
:url => url,
|
@@ -122,7 +136,8 @@ module Honeybadger
|
|
122
136
|
:action => action,
|
123
137
|
:params => parameters,
|
124
138
|
:session => session_data,
|
125
|
-
:cgi_data => cgi_data
|
139
|
+
:cgi_data => cgi_data,
|
140
|
+
:user => user
|
126
141
|
},
|
127
142
|
:server => {
|
128
143
|
:project_root => project_root,
|
@@ -169,7 +184,8 @@ module Honeybadger
|
|
169
184
|
:backtrace_filters, :parameters, :params_filters, :environment_filters,
|
170
185
|
:session_data, :project_root, :url, :ignore, :ignore_by_filters,
|
171
186
|
:notifier_name, :notifier_url, :notifier_version, :component, :action,
|
172
|
-
:cgi_data, :environment_name, :hostname
|
187
|
+
:cgi_data, :environment_name, :hostname, :user, :source_extract,
|
188
|
+
:source_extract_radius
|
173
189
|
|
174
190
|
# Private: Arguments given in the initializer
|
175
191
|
attr_accessor :args
|
@@ -247,6 +263,23 @@ module Honeybadger
|
|
247
263
|
end
|
248
264
|
end
|
249
265
|
|
266
|
+
def extract_source_from_backtrace
|
267
|
+
if backtrace.lines.empty?
|
268
|
+
nil
|
269
|
+
else
|
270
|
+
# ActionView::Template::Error has its own source_extract method.
|
271
|
+
# If present, use that instead.
|
272
|
+
if exception.respond_to?(:source_extract)
|
273
|
+
Hash[exception_attribute(:source_extract).split("\n").map do |line|
|
274
|
+
parts = line.split(': ')
|
275
|
+
[parts[0].strip, parts[1] || '']
|
276
|
+
end]
|
277
|
+
else
|
278
|
+
backtrace.lines.first.source(source_extract_radius)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
250
283
|
def filter(hash)
|
251
284
|
if params_filters
|
252
285
|
hash.each do |key, value|
|
@@ -7,7 +7,8 @@ module Honeybadger
|
|
7
7
|
:controller => params[:controller],
|
8
8
|
:action => params[:action],
|
9
9
|
:url => honeybadger_request_url,
|
10
|
-
:cgi_data => honeybadger_filter_if_filtering(request.env)
|
10
|
+
:cgi_data => honeybadger_filter_if_filtering(request.env),
|
11
|
+
:user => honeybadger_user_info }
|
11
12
|
end
|
12
13
|
|
13
14
|
private
|
@@ -54,6 +55,17 @@ module Honeybadger
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
def honeybadger_user_info
|
59
|
+
method = Honeybadger.configuration.current_user_method
|
60
|
+
|
61
|
+
if respond_to?(method) && user = send(method)
|
62
|
+
{
|
63
|
+
:id => user.id,
|
64
|
+
:email => user.respond_to?(:email) ? user.email : 'N/A'
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
57
69
|
def honeybadger_request_url
|
58
70
|
url = "#{request.protocol}#{request.host}"
|
59
71
|
|
@@ -17,7 +17,7 @@ module Honeybadger
|
|
17
17
|
controller = env['action_controller.instance']
|
18
18
|
env['honeybadger.error_id'] = Honeybadger.
|
19
19
|
notify_or_ignore(exception,
|
20
|
-
(controller.
|
20
|
+
(controller.respond_to?(:honeybadger_request_data) ? controller.honeybadger_request_data : {:rack_env => env})) unless skip_user_agent?(env)
|
21
21
|
if defined?(controller.rescue_action_in_public_without_honeybadger)
|
22
22
|
controller.rescue_action_in_public_without_honeybadger(exception)
|
23
23
|
end
|
@@ -24,7 +24,7 @@ namespace :honeybadger do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
heroku_rails_env = heroku_var("rails_env")
|
27
|
-
heroku_api_key = heroku_var("
|
27
|
+
heroku_api_key = heroku_var("honeybadger_api_key").split.find {|x| x unless x.blank?} ||
|
28
28
|
Honeybadger.configuration.api_key
|
29
29
|
|
30
30
|
command = %Q(heroku addons:add deployhooks:http --url="https://api.honeybadger.io/v1/deploys?deploy[environment]=#{heroku_rails_env}&api_key=#{heroku_api_key}")
|
data/lib/honeybadger_tasks.rb
CHANGED
@@ -57,8 +57,13 @@ module HoneybadgerTasks
|
|
57
57
|
else
|
58
58
|
response = http.request(post)
|
59
59
|
|
60
|
-
|
61
|
-
|
60
|
+
if Net::HTTPSuccess === response
|
61
|
+
puts "Succesfully recorded deployment"
|
62
|
+
return true
|
63
|
+
else
|
64
|
+
puts response.body
|
65
|
+
return false
|
66
|
+
end
|
62
67
|
end
|
63
68
|
end
|
64
69
|
end
|
@@ -76,7 +76,7 @@ class HoneybadgerGenerator < Rails::Generators::Base
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def heroku_api_key
|
79
|
-
heroku_var("
|
79
|
+
heroku_var("honeybadger_api_key",options[:app]).split.find {|x| x unless x.blank?}
|
80
80
|
end
|
81
81
|
|
82
82
|
def heroku?
|
data/test/unit/backtrace_test.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'stringio'
|
2
3
|
|
3
4
|
class BacktraceTest < Honeybadger::UnitTest
|
4
5
|
should "parse a backtrace into lines" do
|
@@ -55,6 +56,66 @@ class BacktraceTest < Honeybadger::UnitTest
|
|
55
56
|
assert_equal expected_backtrace, original_backtrace
|
56
57
|
end
|
57
58
|
|
59
|
+
context "when source file exists" do
|
60
|
+
setup do
|
61
|
+
source = <<-RUBY
|
62
|
+
$:<<'lib'
|
63
|
+
require 'honeybadger'
|
64
|
+
|
65
|
+
begin
|
66
|
+
raise StandardError
|
67
|
+
rescue => e
|
68
|
+
puts Honeybadger::Notice.new(exception: e).backtrace.to_json
|
69
|
+
end
|
70
|
+
RUBY
|
71
|
+
|
72
|
+
array = [
|
73
|
+
"app/models/user.rb:2:in `magic'",
|
74
|
+
"app/concerns/authenticated_controller.rb:4:in `authorize'",
|
75
|
+
"app/controllers/users_controller.rb:8:in `index'"
|
76
|
+
]
|
77
|
+
|
78
|
+
['app/models/user.rb', 'app/concerns/authenticated_controller.rb', 'app/controllers/users_controller.rb'].each do |file|
|
79
|
+
File.expects(:exists?).with(file).returns true
|
80
|
+
File.expects(:open).with(file).yields StringIO.new(source)
|
81
|
+
end
|
82
|
+
|
83
|
+
@backtrace = Honeybadger::Backtrace.parse(array)
|
84
|
+
end
|
85
|
+
|
86
|
+
should "include a snippet from the source file for each line of the backtrace" do
|
87
|
+
assert_equal 4, @backtrace.lines.first.source.keys.size
|
88
|
+
assert_match /\$:<</, @backtrace.lines.first.source[1]
|
89
|
+
assert_match /require/, @backtrace.lines.first.source[2]
|
90
|
+
assert_match /\n/, @backtrace.lines.first.source[3]
|
91
|
+
assert_match /begin/, @backtrace.lines.first.source[4]
|
92
|
+
|
93
|
+
assert_equal 5, @backtrace.lines.second.source.keys.size
|
94
|
+
assert_match /require/, @backtrace.lines.second.source[2]
|
95
|
+
assert_match /\n/, @backtrace.lines.second.source[3]
|
96
|
+
assert_match /begin/, @backtrace.lines.second.source[4]
|
97
|
+
assert_match /StandardError/, @backtrace.lines.second.source[5]
|
98
|
+
assert_match /rescue/, @backtrace.lines.second.source[6]
|
99
|
+
|
100
|
+
assert_equal 3, @backtrace.lines.third.source.keys.size
|
101
|
+
assert_match /rescue/, @backtrace.lines.third.source[6]
|
102
|
+
assert_match /Honeybadger/, @backtrace.lines.third.source[7]
|
103
|
+
assert_match /end/, @backtrace.lines.third.source[8]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
should "fail gracefully when looking up snippet and file doesn't exist" do
|
108
|
+
array = [
|
109
|
+
"app/models/user.rb:13:in `magic'",
|
110
|
+
"app/controllers/users_controller.rb:8:in `index'"
|
111
|
+
]
|
112
|
+
|
113
|
+
backtrace = Honeybadger::Backtrace.parse(array)
|
114
|
+
|
115
|
+
assert_empty backtrace.lines.first.source
|
116
|
+
assert_empty backtrace.lines.second.source
|
117
|
+
end
|
118
|
+
|
58
119
|
context "with a project root" do
|
59
120
|
setup do
|
60
121
|
@project_root = '/some/path'
|
@@ -20,7 +20,7 @@ class CapistranoTest < Honeybadger::UnitTest
|
|
20
20
|
should "log when calling honeybadger:deploy task" do
|
21
21
|
@configuration.set(:current_revision, '084505b1c0e0bcf1526e673bb6ac99fbcb18aecc')
|
22
22
|
@configuration.set(:repository, 'repository')
|
23
|
-
@configuration.set(:current_release, '/home/deploy/rails_app/
|
23
|
+
@configuration.set(:current_release, '/home/deploy/rails_app/honeybadger')
|
24
24
|
io = StringIO.new
|
25
25
|
logger = Capistrano::Logger.new(:output => io)
|
26
26
|
logger.level = Capistrano::Logger::MAX_LEVEL
|
@@ -27,6 +27,8 @@ class ConfigurationTest < Honeybadger::UnitTest
|
|
27
27
|
assert_config_default :ignore,
|
28
28
|
Honeybadger::Configuration::IGNORE_DEFAULT
|
29
29
|
assert_config_default :framework, 'Standalone'
|
30
|
+
assert_config_default :current_user_method, :current_user
|
31
|
+
assert_config_default :source_extract_radius, 2
|
30
32
|
end
|
31
33
|
|
32
34
|
should "provide default values for secure connections" do
|
@@ -67,6 +69,7 @@ class ConfigurationTest < Honeybadger::UnitTest
|
|
67
69
|
assert_config_overridable :notifier_url
|
68
70
|
assert_config_overridable :environment_name
|
69
71
|
assert_config_overridable :logger
|
72
|
+
assert_config_overridable :current_user_method
|
70
73
|
end
|
71
74
|
|
72
75
|
should "have an api key" do
|
@@ -96,7 +96,7 @@ class HoneybadgerTasksTest < Honeybadger::UnitTest
|
|
96
96
|
end
|
97
97
|
|
98
98
|
before_should "puts the response body on success" do
|
99
|
-
HoneybadgerTasks.expects(:puts).with("
|
99
|
+
HoneybadgerTasks.expects(:puts).with("Succesfully recorded deployment")
|
100
100
|
@http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
|
101
101
|
end
|
102
102
|
|
@@ -122,7 +122,7 @@ class HoneybadgerTasksTest < Honeybadger::UnitTest
|
|
122
122
|
|
123
123
|
context "in a configured project with custom host" do
|
124
124
|
setup do
|
125
|
-
Honeybadger.configure do |config|
|
125
|
+
Honeybadger.configure do |config|
|
126
126
|
config.api_key = "1234123412341234"
|
127
127
|
config.host = "custom.host"
|
128
128
|
config.secure = false
|
data/test/unit/notice_test.rb
CHANGED
@@ -57,6 +57,10 @@ class NoticeTest < Honeybadger::UnitTest
|
|
57
57
|
assert_equal 'index', build_notice(:action => 'index').action
|
58
58
|
end
|
59
59
|
|
60
|
+
should "accept source excerpt radius" do
|
61
|
+
assert_equal 3, build_notice(:source_extract_radius => 3).source_extract_radius
|
62
|
+
end
|
63
|
+
|
60
64
|
should "accept a url" do
|
61
65
|
url = 'http://some.host/uri'
|
62
66
|
notice = build_notice(:url => url)
|
@@ -68,31 +72,61 @@ class NoticeTest < Honeybadger::UnitTest
|
|
68
72
|
assert_equal hostname, notice.hostname
|
69
73
|
end
|
70
74
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
context "with a backtrace" do
|
76
|
+
setup do
|
77
|
+
@backtrace_array = ['my/file/backtrace:3']
|
78
|
+
@exception = build_exception
|
79
|
+
@exception.set_backtrace(@backtrace_array)
|
80
|
+
end
|
81
|
+
|
82
|
+
should "accept a backtrace from an exception or hash" do
|
83
|
+
backtrace = Honeybadger::Backtrace.parse(@backtrace_array)
|
84
|
+
notice_from_exception = build_notice(:exception => @exception)
|
77
85
|
|
86
|
+
assert_equal backtrace,
|
87
|
+
notice_from_exception.backtrace,
|
88
|
+
"backtrace was not correctly set from an exception"
|
78
89
|
|
79
|
-
|
80
|
-
|
81
|
-
|
90
|
+
notice_from_hash = build_notice(:backtrace => @backtrace_array)
|
91
|
+
assert_equal backtrace,
|
92
|
+
notice_from_hash.backtrace,
|
93
|
+
"backtrace was not correctly set from a hash"
|
94
|
+
end
|
82
95
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
96
|
+
should "pass its backtrace filters for parsing" do
|
97
|
+
Honeybadger::Backtrace.expects(:parse).with(@backtrace_array, {:filters => 'foo'}).returns(mock(:lines => []))
|
98
|
+
|
99
|
+
notice = Honeybadger::Notice.new({:exception => @exception, :backtrace_filters => 'foo'})
|
100
|
+
end
|
101
|
+
|
102
|
+
should "pass its backtrace line filters for parsing" do
|
103
|
+
Honeybadger::Backtrace::Line.expects(:parse).with(@backtrace_array.first, {:filters => 'foo'})
|
104
|
+
|
105
|
+
notice = Honeybadger::Notice.new({:exception => @exception, :backtrace_filters => 'foo'})
|
106
|
+
end
|
107
|
+
|
108
|
+
should "include source extract from backtrace" do
|
109
|
+
backtrace = Honeybadger::Backtrace.parse(@backtrace_array)
|
110
|
+
notice_from_exception = build_notice(:exception => @exception)
|
111
|
+
|
112
|
+
assert_equal backtrace.lines.first.source, notice_from_exception.source_extract
|
113
|
+
end
|
87
114
|
end
|
88
115
|
|
89
|
-
should "
|
90
|
-
|
116
|
+
should "Use source extract from view when reporting an ActionView::Template::Error" do
|
117
|
+
# TODO: I would like to stub out a real ActionView::Template::Error, but we're
|
118
|
+
# currently locked at actionpack 2.3.8. Perhaps if one day we upgrade...
|
119
|
+
source = <<-ERB
|
120
|
+
1: <%= current_user.name %>
|
121
|
+
2: </div>
|
122
|
+
3:
|
123
|
+
4: <div>
|
124
|
+
ERB
|
91
125
|
exception = build_exception
|
92
|
-
exception.
|
93
|
-
Honeybadger::
|
126
|
+
exception.stubs(:source_extract).returns(source)
|
127
|
+
notice = Honeybadger::Notice.new({:exception => exception})
|
94
128
|
|
95
|
-
|
129
|
+
assert_equal({ '1' => ' <%= current_user.name %>', '2' => '</div>', '3' => '', '4' => '<div>'}, notice.source_extract)
|
96
130
|
end
|
97
131
|
|
98
132
|
should "set the error class from an exception or hash" do
|
@@ -135,6 +169,10 @@ class NoticeTest < Honeybadger::UnitTest
|
|
135
169
|
assert_equal data, notice.cgi_data, "should take CGI data from a hash"
|
136
170
|
end
|
137
171
|
|
172
|
+
should "accept user" do
|
173
|
+
assert_equal 'foo@bar.com', build_notice(:user => 'foo@bar.com').user
|
174
|
+
end
|
175
|
+
|
138
176
|
should "accept notifier information" do
|
139
177
|
params = { :notifier_name => 'a name for a notifier',
|
140
178
|
:notifier_version => '1.0.5',
|
@@ -196,12 +234,21 @@ class NoticeTest < Honeybadger::UnitTest
|
|
196
234
|
assert_nil notice.url
|
197
235
|
assert_nil notice.controller
|
198
236
|
assert_nil notice.action
|
237
|
+
assert_nil notice.user
|
199
238
|
|
200
239
|
json = notice.to_json
|
201
240
|
payload = JSON.parse(json)
|
202
241
|
assert_nil payload['request']['url']
|
203
242
|
assert_nil payload['request']['component']
|
204
243
|
assert_nil payload['request']['action']
|
244
|
+
assert_nil payload['request']['user']
|
245
|
+
end
|
246
|
+
|
247
|
+
should "send user in request" do
|
248
|
+
notice = build_notice(:user => 'foo@bar.com')
|
249
|
+
json = notice.to_json
|
250
|
+
payload = JSON.parse(json)
|
251
|
+
assert_equal payload['request']['user'], 'foo@bar.com'
|
205
252
|
end
|
206
253
|
|
207
254
|
%w(url controller action).each do |var|
|
@@ -288,7 +335,6 @@ class NoticeTest < Honeybadger::UnitTest
|
|
288
335
|
end
|
289
336
|
end
|
290
337
|
|
291
|
-
|
292
338
|
should "ensure #to_ary is called on objects that support it" do
|
293
339
|
assert_nothing_raised do
|
294
340
|
build_notice(:session => { :object => stub(:to_ary => {}) })
|
@@ -113,6 +113,7 @@ class ActionControllerCatcherTest < Honeybadger::UnitTest
|
|
113
113
|
klass.local = opts[:local]
|
114
114
|
controller = klass.new
|
115
115
|
controller.stubs(:rescue_action_in_public_without_honeybadger)
|
116
|
+
controller.stubs(Honeybadger.configuration.current_user_method).returns(opts[:current_user]) if opts[:current_user]
|
116
117
|
opts[:request].query_parameters = opts[:request].query_parameters.merge(opts[:params] || {})
|
117
118
|
opts[:request].session = ActionController::TestSession.new(opts[:session] || {})
|
118
119
|
# Prevents request.fullpath from crashing Rails in tests
|
@@ -297,4 +298,27 @@ class ActionControllerCatcherTest < Honeybadger::UnitTest
|
|
297
298
|
assert_received(session, :data) { |expect| expect.at_least_once }
|
298
299
|
assert_caught_and_sent
|
299
300
|
end
|
301
|
+
|
302
|
+
should "call current_user_method if overridden" do
|
303
|
+
Honeybadger.configuration.current_user_method = :rockstar
|
304
|
+
|
305
|
+
current_user = mock( :id => 1 )
|
306
|
+
controller = process_action_with_automatic_notification(:current_user => current_user)
|
307
|
+
assert_received(controller, :rockstar) { |expect| expect.at_least_once }
|
308
|
+
assert_caught_and_sent
|
309
|
+
end
|
310
|
+
|
311
|
+
should "include current_user.id in request user data" do
|
312
|
+
current_user = stub( :id => 1 )
|
313
|
+
controller = process_action_with_automatic_notification(:current_user => current_user)
|
314
|
+
assert_equal({ :id => 1, :email => 'N/A' }, controller.honeybadger_request_data[:user])
|
315
|
+
assert_caught_and_sent
|
316
|
+
end
|
317
|
+
|
318
|
+
should "include current_user.email in request user data" do
|
319
|
+
current_user = stub( :id => 1, :email => 'foo@bar.com' )
|
320
|
+
controller = process_action_with_automatic_notification(:current_user => current_user)
|
321
|
+
assert_equal({ :id => 1, :email => 'foo@bar.com' }, controller.honeybadger_request_data[:user])
|
322
|
+
assert_caught_and_sent
|
323
|
+
end
|
300
324
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeybadger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|