Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make backtrace cleaning optional #328

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* enhancements
* update URL in gemspec (by @ktdreyer)
* Add `hostname` to Slack notifier (by @juanazam)
* Allow `exception_recipients` to be a proc (by @kellyjosephprice)
* Add `clean_backtrace` option to allow displaying full backtrace in e-mail notifications (by @chancancode and @vala)

== 4.1.4

Expand Down Expand Up @@ -107,7 +109,7 @@
* Add normalize_subject option to remove numbers from email so that they thread (by @jjb)
* Allow the user to provide a custom message and hash of data (by @jjb)
* Add support for configurable background sections and a data partial (by @jeffrafter)
* Include timestamp of exception in notification body
* Include timestamp of exception in notification body
* Add support for rack based session management (by @phoet)
* Add ignore_crawlers option to ignore exceptions generated by crawlers
* Add verbode_subject option to exclude exception message from subject (by @amishyn)
Expand Down
5 changes: 4 additions & 1 deletion MIT-LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Copyright (c) 2005 Jamis Buck
Copyright (c) 2011-2016 Sebastian Martinez
Copyright (c) 2005-2010 Jamis Buck

The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand Down
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,36 @@ Rails.application.config.middleware.use ExceptionNotification::Rack,

In order to use ExceptionNotification with Sinatra, please take a look in the [example application](https://github.com/smartinez87/exception_notification/tree/master/examples/sinatra).

### Custom Data, e.g. Current User

Save the current user in the `request` using a controller callback.

```ruby
class ApplicationController < ActionController::Base
before_filter :prepare_exception_notifier
private
def prepare_exception_notifier
request.env["exception_notifier.exception_data"] = {
:current_user => current_user
}
end
end
```

The current user will show up in your email, in a new section titled "Data".

```
------------------------------- Data:

* data: {:current_user=>
#<User:0x007ff03c0e5860
id: 3,
email: "[email protected]", # etc...
```

For more control over the display of custom data, see "Email notifier ->
Options -> sections" below.

## Notifiers

ExceptionNotification relies on notifiers to deliver notifications when errors occur in your applications. By default, six notifiers are available:
Expand Down Expand Up @@ -144,9 +174,9 @@ Who the message is from.

##### exception_recipients

*String/Array of strings, default: []*
*String/Array of strings/Proc, default: []*

Who the message is destined for, can be a string of addresses, or an array of addresses.
Who the message is destined for, can be a string of addresses, an array of addresses, or it can be a proc that returns a string of addresses or an array of addresses. The proc will be evaluated when the mail is sent.

##### email_prefix

Expand Down Expand Up @@ -308,7 +338,7 @@ This notifier sends notifications to your Hipchat room.

#### Usage

Just add the [hipchat](https://github.com/hipchat/hipchat) gem to your `Gemfile`:
Just add the [hipchat](https://github.com/hipchat/hipchat-rb) gem to your `Gemfile`:

```ruby
gem 'hipchat'
Expand Down Expand Up @@ -493,7 +523,20 @@ Rails.application.config.middleware.use ExceptionNotification::Rack,
}
```

The slack notification will include any data saved under `env["exception_notifier.exception_data"]`. If you find this too verbose, you can determine to exclude certain information by doing the following:
The slack notification will include any data saved under `env["exception_notifier.exception_data"]`.

An example of how to send the server name to Slack in Rails (put this code in application_controller.rb):

```ruby
before_filter :set_notification

def set_notification
request.env['exception_notifier.exception_data'] = {"server" => request.env['SERVER_NAME']}
# can be any key-value pairs
end
```

If you find this too verbose, you can determine to exclude certain information by doing the following:

```ruby
Rails.application.config.middleware.use ExceptionNotification::Rack,
Expand Down
2 changes: 1 addition & 1 deletion exception_notification.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Gem::Specification.new do |s|
s.add_dependency("actionmailer", "~> 4.0")
s.add_dependency("activesupport", "~> 4.0")

s.add_development_dependency "rails", "~> 4.0"
s.add_development_dependency "rails", ">= 4.0", "<= 6.0"
s.add_development_dependency "resque", "~> 1.2.0"
# Sidekiq 3.2.2 does not support Ruby 1.9.
s.add_development_dependency "sidekiq", "~> 3.0.0", "< 3.2.2"
Expand Down
1 change: 1 addition & 0 deletions lib/exception_notification/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def initialize(app, options = {})
@app = app

ExceptionNotifier.ignored_exceptions = options.delete(:ignore_exceptions) if options.key?(:ignore_exceptions)
ExceptionNotifier.clean_backtrace = options.delete(:clean_backtrace) if options.key?(:clean_backtrace)

if options.key?(:ignore_if)
rack_ignore = options.delete(:ignore_if)
Expand Down
3 changes: 3 additions & 0 deletions lib/exception_notifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class UndefinedNotifierError < StandardError; end
mattr_accessor :testing_mode
@@testing_mode = false

mattr_accessor :clean_backtrace
@@clean_backtrace = true

class << self
# Store conditions that decide when exceptions must be ignored or not.
@@ignores = []
Expand Down
9 changes: 7 additions & 2 deletions lib/exception_notifier/email_notifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def background_exception_notification(exception, options={}, default_options={})

@exception = exception
@options = options.reverse_merge(default_options)
@backtrace = exception.backtrace || []
@backtrace = exception.backtrace ? clean_backtrace(exception) : []
@sections = @options[:background_sections]
@data = options[:data] || {}

Expand Down Expand Up @@ -94,10 +94,11 @@ def compose_email
set_data_variables
subject = compose_subject
name = @env.nil? ? 'background_exception_notification' : 'exception_notification'
exception_recipients = maybe_call(@options[:exception_recipients])

headers = {
:delivery_method => @options[:delivery_method],
:to => @options[:exception_recipients],
:to => exception_recipients,
:from => @options[:sender_address],
:subject => subject,
:template_name => name
Expand All @@ -118,6 +119,10 @@ def load_custom_views
self.prepend_view_path Rails.root.nil? ? "app/views" : "#{Rails.root}/app/views"
end
end

def maybe_call(maybe_proc)
maybe_proc.respond_to?(:call) ? maybe_proc.call : maybe_proc
end
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/exception_notifier/modules/backtrace_cleaner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ module ExceptionNotifier
module BacktraceCleaner

def clean_backtrace(exception)
if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)

if ExceptionNotifier.clean_backtrace && defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
Rails.backtrace_cleaner.send(:filter, exception.backtrace)
else
exception.backtrace
Expand Down
28 changes: 28 additions & 0 deletions test/dummy/test/functional/posts_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,31 @@ class PostsControllerTestBackgroundNotification < ActionController::TestCase
assert_includes @mail.encoded, "* New background section for testing"
end
end

class PostsControllerTestWithExceptionRecipientsAsProc < ActionController::TestCase
tests PostsController
setup do
exception_recipients = %w{[email protected] [email protected]}

@email_notifier = ExceptionNotifier::EmailNotifier.new(
exception_recipients: -> { [ exception_recipients.shift ] }
)

@action = proc do
begin
@post = posts(:one)
post :create, :post => @post.attributes
rescue => e
@exception = e
@mail = @email_notifier.create_email(@exception, {:env => request.env})
end
end
end

test "should lazily evaluate exception_recipients" do
@action.call
assert_equal [ "[email protected]" ], @mail.to
@action.call
assert_equal [ "[email protected]" ], @mail.to
end
end
42 changes: 40 additions & 2 deletions test/exception_notifier/email_notifier_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

class EmailNotifierTest < ActiveSupport::TestCase
setup do
@original_clean_backtrace = ExceptionNotifier.clean_backtrace
ExceptionNotifier.clean_backtrace = true

Time.stubs(:current).returns('Sat, 20 Apr 2013 20:58:55 UTC +00:00')
@email_notifier = ExceptionNotifier.registered_exception_notifier(:email)
begin
Expand All @@ -14,6 +17,10 @@ class EmailNotifierTest < ActiveSupport::TestCase
end
end

teardown do
ExceptionNotifier.clean_backtrace = @original_clean_backtrace
end

test "should call pre/post_callback if specified" do
assert_equal @email_notifier.options[:pre_callback_called], 1
assert_equal @email_notifier.options[:post_callback_called], 1
Expand Down Expand Up @@ -119,8 +126,24 @@ class EmailNotifierTest < ActiveSupport::TestCase
assert_includes @vowel_mail.encoded, "An ActiveRecord::RecordNotFound occurred in background at #{Time.current}"
end

test "mail should contain backtrace in body" do
assert @mail.encoded.include?("test/exception_notifier/email_notifier_test.rb:9"), "\n#{@mail.inspect}"
test "mail should contain cleaned backtrace in body" do
assert_includes @mail.encoded, @exception.backtrace[0], "\n#{@mail}"
assert_includes @mail.encoded, @exception.backtrace[1], "\n#{@mail}"

assert_not_includes @mail.encoded, @exception.backtrace[2], "\n#{@mail}"
assert_not_includes @mail.encoded, @exception.backtrace[-1], "\n#{@mail}"
end

test "clean_backtrace should not do anything if backtrace cleaning is disabled" do
ExceptionNotifier.clean_backtrace = false

@mail = @email_notifier.create_email(@exception,
:data => {:job => 'DivideWorkerJob', :payload => '1/0', :message => 'My Custom Message'})

assert_includes @mail.encoded, @exception.backtrace[0], "\n#{@mail.inspect}"
assert_includes @mail.encoded, @exception.backtrace[1], "\n#{@mail.inspect}"
assert_includes @mail.encoded, @exception.backtrace[2], "\n#{@mail.inspect}"
assert_includes @mail.encoded, @exception.backtrace[-1], "\n#{@mail.inspect}"
end

test "mail should contain data in body" do
Expand Down Expand Up @@ -182,4 +205,19 @@ class EmailNotifierTest < ActiveSupport::TestCase

assert_equal 1, ActionMailer::Base.deliveries.count
end

test "should lazily evaluate exception_recipients" do
exception_recipients = %w{[email protected] [email protected]}
email_notifier = ExceptionNotifier::EmailNotifier.new(
:email_prefix => '[Dummy ERROR] ',
:sender_address => %{"Dummy Notifier" <[email protected]>},
:exception_recipients => -> { [ exception_recipients.shift ] },
:delivery_method => :test
)

mail = email_notifier.call(@exception)
assert_equal %w{[email protected]}, mail.to
mail = email_notifier.call(@exception)
assert_equal %w{[email protected]}, mail.to
end
end