diff --git a/example/padrino/Gemfile b/example/padrino/Gemfile index 4b7262071..f8d4ba1a1 100644 --- a/example/padrino/Gemfile +++ b/example/padrino/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' if ENV['INTEGRATION_LANGUAGE'] - gem 'bugsnag', path: '../../../../' + gem 'bugsnag', path: '../../' else gem 'bugsnag' end @@ -38,7 +38,7 @@ gem 'riot', :group => 'test' gem 'rack-test', :require => 'rack/test', :group => 'test' # Padrino Stable Gem -gem 'padrino', '0.12.2' +gem 'padrino' # Or Padrino Edge # gem 'padrino', :github => 'padrino/padrino-framework' diff --git a/example/padrino/README.md b/example/padrino/README.md index 71aa0d87a..f82ab5b96 100644 --- a/example/padrino/README.md +++ b/example/padrino/README.md @@ -1,90 +1,44 @@ # Bugsnag Padrino demo -This Padrino application demonstrates how to use Bugsnag with Padrino. Before -testing it, open up the `config/boot.rb` file configure your API key inside -`Padrino.before_load`. +This Padrino application demonstrates how to use Bugsnag with Padrino. +Further details about integrating Bugsnag with Rack applications can be found [here.](https://docs.bugsnag.com/platforms/ruby/rack/) -``` -Padrino.before_load do - Bugsnag.configure do |config| - config.api_key = '0a6f5add590596f93a8d601ea89af841' - end -end +Install dependencies + +```shell +bundle install ``` -In the same file activate the Bugsnag Rack middleware. +## Configuring Bugsnag and Padrino -``` -Padrino.after_load do - Padrino.use Bugsnag::Rack -end -``` +1. Set up the Padrino Bugsnag configuration in ```config/boot.rb``` in the `before_load` call according to the [available configuration options](https://docs.bugsnag.com/platforms/ruby/rack/configuration-options/): + ```ruby + Padrino.before_load do + Bugsnag.configure do |config| + config.api_key = 'YOUR_API_KEY' + end + end + ``` -Open up `app/app.rb`, find two options and set them as follows: `raise_errors` -to `true` and `show_exceptions` to `false`. This enables automatic notifications -in the development environment. By default Padrino swallows exceptions from -Bugsnag (only in development, though). +2. Register the Rack middleware in ```config/boot.rb``` in the `after_load` call: + ```ruby + Padrino.after_load do + Padrino.use Bugsnag::Rack + end + ``` -``` +3. In `production` automatic notification of exceptions and errors will be enabled by default. If you want to enable notifications in `development`, open ```app/app.rb``` and set the following options: +```ruby set :raise_errors, true set :show_exceptions, false ``` -If you would like to use custom error handlers, then you need to notify Bugsnag -explicitly. - -``` -error 500 do - Bugsnag.notify($!) do |report| - report.severity = "error" - end - - erb :'errors/500' -end -``` - -Install dependencies. - -``` -bundle install -``` +## Running the example -Launch the Padrino application. +Run the example using: -``` +```shell bundle exec padrino start ``` -Next, open your project's dashboard on Bugsnag. - -1. [crash](http://localhost:9292/crash) -
-Crashes the application and sends a notification about the nature of the crash. -Basically, almost any unhandled exception sends a notification to Bugsnag. See -the line mentioning `get '/crash'` in `app/app.rb`. - -1. [crash and use callbacks](http://localhost:9292/crash_with_callback) -
-Before crashing, the application would append the Diagnostics tab with some -predefined information, attached by means of a callback. See the line mentioning -`get '/crash_with_callback'` in `app/app.rb`. - -1. [notify](http://localhost:9292/notify) -
-Bugsnag Ruby provides a way to send notifications on demand by means of -`Bugsnag.notify`. This API allows to send notifications manually, without -crashing your application. See the line mentioning `get '/notify'` in -`app/app.rb`. - -1. [notify with meta data](http://localhost:9292/notify_meta) -
-Same as `notify`, but also attaches meta data. The meta data is any additional -information you want to attach to an exception. In this artificial case -additional information with be sent and displayed in a new tab called -"Diagnostics". See the line mentioning `get '/notify_meta'` in `app/app.rb`. - -1. [severity](http://localhost:9292/severity) -
-Bugsnag supports three severities: 'error', 'warning' and 'info'. You can set -the severity by passing one of these objects as a string to '#notify'. See the -line mentioning `get '/severity'` in `app/app.rb`. +Once the server is running head to the default path for more information on Bugsnag logging examples. diff --git a/example/padrino/app/app.rb b/example/padrino/app/app.rb index 127e36ebf..3630647ef 100644 --- a/example/padrino/app/app.rb +++ b/example/padrino/app/app.rb @@ -67,7 +67,7 @@ class App < Padrino::Application fenced_code_blocks: true } renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML, opts) - renderer.render(File.read(File.expand_path('README.md'))) + renderer.render(File.read(File.expand_path('app/templates/index.md'))) end get '/crash' do @@ -76,12 +76,12 @@ class App < Padrino::Application end get '/crash_with_callback' do - Bugsnag.before_notify_callbacks << proc { |notification| + Bugsnag.before_notify_callbacks << proc { |report| new_tab = { message: 'Padrino demo says: Everything is great', code: 200 } - notification.add_tab(:diagnostics, new_tab) + report.add_tab(:diagnostics, new_tab) } msg = 'Bugsnag Padrino demo says: It crashed! But, due to the attached callback' + @@ -98,31 +98,31 @@ class App < Padrino::Application ' for a new notification.' end - get '/notify_meta' do - meta_data = { - :user => { + get '/notify_data' do + error = RuntimeError.new("Bugsnag Padrino demo says: False alarm, your application didn't crash") + Bugsnag.notify error do |report| + report.add_tab(:user, { :username => "bob-hoskins", :email => 'bugsnag@bugsnag.com', :registered_user => true - }, - - :diagnostics => { + }) + report.add_tab(:diagnostics, { :message => 'Padrino demo says: Everything is great', :code => 200 - } - } - error = RuntimeError.new("Bugsnag Padrino demo says: False alarm, your application didn't crash") - Bugsnag.notify(error, meta_data) + }) + end "Bugsnag Padrino demo says: It didn't crash! " + 'But still go check https://bugsnag.com' + ' for a new notification. Check out the User tab for the meta data' end - get '/severity' do + get '/notify_severity' do msg = "Bugsnag Padrino demo says: Look at the circle on the right side. It's different" error = RuntimeError.new(msg) - Bugsnag.notify(error, severity: 'info') + Bugsnag.notify error do |report| + report.severity = 'info' + end msg end end diff --git a/example/padrino/app/templates/index.md b/example/padrino/app/templates/index.md new file mode 100644 index 000000000..4f2d4be06 --- /dev/null +++ b/example/padrino/app/templates/index.md @@ -0,0 +1,25 @@ +# Bugsnag Padrino demo + +This application demonstrates the use of Bugsnag with the Padrino web framework. + +While testing the examples open [your dashboard](https://app.bugsnag.com) in order to see the example errors and exceptions being received. + +1. [Crash](/crash) +
+ Raises an error within the framework, generating a report in the Bugsnag dashboard. + +2. [Crash and use callbacks](/crash_with_callback) +
+ Raises an exception within the framework, but with additional data attached to the report. By registering a callback before the error occurs useful data can be attached as a tab in the Bugsnag dashboard. + +3. [Notify](/notify) +
+ Sends Bugsnag a report on demand using `bugsnag.notify`. Allows details of handled errors or information to be sent to the Bugsnag dashboard without crashing your code. + +4. [Notify with data](/notify_data) +
+ Same as `notify` but allows you to attach additional data within a `block`, similar to the `before_notify_callbacks` example above. In this case we're adding information about the user to go into the `user` tab, and additional diagnostics as a `diagnostics` tab. + +5. [Set the severity](/notify_severity) +
+ This uses the same mechanism as adding meta-data, but allows you to set he `severity` when notifying Bugsnag of the error. Valid severities are `error`, `warning`, and `info`. Have a look on the dashboard to see the difference in these severities. \ No newline at end of file diff --git a/example/padrino/config/boot.rb b/example/padrino/config/boot.rb index e6a8ac9d0..54e54347c 100644 --- a/example/padrino/config/boot.rb +++ b/example/padrino/config/boot.rb @@ -37,7 +37,7 @@ # Padrino.before_load do Bugsnag.configure do |config| - config.api_key = 'f35a2472bd230ac0ab0f52715bbdc65d' + config.api_key = 'YOUR_API_KEY' end end diff --git a/example/padrino/config/database.rb b/example/padrino/config/database.rb deleted file mode 100644 index 801a76d9b..000000000 --- a/example/padrino/config/database.rb +++ /dev/null @@ -1,40 +0,0 @@ -## -# A MySQL connection: -# DataMapper.setup(:default, 'mysql://user:password@localhost/the_database_name') -# -# # A Postgres connection: -# DataMapper.setup(:default, 'postgres://user:password@localhost/the_database_name') -# -# # A Sqlite3 connection -# DataMapper.setup(:default, "sqlite3://" + Padrino.root('db', "development.db")) -# -# # Setup DataMapper using config/database.yml -# DataMapper.setup(:default, YAML.load_file(Padrino.root('config/database.yml'))[RACK_ENV]) -# -# config/database.yml file: -# -# --- -# development: &defaults -# adapter: mysql -# database: example_development -# username: user -# password: Pa55w0rd -# host: 127.0.0.1 -# -# test: -# <<: *defaults -# database: example_test -# -# production: -# <<: *defaults -# database: example_production -# - -DataMapper.logger = logger -DataMapper::Property::String.length(255) - -case Padrino.env - when :development then DataMapper.setup(:default, "sqlite3://" + Padrino.root('db', "bugsnag_padrino_development.db")) - when :production then DataMapper.setup(:default, "sqlite3://" + Padrino.root('db', "bugsnag_padrino_production.db")) - when :test then DataMapper.setup(:default, "sqlite3://" + Padrino.root('db', "bugsnag_padrino_test.db")) -end diff --git a/example/padrino/public/favicon.ico b/example/padrino/public/favicon.ico deleted file mode 100644 index 4e26b1989..000000000 Binary files a/example/padrino/public/favicon.ico and /dev/null differ diff --git a/example/padrino/public/javascripts/application.js b/example/padrino/public/javascripts/application.js deleted file mode 100644 index 88a3216c4..000000000 --- a/example/padrino/public/javascripts/application.js +++ /dev/null @@ -1 +0,0 @@ -// Put your application scripts here \ No newline at end of file diff --git a/example/padrino/public/javascripts/jquery-ujs.js b/example/padrino/public/javascripts/jquery-ujs.js deleted file mode 100644 index 4f15428fc..000000000 --- a/example/padrino/public/javascripts/jquery-ujs.js +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Padrino Javascript Jquery Adapter - * Created for use with Padrino Ruby Web Framework (http://www.padrinorb.com) -**/ - -/* Remote Form Support - * form_for @user, '/user', :remote => true -**/ - -$(function(){ - $('form').on('submit', function(e) { - var element = $(this), message = element.data('confirm'); - if (message && !confirm(message)) { return false; } - if (element.data('remote') == true) { - e.preventDefault(); e.stopped = true; - JSAdapter.sendRequest(element, { - verb: element.data('method') || element.attr('method') || 'post', - url: element.attr('action'), - dataType: element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType) || 'script', - params: element.serializeArray() - }); - } - }); - - /* Confirmation Support - * link_to 'sign out', '/logout', :confirm => 'Log out?' - **/ - - $(document).on('click', 'a[data-confirm]', function(e) { - var message = $(this).data('confirm'); - if (!confirm(message)) { e.preventDefault(); e.stopped = true; } - }); - - /* - * Link Remote Support - * link_to 'add item', '/create', :remote => true - **/ - - $(document).on('click', 'a[data-remote=true]', function(e) { - var element = $(this); - if (e.stopped) return; - e.preventDefault(); e.stopped = true; - JSAdapter.sendRequest(element, { - verb: element.data('method') || 'get', - url: element.attr('href') - }); - }); - - /* - * Link Method Support - * link_to 'delete item', '/destroy', :method => :delete - **/ - - $(document).on('click', 'a[data-method]:not([data-remote])', function(e) { - if (e.stopped) return; - JSAdapter.sendMethod($(this)); - e.preventDefault(); e.stopped = true; - }); - - /* JSAdapter */ - var JSAdapter = { - // Sends an xhr request to the specified url with given verb and params - // JSAdapter.sendRequest(element, { verb: 'put', url : '...', params: {} }); - sendRequest: function(element, options) { - var verb = options.verb, url = options.url, params = options.params, dataType = options.dataType; - var event = element.trigger('ajax:before'); - if (event.stopped) return false; - $.ajax({ - url: url, - type: verb.toUpperCase() || 'POST', - data: params || [], - dataType: dataType, - - beforeSend: function(request) { element.trigger('ajax:loading', [ request ]); }, - complete: function(request) { element.trigger('ajax:complete', [ request ]); }, - success: function(request) { element.trigger('ajax:success', [ request ]); }, - error: function(request) { element.trigger('ajax:failure', [ request ]); } - }); - element.trigger('ajax:after'); - }, - // Triggers a particular method verb to be triggered in a form posting to the url - // JSAdapter.sendMethod(element); - sendMethod: function(element) { - var verb = element.data('method'); - var url = element.attr('href'); - var form = $('
'); - var csrf_token = $('meta[name=csrf-token]').attr('content'); - var csrf_param = $('meta[name=csrf-param]').attr('content'); - form.hide().appendTo('body'); - if (verb !== 'post') { - var field = ''; - form.append(field); - } - if (csrf_param !== undefined && csrf_token !== undefined) { - var field = ''; - form.append(field); - } - form.submit(); - } - }; - - // Every xhr request is sent along with the CSRF token. - $.ajaxPrefilter(function(options, originalOptions, xhr) { - if (options.verb !== 'GET') { - var token = $('meta[name="csrf-token"]').attr('content'); - if (token) xhr.setRequestHeader('X-CSRF-Token', token); - } - }); -}); diff --git a/example/padrino/public/javascripts/jquery.js b/example/padrino/public/javascripts/jquery.js deleted file mode 100644 index 50d1b22f2..000000000 --- a/example/padrino/public/javascripts/jquery.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.9.0 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license */(function(e,t){"use strict";function n(e){var t=e.length,n=st.type(e);return st.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e){var t=Tt[e]={};return st.each(e.match(lt)||[],function(e,n){t[n]=!0}),t}function i(e,n,r,i){if(st.acceptData(e)){var o,a,s=st.expando,u="string"==typeof n,l=e.nodeType,c=l?st.cache:e,f=l?e[s]:e[s]&&s;if(f&&c[f]&&(i||c[f].data)||!u||r!==t)return f||(l?e[s]=f=K.pop()||st.guid++:f=s),c[f]||(c[f]={},l||(c[f].toJSON=st.noop)),("object"==typeof n||"function"==typeof n)&&(i?c[f]=st.extend(c[f],n):c[f].data=st.extend(c[f].data,n)),o=c[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[st.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[st.camelCase(n)])):a=o,a}}function o(e,t,n){if(st.acceptData(e)){var r,i,o,a=e.nodeType,u=a?st.cache:e,l=a?e[st.expando]:st.expando;if(u[l]){if(t&&(r=n?u[l]:u[l].data)){st.isArray(t)?t=t.concat(st.map(t,st.camelCase)):t in r?t=[t]:(t=st.camelCase(t),t=t in r?[t]:t.split(" "));for(i=0,o=t.length;o>i;i++)delete r[t[i]];if(!(n?s:st.isEmptyObject)(r))return}(n||(delete u[l].data,s(u[l])))&&(a?st.cleanData([e],!0):st.support.deleteExpando||u!=u.window?delete u[l]:u[l]=null)}}}function a(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(Nt,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:wt.test(r)?st.parseJSON(r):r}catch(o){}st.data(e,n,r)}else r=t}return r}function s(e){var t;for(t in e)if(("data"!==t||!st.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function u(){return!0}function l(){return!1}function c(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function f(e,t,n){if(t=t||0,st.isFunction(t))return st.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return st.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=st.grep(e,function(e){return 1===e.nodeType});if(Wt.test(t))return st.filter(t,r,!n);t=st.filter(t,r)}return st.grep(e,function(e){return st.inArray(e,t)>=0===n})}function p(e){var t=zt.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function d(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function h(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function g(e){var t=nn.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function m(e,t){for(var n,r=0;null!=(n=e[r]);r++)st._data(n,"globalEval",!t||st._data(t[r],"globalEval"))}function y(e,t){if(1===t.nodeType&&st.hasData(e)){var n,r,i,o=st._data(e),a=st._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)st.event.add(t,n,s[n][r])}a.data&&(a.data=st.extend({},a.data))}}function v(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!st.support.noCloneEvent&&t[st.expando]){r=st._data(t);for(i in r.events)st.removeEvent(t,i,r.handle);t.removeAttribute(st.expando)}"script"===n&&t.text!==e.text?(h(t).text=e.text,g(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),st.support.html5Clone&&e.innerHTML&&!st.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Zt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}function b(e,n){var r,i,o=0,a=e.getElementsByTagName!==t?e.getElementsByTagName(n||"*"):e.querySelectorAll!==t?e.querySelectorAll(n||"*"):t;if(!a)for(a=[],r=e.childNodes||e;null!=(i=r[o]);o++)!n||st.nodeName(i,n)?a.push(i):st.merge(a,b(i,n));return n===t||n&&st.nodeName(e,n)?st.merge([e],a):a}function x(e){Zt.test(e.type)&&(e.defaultChecked=e.checked)}function T(e,t){if(t in e)return t;for(var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Nn.length;i--;)if(t=Nn[i]+n,t in e)return t;return r}function w(e,t){return e=t||e,"none"===st.css(e,"display")||!st.contains(e.ownerDocument,e)}function N(e,t){for(var n,r=[],i=0,o=e.length;o>i;i++)n=e[i],n.style&&(r[i]=st._data(n,"olddisplay"),t?(r[i]||"none"!==n.style.display||(n.style.display=""),""===n.style.display&&w(n)&&(r[i]=st._data(n,"olddisplay",S(n.nodeName)))):r[i]||w(n)||st._data(n,"olddisplay",st.css(n,"display")));for(i=0;o>i;i++)n=e[i],n.style&&(t&&"none"!==n.style.display&&""!==n.style.display||(n.style.display=t?r[i]||"":"none"));return e}function C(e,t,n){var r=mn.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function k(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;4>o;o+=2)"margin"===n&&(a+=st.css(e,n+wn[o],!0,i)),r?("content"===n&&(a-=st.css(e,"padding"+wn[o],!0,i)),"margin"!==n&&(a-=st.css(e,"border"+wn[o]+"Width",!0,i))):(a+=st.css(e,"padding"+wn[o],!0,i),"padding"!==n&&(a+=st.css(e,"border"+wn[o]+"Width",!0,i)));return a}function E(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=ln(e),a=st.support.boxSizing&&"border-box"===st.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=un(e,t,o),(0>i||null==i)&&(i=e.style[t]),yn.test(i))return i;r=a&&(st.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+k(e,t,n||(a?"border":"content"),r,o)+"px"}function S(e){var t=V,n=bn[e];return n||(n=A(e,t),"none"!==n&&n||(cn=(cn||st("