Skip to content

Commit 72e662a

Browse files
committed
adding uncaught exception handler
1 parent 1fbd4a0 commit 72e662a

File tree

9 files changed

+180
-7
lines changed

9 files changed

+180
-7
lines changed

lib/apps/users/controller.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ var responder = main.server.responder;
33

44
var methods = {
55
create: function (req, res, next) {
6+
//throw new Error('foo');
67
User.create(req.params, function (err, user) {
78
responder.respond(res, err, {data: user}, next);
89
});

lib/server/app_server.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var path = require('path');
22
var restify = require('restify');
33
var Logger = require('bunyan');
4+
var UncaughtExceptionHandler = require('./uncaught_exception_handler');
45

56
var ENV = process.env.NODE_ENV;
67

@@ -19,13 +20,14 @@ function AppServer(config) {
1920
var self = this;
2021
self.config = config;
2122
self.started = false;
22-
23-
// TODO:
24-
//var uncaught_exception_handler = require('./uncaught_exception_handler')({app_name: app_name});
2523
if (!config) { throw new Error("AppServer requires a config object"); }
2624

25+
var app_name = self.config.app_name || 'MyApi';
26+
27+
var uncaught_exception_handler = new UncaughtExceptionHandler({app_name: app_name});
28+
2729
self.server = restify.createServer({
28-
name: config.app_name || 'MyApi',
30+
name: app_name,
2931
log: logger
3032
});
3133

@@ -34,6 +36,8 @@ function AppServer(config) {
3436
log: logger
3537
}));
3638

39+
self.server.on('uncaughtException', uncaught_exception_handler.handle);
40+
3741
process.on('SIGHUP', function () { process.exit(); });
3842
}
3943

lib/server/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ var server = {
22
AppRegistrar: require('./app_registrar'),
33
AppServer: require('./app_server'),
44
responder: require('./responder'),
5-
router: require('./router')
5+
router: require('./router'),
6+
UncaughtExceptionHandler: require('./uncaught_exception_handler')
67
};
78

89
module.exports = server;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Handler for exceptions that are not handled by the application code.
3+
* @class
4+
* @see AppServer
5+
*/
6+
7+
function UncaughtExceptionHandler(args) {
8+
args = args || {};
9+
var self = this;
10+
self.app_name = args.app_name || '';
11+
}
12+
13+
UncaughtExceptionHandler.prototype.handle = function (req, res, route, err) {
14+
var self = this;
15+
16+
if (err) {
17+
var msg = '[app] ';
18+
if (self.app_name) {
19+
msg += self.app_name + ' ';
20+
}
21+
msg += 'uncaught exception';
22+
23+
console.log(msg);
24+
25+
if (route && route.spec) {
26+
console.log('Route: ' + route.spec.method + ' ' + route.spec.path);
27+
}
28+
29+
console.log(err);
30+
console.log(err.stack);
31+
32+
res.header('Content-Type', 'application/json; charset=utf-8');
33+
res.charSet = "utf-8";
34+
res.status(500);
35+
res.json(err);
36+
}
37+
};
38+
39+
module.exports = UncaughtExceptionHandler;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nodejs-tdd-boilerplate",
3-
"version": "0.0.4",
3+
"version": "0.0.5",
44
"description": "TDD boilerplate for NodeJS API apps",
55
"author": "Bryan Donovan",
66
"engines": {

test/acceptance/users/create.acceptance.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ describe("Feature: User creation", function () {
2222
};
2323

2424
http_client.post('/users', params, function (err, result, raw) {
25+
console.log("\nHERE\n");
26+
console.log(result);
2527
assert.ifError(err);
2628
response = result;
2729
raw_res = raw;

test/server/app_server.unit.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var assert = require('assert');
2+
require('../support');
23
var Settings = require('settings');
34
var config = new Settings(require('../../config'));
45
var AppServer = main.server.AppServer;
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
var assert = require('assert');
2+
var sinon = require('sinon');
3+
var support = require('../support');
4+
var UncaughtExceptionHandler = main.server.UncaughtExceptionHandler;
5+
6+
describe("UncaughtExceptionHandler", function () {
7+
describe("instantiating", function () {
8+
it("sets self.app_name", function () {
9+
var app_name = support.random.string();
10+
var handler = new UncaughtExceptionHandler({app_name: app_name});
11+
assert.strictEqual(handler.app_name, app_name);
12+
});
13+
14+
it("sets self.app_name to '' by default", function () {
15+
var handler = new UncaughtExceptionHandler();
16+
assert.strictEqual(handler.app_name, '');
17+
});
18+
});
19+
20+
describe("handle()", function () {
21+
var handler;
22+
var app_name;
23+
var error;
24+
var req = {};
25+
var res = {
26+
header: function () {},
27+
status: function () {},
28+
json: function () {}
29+
};
30+
31+
var route = {spec: {method: 'POST', path: '/foo/bar'}};
32+
33+
beforeEach(function () {
34+
app_name = support.random.string();
35+
handler = new UncaughtExceptionHandler({app_name: app_name});
36+
error = support.fake_error();
37+
});
38+
39+
context("whe no error passed in", function () {
40+
it("doesn't log to console", function () {
41+
sinon.stub(console, 'log');
42+
43+
handler.handle(req, res, route);
44+
assert.ok(!console.log.called);
45+
46+
console.log.restore();
47+
});
48+
});
49+
50+
it("logs meta info to the console", function () {
51+
sinon.stub(console, 'log');
52+
53+
handler.handle(req, res, route, error);
54+
var expected = /\[app\].*uncaught exception/i;
55+
assert.ok(console.log.calledWithMatch(expected));
56+
57+
console.log.restore();
58+
});
59+
60+
it("logs route info to the console", function () {
61+
sinon.stub(console, 'log');
62+
63+
handler.handle(req, res, route, error);
64+
var expected = 'Route: ' + route.spec.method + ' ' + route.spec.path;
65+
assert.ok(console.log.calledWith(expected));
66+
67+
console.log.restore();
68+
});
69+
70+
it("doesn't log route info if no route passed in", function () {
71+
sinon.stub(console, 'log');
72+
73+
handler.handle(req, res, null, error);
74+
var route_regex = /Route/;
75+
assert.ok(!console.log.calledWithMatch(route_regex));
76+
77+
console.log.restore();
78+
});
79+
80+
it("logs error to the console", function () {
81+
sinon.stub(console, 'log');
82+
83+
handler.handle(req, res, route, error);
84+
assert.ok(console.log.calledWith(error));
85+
86+
console.log.restore();
87+
});
88+
89+
it("logs error's stack to the console", function () {
90+
sinon.stub(console, 'log');
91+
92+
handler.handle(req, res, route, error);
93+
assert.ok(console.log.calledWith(error.stack));
94+
95+
console.log.restore();
96+
});
97+
98+
it("doesn't throw an error when no app_name is set", function () {
99+
sinon.stub(console, 'log');
100+
handler = new UncaughtExceptionHandler();
101+
102+
handler.handle(req, res, route, error);
103+
assert.ok(console.log.calledWith(error));
104+
105+
console.log.restore();
106+
});
107+
108+
it("calls res.json() with error", function () {
109+
sinon.stub(console, 'log');
110+
sinon.stub(res, 'json');
111+
112+
handler.handle(req, res, route, error);
113+
assert.ok(res.json.calledWith(error));
114+
115+
res.json.restore();
116+
console.log.restore();
117+
});
118+
});
119+
});

test/support/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require('../../lib');
22

3-
module.exports = {
3+
var support = {
44
http: require('./http'),
55
random: require('./random'),
66
walk_dir: require('./walk_dir'),
@@ -13,5 +13,11 @@ module.exports = {
1313
});
1414
}
1515
return ret;
16+
},
17+
18+
fake_error: function (message) {
19+
return new Error(message || support.random.string());
1620
}
1721
};
22+
23+
module.exports = support;

0 commit comments

Comments
 (0)