Comparing version 1.0.3 to 1.1.0
@@ -1,5 +0,11 @@ | ||
# Airbrake Changelog | ||
Node Airbrake Changelog | ||
======================= | ||
### master | ||
### [v1.1.0][v1.1.0] (July 30, 2016) | ||
* **IMPORTANT:** Added support for the Hapi framework | ||
([#112](https://github.com/airbrake/node-airbrake/pull/112)) | ||
### [v1.0.3][v1.0.3] (June 24, 2016) | ||
@@ -69,1 +75,2 @@ | ||
[v1.0.3]: https://github.com/airbrake/node-airbrake/releases/tag/v1.0.3 | ||
[v1.1.0]: https://github.com/airbrake/node-airbrake/releases/tag/v1.1.0 |
@@ -12,2 +12,3 @@ var HTTP_STATUS_CODES = require('http').STATUS_CODES; | ||
var url = require('url'); | ||
var pkg = require('../package.json'); | ||
@@ -22,2 +23,3 @@ function Airbrake() { | ||
this.blackListKeys = []; | ||
this.filters = []; | ||
this.projectRoot = process.cwd(); | ||
@@ -53,3 +55,3 @@ this.appVersion = null; | ||
Airbrake.PACKAGE = (function () { | ||
Airbrake.PACKAGE = (function() { | ||
var json = fs.readFileSync(__dirname + '/../package.json', 'utf8'); | ||
@@ -59,3 +61,3 @@ return JSON.parse(json); | ||
Airbrake.createClient = function (projectId, key, env) { | ||
Airbrake.createClient = function(projectId, key, env) { | ||
var instance = new this(); | ||
@@ -68,7 +70,7 @@ instance.key = key; | ||
Airbrake.prototype.expressHandler = function (disableUncaughtException) { | ||
Airbrake.prototype.expressHandler = function(disableUncaughtException) { | ||
var self = this; | ||
if (!disableUncaughtException) { | ||
process.on('uncaughtException', function (err) { | ||
process.on('uncaughtException', function(err) { | ||
self._onError(err, true); | ||
@@ -97,4 +99,30 @@ }); | ||
Airbrake.prototype._onError = function (err, die) { | ||
Airbrake.prototype.hapiHandler = function() { | ||
var self = this; | ||
var plugin = { | ||
register: function(server, options, next) { | ||
server.on('request-error', function(req, err) { | ||
var error = err; | ||
error.url = | ||
req.connection.info.protocol + '://' + | ||
req.info.host + | ||
req.url.path; | ||
error.params = request.params; | ||
error.ua = req.headers['user-agent']; | ||
self._onError(err, false); | ||
}); | ||
next(); | ||
} | ||
}; | ||
plugin.register.attributes = { pkg: pkg }; | ||
return plugin; | ||
}; | ||
Airbrake.prototype._onError = function(err, die) { | ||
var self = this; | ||
var error = (err instanceof Error) ? err : new Error(err); | ||
@@ -104,3 +132,3 @@ self.log('Airbrake: Uncaught exception, sending notification for:'); | ||
self.notify(error, function (notifyErr, notifyUrl, devMode) { | ||
self.notify(error, function(notifyErr, notifyUrl, devMode) { | ||
if (notifyErr) { | ||
@@ -121,6 +149,6 @@ self.log('Airbrake: Could not notify service.'); | ||
Airbrake.prototype.handleExceptions = function (die) { | ||
Airbrake.prototype.handleExceptions = function(die) { | ||
var self = this; | ||
var shouldDie = (typeof die === 'undefined') ? true : die; | ||
process.on('uncaughtException', function (err) { | ||
process.on('uncaughtException', function(err) { | ||
self._onError(err, shouldDie); | ||
@@ -130,3 +158,3 @@ }); | ||
Airbrake.prototype.log = function (str) { | ||
Airbrake.prototype.log = function(str) { | ||
if (this.consoleLogError) { | ||
@@ -137,7 +165,5 @@ console.error(str); | ||
Airbrake.prototype._sendRequest = function (err, cb) { | ||
Airbrake.prototype._sendRequest = function(body, cb) { | ||
var callback = this._callback(cb); | ||
var body = this.notifyJSON(err); | ||
var options = merge({ | ||
@@ -155,5 +181,5 @@ method: 'POST', | ||
request(options, function (requestErr, res, responseBody) { | ||
request(options, function(requestErr, res, responseBody) { | ||
if (requestErr) { | ||
return callback(err); | ||
return callback(requestErr); | ||
} | ||
@@ -182,3 +208,7 @@ | ||
Airbrake.prototype.notify = function (err, cb) { | ||
Airbrake.prototype.addFilter = function(filter) { | ||
this.filters.push(filter); | ||
}; | ||
Airbrake.prototype.notify = function(err, cb) { | ||
var callback = this._callback(cb); | ||
@@ -192,3 +222,3 @@ var exit = false; | ||
this.ignoredExceptions.forEach(function (exception) { | ||
this.ignoredExceptions.forEach(function(exception) { | ||
if (err instanceof exception) { | ||
@@ -199,12 +229,20 @@ exit = true; | ||
if (exit) { | ||
var notice = this.notifyJSON(err); | ||
this.filters.forEach(function(filter) { | ||
if (notice) { | ||
notice = filter(notice); | ||
} | ||
}); | ||
if (exit || !notice) { | ||
return callback(null, null, false); | ||
} | ||
return this._sendRequest(err, callback); | ||
return this._sendRequest(stringify(notice), callback); | ||
}; | ||
Airbrake.prototype._callback = function (cb) { | ||
Airbrake.prototype._callback = function(cb) { | ||
var self = this; | ||
return function (err) { | ||
return function(err) { | ||
if (cb) { | ||
@@ -221,7 +259,7 @@ cb.apply(self, arguments); | ||
Airbrake.prototype.url = function (path) { | ||
Airbrake.prototype.url = function(path) { | ||
return this.protocol + '://' + this.serviceHost + path; | ||
}; | ||
Airbrake.prototype.environmentJSON = function (err) { | ||
Airbrake.prototype.environmentJSON = function(err) { | ||
var cgiData = {}; | ||
@@ -231,3 +269,3 @@ var self = this; | ||
if (this.whiteListKeys.length > 0) { | ||
Object.keys(process.env).forEach(function (key) { | ||
Object.keys(process.env).forEach(function(key) { | ||
if (self.whiteListKeys.indexOf(key) > -1) { | ||
@@ -240,3 +278,3 @@ cgiData[key] = process.env[key]; | ||
} else if (this.blackListKeys.length > 0) { | ||
Object.keys(process.env).forEach(function (key) { | ||
Object.keys(process.env).forEach(function(key) { | ||
if (self.blackListKeys.indexOf(key) > -1) { | ||
@@ -254,3 +292,3 @@ cgiData[key] = '[FILTERED]'; | ||
Object.keys(err).forEach(function (key) { | ||
Object.keys(err).forEach(function(key) { | ||
if (self.exclude.indexOf(key) >= 0) { | ||
@@ -282,3 +320,3 @@ return; | ||
Airbrake.prototype.contextJSON = function (err) { | ||
Airbrake.prototype.contextJSON = function(err) { | ||
var context = {}; | ||
@@ -299,7 +337,7 @@ context.notifier = { | ||
Airbrake.prototype.notifyJSON = function (err) { | ||
Airbrake.prototype.notifyJSON = function(err) { | ||
var trace = stackTrace.parse(err); | ||
var self = this; | ||
return stringify({ | ||
return { | ||
errors: [ | ||
@@ -309,3 +347,3 @@ { | ||
message: err.message, | ||
backtrace: trace.map(function (callSite) { | ||
backtrace: trace.map(function(callSite) { | ||
return { | ||
@@ -322,6 +360,6 @@ file: callSite.getFileName() || '', | ||
params: self.paramsVars(err) | ||
}); | ||
}; | ||
}; | ||
Airbrake.prototype.sessionVars = function (err) { | ||
Airbrake.prototype.sessionVars = function(err) { | ||
return (typeof err.session === 'object') | ||
@@ -332,3 +370,3 @@ ? err.session | ||
Airbrake.prototype.paramsVars = function (err) { | ||
Airbrake.prototype.paramsVars = function(err) { | ||
return (typeof err.params === 'object') | ||
@@ -339,3 +377,3 @@ ? err.params | ||
Airbrake.prototype.trackDeployment = function (params, cb) { | ||
Airbrake.prototype.trackDeployment = function(params, cb) { | ||
var callback = cb; | ||
@@ -349,3 +387,3 @@ var deploymentParams = params || {}; | ||
var getCommandValue = function (command) { | ||
var getCommandValue = function(command) { | ||
return command.stdout.toString().slice(0, -1); | ||
@@ -378,3 +416,3 @@ }; | ||
request(options, function (err, res, responseBody) { | ||
request(options, function(err, res, responseBody) { | ||
if (err) { | ||
@@ -395,3 +433,3 @@ return requestCallback(err); | ||
Airbrake.prototype.deploymentPostData = function (params) { | ||
Airbrake.prototype.deploymentPostData = function(params) { | ||
return JSON.stringify({ | ||
@@ -398,0 +436,0 @@ version: 'v2.0', |
{ | ||
"author": "Felix Geisendörfer <felix@debuggable.com> (http://debuggable.com/)", | ||
"author": "Airbrake Technologies, Inc.", | ||
"contributors": [ | ||
"Felix Geisendörfer <felix@debuggable.com> (http://debuggable.com/)", | ||
"László Bácsi <lackac@lackac.hu> (http://lackac.hu)", | ||
@@ -19,4 +20,4 @@ "Carlos Brito Lage <carlos@carloslage.net> (http://carloslage.net)", | ||
"name": "airbrake", | ||
"description": "Node.js client for airbrake.io", | ||
"version": "1.0.3", | ||
"description": "A Node.js notifier for Airbrake, the leading exception reporting service.", | ||
"version": "1.1.0", | ||
"homepage": "https://github.com/airbrake/node-airbrake", | ||
@@ -39,3 +40,3 @@ "repository": { | ||
"lodash.merge": "^4.4.0", | ||
"request": "~2.69.0", | ||
"request": "~2.74.0", | ||
"stack-trace": "~0.0.6", | ||
@@ -50,4 +51,7 @@ "sync-exec": "^0.6.2" | ||
"far": "~0.0.4", | ||
"hapi": "~13.5.0", | ||
"mockery": "~1.4.0", | ||
"nock": "^8.0.0", | ||
"nsp": "~2.2.0", | ||
"semver": "~5.3.0", | ||
"sinon": "~1.7.2" | ||
@@ -54,0 +58,0 @@ }, |
@@ -8,4 +8,2 @@ Node Airbrake | ||
[![Downloads](https://img.shields.io/npm/dt/airbrake.svg)](https://www.npmjs.com/package/airbrake) | ||
[![Issue Stats](http://issuestats.com/github/airbrake/node-airbrake/badge/pr?style=flat)](http://issuestats.com/github/airbrake/node-airbrake) | ||
[![Issue Stats](http://issuestats.com/github/airbrake/node-airbrake/badge/issue?style=flat)](http://issuestats.com/github/airbrake/node-airbrake) | ||
@@ -36,2 +34,4 @@ ![Node Airbrake][arthur-node] | ||
* Timeout Airbrake requests after 30 seconds, you never know | ||
* Express web application framework support | ||
* hapi web application framework support | ||
@@ -48,3 +48,3 @@ Installation | ||
"dependencies": { | ||
"airbrake": "~1.0.2" | ||
"airbrake": "~1.1.0" | ||
} | ||
@@ -91,2 +91,38 @@ } | ||
### Filtering errors | ||
There may be some errors thrown in your application that you're not interested in sending to Airbrake, such as errors thrown by 3rd-party libraries. | ||
The Airbrake notifier makes it simple to ignore this chaff while still processing legitimate errors. Add filters to the notifier by providing filter functions to `addFilter`. | ||
`addFilter` accepts the entire [error notice](https://airbrake.io/docs/#create-notice-v3) to be sent to Airbrake, and provides access to the `context`, `environment`, `params`, and `session` values submitted with the notice, as well as the single-element `errors` array with its `backtrace` element and associated backtrace lines. | ||
The return value of the filter function determines whether or not the error notice will be submitted. | ||
* If null value is returned, the notice is ignored. | ||
* Otherwise returned notice will be submitted. | ||
An error notice must pass all provided filters to be submitted. | ||
In the following example errors triggered with a message of 'this should not be posted to airbrake' will be ignored: | ||
```js | ||
airbrake.addFilter(function(notice) { | ||
if (notice.errors[0].message === 'this should not be posted to airbrake') { | ||
// Ignore errors with this messsage | ||
return null; | ||
} | ||
return notice; | ||
}); | ||
``` | ||
Filters can be also used to modify notice payload, e.g. to set environment and application version: | ||
```js | ||
airbrake.addFilter(function(notice) { | ||
notice.context.environment = 'production'; | ||
notice.context.version = '1.2.3'; | ||
return notice; | ||
}); | ||
``` | ||
### Manual error delivery | ||
@@ -138,2 +174,24 @@ | ||
### hapi integration | ||
The library provides out-of-box integration with the hapi framework. To | ||
integrate Airbrake with a hapi application simply install our handler: | ||
```js | ||
const Hapi = require('hapi'); | ||
const server = new Hapi.Server(); | ||
const Airbrake = require('airbrake').createClient( | ||
"your project ID", | ||
"your api key" | ||
); | ||
Airbrake.env = 'production'; | ||
server.register(Airbrake.hapiHandler(), err => { | ||
if (err) { | ||
throw err; | ||
} | ||
}); | ||
``` | ||
API | ||
@@ -313,3 +371,3 @@ --- | ||
The library was originally created by [Felix Geisendörfer](https://github.com/felixge). | ||
The project uses the MIT License. See LICENSE for details. | ||
The project uses the MIT License. See LICENSE.md for details. | ||
@@ -316,0 +374,0 @@ [arthur-node]: http://s3.amazonaws.com/airbrake-github-assets/node-airbrake/arthur-node.jpeg |
@@ -9,4 +9,4 @@ // Ignore rules for initialization file. | ||
// An account on the free plan specifically for testing this module. | ||
exports.key = '96979331ec7e18bbe7ec1529da2ed083'; | ||
exports.projectId = '122374'; | ||
exports.key = '81bbff95d52f8856c770bb39e827f3f6'; | ||
exports.projectId = '113743'; | ||
@@ -13,0 +13,0 @@ // Use custom config if available instead |
@@ -13,3 +13,3 @@ var express = require('express'); | ||
app.get('/caught', function (req, res, next) { | ||
app.get('/caught', function(req, res, next) { | ||
var err = new Error('i am caught!'); | ||
@@ -19,3 +19,3 @@ next(err); | ||
app.get('/uncaught', function () { | ||
app.get('/uncaught', function() { | ||
// This actually gets handled by app.error() as well, express will catch | ||
@@ -35,3 +35,3 @@ // this one for us. | ||
} | ||
}, function () { | ||
}, function() { | ||
assert.equal(airbrake._onError.getCall(0).args[0].ua, 'foo'); | ||
@@ -42,3 +42,3 @@ assert.equal(airbrake._onError.callCount, 1); | ||
path: '/uncaught' | ||
}, function () { | ||
}, function() { | ||
assert.equal(airbrake._onError.callCount, 2); | ||
@@ -45,0 +45,0 @@ process.exit(); |
@@ -22,3 +22,3 @@ var mockery = require('mockery'); | ||
airbrake.notify(new Error('the error'), function () {}); | ||
airbrake.notify(new Error('the error'), function() {}); | ||
@@ -41,3 +41,3 @@ assert(requestStub.calledWith( | ||
rev: '98103a8fa850d5eaf3666e419d8a0a93e535b1b2' | ||
}, function () {}); | ||
}, function() {}); | ||
@@ -44,0 +44,0 @@ assert(requestStub.calledWith( |
@@ -6,3 +6,3 @@ var common = require('../common'); | ||
var server = http.createServer(function (req, res) { | ||
var server = http.createServer(function(req, res) { | ||
res.writeHead(500); | ||
@@ -12,3 +12,3 @@ res.end('something went wrong'); | ||
server.listen(common.port, function () { | ||
server.listen(common.port, function() { | ||
var testNotifyError = new Error('test-notify'); | ||
@@ -20,3 +20,3 @@ airbrake.serviceHost = 'localhost:' + common.port; | ||
var errorTimeout = setTimeout(function () { | ||
var errorTimeout = setTimeout(function() { | ||
errorTimeout = null; | ||
@@ -28,3 +28,3 @@ if (!errorProcessed) { | ||
airbrake.on('error', function (err) { | ||
airbrake.on('error', function(err) { | ||
errorProcessed = true; | ||
@@ -31,0 +31,0 @@ if (errorTimeout !== null) { |
@@ -10,3 +10,3 @@ var common = require('../common'); | ||
process.on('exit', function () { | ||
process.on('exit', function() { | ||
var exitCode = (airbrake.notify.called) | ||
@@ -13,0 +13,0 @@ ? 0 |
@@ -6,5 +6,5 @@ var common = require('../common'); | ||
var myErr = new Error('test-notify'); | ||
airbrake.notify(myErr, function (err) { | ||
airbrake.notify(myErr, function(err) { | ||
assert.ok(!!err, 'should receive an error object'); | ||
assert.ok(/401/i.test(err.message)); | ||
}); |
var common = require('../common'); | ||
var airbrake = require(common.dir.root).createClient(null, common.key, 'production'); | ||
var airbrake = require(common.dir.root).createClient(common.projectId, common.key, 'production'); | ||
var sinon = require('sinon'); | ||
var assert = require('assert'); | ||
var nock = require('nock'); | ||
nock.disableNetConnect(); | ||
var err = new Error('Node.js just totally exploded on me'); | ||
@@ -16,3 +19,3 @@ err.env = { protect: 'the environment!' }; | ||
airbrake.on('vars', function (type, vars) { | ||
airbrake.on('vars', function(type, vars) { | ||
/* eslint no-param-reassign: 0 */ | ||
@@ -23,6 +26,11 @@ delete vars.SECRET; | ||
var spy = sinon.spy(); | ||
var endpoint = nock('https://api.airbrake.io'). | ||
post('/api/v3/projects/' + common.projectId + '/notices?key=' + common.key). | ||
reply(201, '{"url":"https://airbrake.io/locate/123"}'); | ||
airbrake.notify(err, spy); | ||
process.on('exit', function () { | ||
process.on('exit', function() { | ||
assert.ok(spy.called); | ||
endpoint.done(); | ||
@@ -29,0 +37,0 @@ var error = spy.args[0][0]; |
@@ -11,3 +11,3 @@ // Tests for throwing undefined, ignore rule. | ||
process.on('exit', function () { | ||
process.on('exit', function() { | ||
var exitCode = (airbrake.notify.called) | ||
@@ -14,0 +14,0 @@ ? 0 |
@@ -11,3 +11,3 @@ var common = require('../common'); | ||
process.on('exit', function () { | ||
process.on('exit', function() { | ||
assert.strictEqual(spy.args[0][0], null); | ||
@@ -14,0 +14,0 @@ assert.deepEqual(Object.keys(spy.args[0][1]), [ |
Sorry, the diff of this file is not supported yet
49286
27
930
376
11
23
4
+ Addedbl@1.1.2(transitive)
+ Addedpunycode@1.4.1(transitive)
+ Addedqs@6.2.4(transitive)
+ Addedrequest@2.74.0(transitive)
+ Addedtough-cookie@2.3.4(transitive)
- Removedbl@1.0.3(transitive)
- Removedqs@6.0.4(transitive)
- Removedrequest@2.69.0(transitive)
- Removedtough-cookie@2.2.2(transitive)
Updatedrequest@~2.74.0