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

V6 parity #381

Merged
merged 6 commits into from
Oct 12, 2017
Merged
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
7 changes: 7 additions & 0 deletions example/que/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source 'https://rubygems.org'

gem 'que'
gem 'activerecord'
gem 'pg'
gem 'rake'
gem 'bugsnag', path: '../../'
45 changes: 45 additions & 0 deletions example/que/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Using Bugsnag with Que

This example shows how to use Bugsnag in conjunction with Que to report any exceptions that occur in your applications.

First, install dependencies
```shell
bundle install
```

## Setting up a database
Que requires a database backend in order to queue jobs. By default this database will be PostgreSQL although this can be changed via options as detailed in [the que documentation](https://github.com/chanks/que).

Once PostgreSQL is set up as detailed using [the PostgreSQL documentation](https://www.postgresql.org/docs/), ensure Que can connect correctly by setting the environment variable `DBNAME` to the name of an existing PostgreSQL database.

## Configuring Bugsnag with Que

Bugsnag can be configured in one of two ways in your Que app:

1. require `bugsnag` in your application and call `Bugsnag.configure` with a block, setting the appropriate configuration options:
```ruby
Bugsnag.configure do |config|
config.api_key = "YOUR_API_KEY"
end
```

2. require `bugsnag` in your application and input configuration options through environment variables, such as setting `BUGSNAG_API_KEY` to `YOUR_API_KEY`.

All configuration options can be found in the [Bugsnag documentation](https://docs.bugsnag.com/platforms/ruby/other/configuration-options/)

## Running the example

Run the database migration using rake:
```shell
bundle exec rake migrate:up
```

After this is complete, queue up our test job:
```shell
bundle exec rake job:enqueue
```

Then execute the worker and see the errors appear on the [Bugsnag dashboard](https://app.bugsnag.com):
```shell
bundle exec rake job:work
```
37 changes: 37 additions & 0 deletions example/que/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace :migrate do
desc "Create database and tables"
task :up do
require_relative 'app/migrations'
CreateUsersTable.migrate(:up)
require_relative 'app/jobs'
Que.migrate!
end

desc "Drop database tables"
task :down do
require_relative 'app/migrations'
CreateUsersTable.migrate(:down)
end
end

namespace :job do
desc "Enqueue a job"
task :enqueue do
require_relative 'app/jobs'
user = User.create(name: 'Bob', cheered_at: 5.days.ago)
user.save
Cheer.enqueue(user.id)
end

desc "Run a worker"
task :work do
require_relative 'app/jobs'
require 'que'

Que.worker_count = 5
Que.mode = :async
loop do
sleep
end
end
end
25 changes: 25 additions & 0 deletions example/que/app/jobs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'active_record'
require_relative 'model'
require 'que'
require 'bugsnag'

Bugsnag.configure do |config|
config.api_key = 'YOUR_API_KEY'
end

Que.connection = ActiveRecord

class Cheer < Que::Job
@run_at = proc { 5.seconds.from_now }

def run(user_id, options={})
user = User.find(user_id)

ActiveRecord::Base.transaction do
user.update_attributes cheered_at: Time.now

raise 'Oh no, a problem!'
destroy
end
end
end
15 changes: 15 additions & 0 deletions example/que/app/migrations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'active_record'
require_relative 'model'

class CreateUsersTable < ActiveRecord::Migration[5.1]
def up
create_table :users do |t|
t.string :name
t.date :cheered_at
end
end

def down
drop_table :users
end
end
8 changes: 8 additions & 0 deletions example/que/app/model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require 'active_record'

class User < ActiveRecord::Base
end

ActiveRecord::Base.establish_connection(
adapter: 'postgresql', database: ENV['DBNAME']
)
5 changes: 5 additions & 0 deletions example/shoryuken/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source 'https://rubygems.org'

gem "bugsnag", path: "../../"
gem "shoryuken"
gem "aws-sdk-sqs"
42 changes: 42 additions & 0 deletions example/shoryuken/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Using Bugsnag with Shoryuken

This example shows how to use Bugsnag in conjunction with Shoryuken to report any exceptions that occur in your applications.

First, install dependencies
```shell
bundle install
```

## Configuring Bugsnag with Shoryuken

Bugsnag can be configured in one of two ways in your Shoryuken app:

1. require `bugsnag` in your application and call `Bugsnag.configure` with a block, setting the appropriate configuration options:
```ruby
Bugsnag.configure do |config|
config.api_key = "YOUR_API_KEY"
end
```

2. require `bugsnag` in your application and input configuration options through environment variables, such as setting `BUGSNAG_API_KEY` to `YOUR_API_KEY`.

All configuration options can be found in the [Bugsnag documentation](https://docs.bugsnag.com/platforms/ruby/other/configuration-options/)

## Running the example

Set up your AWS credentials as required in the [Configure the AWS Client](https://github.com/phstc/shoryuken/wiki/Configure-the-AWS-Client) section of the Shoryuken getting started docs.

Start the Shoryuken processor with:
```shell
bundle exec shoryuken -r ./shoryuken.rb
```

In a seperate terminal instance open the console session with:
```shell
bundle exec irb -r ./shoryuken.rb
```

Where you can queue a message with the command:
```ruby
BugsnagTest.perform_async "Hello world"
```
17 changes: 17 additions & 0 deletions example/shoryuken/shoryuken.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'shoryuken'
require 'bugsnag'

Bugsnag.configure do |config|
config.api_key = 'YOUR_API_KEY'
end

class BugsnagTest
include Shoryuken::Worker

shoryuken_options queue: 'connector_development_default', auto_delete: true

def perform(sqs_msg, body)
puts "Received message: #{body}"
raise 'Uh oh!'
end
end
9 changes: 8 additions & 1 deletion lib/bugsnag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

require "bugsnag/middleware/rack_request"
require "bugsnag/middleware/warden_user"
require "bugsnag/middleware/clearance_user"
require "bugsnag/middleware/callbacks"
require "bugsnag/middleware/rails3_request"
require "bugsnag/middleware/sidekiq"
Expand All @@ -30,6 +31,12 @@ class << self
# Configure the Bugsnag notifier application-wide settings.
def configure
yield(configuration) if block_given?

@key_warning = false unless defined?(@key_warning)
if !configuration.valid_api_key? && !@key_warning
configuration.warn("No valid API key has been set, notifications will not be sent")
@key_warning = true
end
end

# Explicitly notify of an exception
Expand Down Expand Up @@ -115,7 +122,7 @@ def before_notify_callbacks
end
end

[:resque, :sidekiq, :mailman, :delayed_job].each do |integration|
[:resque, :sidekiq, :mailman, :delayed_job, :shoryuken, :que].each do |integration|
begin
require "bugsnag/integrations/#{integration}"
rescue LoadError
Expand Down
14 changes: 12 additions & 2 deletions lib/bugsnag/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class Configuration
attr_accessor :proxy_password
attr_accessor :timeout
attr_accessor :hostname
attr_accessor :delivery_method
attr_accessor :ignore_classes

API_KEY_REGEX = /[0-9a-f]{32}/i
Expand All @@ -57,7 +56,6 @@ def initialize
self.ignore_classes = Set.new([])
self.endpoint = DEFAULT_ENDPOINT
self.hostname = default_hostname
self.delivery_method = :thread_queue
self.timeout = 15
self.notify_release_stages = nil

Expand Down Expand Up @@ -85,6 +83,18 @@ def initialize
self.middleware.use Bugsnag::Middleware::Callbacks
end

def delivery_method
@delivery_method || @default_delivery_method || :thread_queue
end

def delivery_method=(delivery_method)
@delivery_method = delivery_method
end

def default_delivery_method=(delivery_method)
@default_delivery_method = delivery_method
end

def should_notify_release_stage?
@release_stage.nil? || @notify_release_stages.nil? || @notify_release_stages.include?(@release_stage)
end
Expand Down
44 changes: 44 additions & 0 deletions lib/bugsnag/integrations/que.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
if defined?(::Que)
handler = proc do |error, job|
begin
job = job.dup # Make sure the original job object is not mutated.

Bugsnag.notify(error, true) do |report|
job[:error_count] += 1

# If the job was scheduled using ActiveJob then unwrap the job details for clarity:
if job[:job_class] == "ActiveJob::QueueAdapters::QueAdapter::JobWrapper"
wrapped_job = job[:args].last
wrapped_job = wrapped_job.each_with_object({}) { |(k, v), result| result[k.to_sym] = v } # Symbolize keys

# Align key names with keys in `job`
wrapped_job[:queue] = wrapped_job.delete(:queue_name)
wrapped_job[:args] = wrapped_job.delete(:arguments)

job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job)
end

report.add_tab(:job, job)
report.severity = 'error'
report.severity_reason = {
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
:attributes => {
:framework => 'Que'
}
}
end
rescue => e
# Que supresses errors raised by its error handler to avoid killing the worker. Log them somewhere:
Bugsnag.configuration.warn("Failed to notify Bugsnag of error in Que job (#{e.class}): #{e.message} \n#{e.backtrace[0..9].join("\n")}")
raise
end
end

if Que.respond_to?(:error_notifier=)
Bugsnag.configuration.app_type ||= "que"
Que.error_notifier = handler
elsif Que.respond_to?(:error_handler=)
Bugsnag.configuration.app_type ||= "que"
Que.error_handler = handler
end
end
1 change: 1 addition & 0 deletions lib/bugsnag/integrations/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def initialize(app)
# Hook up rack-based notification middlewares
config.middleware.insert_before([Bugsnag::Middleware::Rails3Request,Bugsnag::Middleware::Callbacks], Bugsnag::Middleware::RackRequest) if defined?(::Rack)
config.middleware.insert_before(Bugsnag::Middleware::Callbacks, Bugsnag::Middleware::WardenUser) if defined?(Warden)
config.middleware.insert_before(Bugsnag::Middleware::Callbkacs, Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)

config.app_type ||= "rack"
end
Expand Down
4 changes: 2 additions & 2 deletions lib/bugsnag/integrations/resque.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def save
:type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE,
:attributes => FRAMEWORK_ATTRIBUTES
}
report.meta_data.merge!({:context => "#{payload['class']}@#{queue}", :payload => payload, :delivery_method => :synchronous})
report.meta_data.merge!({:context => "#{payload['class']}@#{queue}", :payload => payload})
end
end
end
Expand All @@ -51,5 +51,5 @@ def save

Resque.before_first_fork do
Bugsnag.configuration.app_type = "resque"
Bugsnag.configuration.delivery_method = :synchronous
Bugsnag.configuration.default_delivery_method = :synchronous
end
Loading