Skip to content

Instantly share code, notes, and snippets.

@logicalparadox
Created January 8, 2012 07:01
Show Gist options
  • Save logicalparadox/1577534 to your computer and use it in GitHub Desktop.
Save logicalparadox/1577534 to your computer and use it in GitHub Desktop.
Designing `loggable` custom error constructors for Node.js.

Custom Errors

I am working on a custom error constructor for my seed project. I had a few objectives in mind when I started.

  • When in production, these errors need to be able to be serialized for logging.
  • When in development, I can easily throw these errors should I need additional feedback on to what is going on.
  • Any addon plugins made can use or extend the custom error type and still satisfy the first two objective with ease.

Screenshot

Technically inspired by this post.

var util = require('util');
function colorize (str, color) {
var options = {
red: '\u001b[31m'
, green: '\u001b[32m'
, yellow: '\u001b[33m'
, blue: '\u001b[34m'
, magenta: '\u001b[35m'
, cyan: '\u001b[36m'
, gray: '\u001b[90m'
, reset: '\u001b[0m'
};
return options[color] + str + options.reset;
};
function pad (str, width) {
return Array(width - str.length).join(' ') + str;
};
module.exports = CustomError;
function CustomError (msg) {
Error.call(this);
// Write our opts to the object
this.message = msg;
this.name = 'CustomError';
this.memory = process.memoryUsage();
// We need the raw stack so we can make a JSON
// object for writing to the logs.
var orig = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack){ return stack; };
Error.captureStackTrace(this, arguments.callee);
this.__stack = this.stack;
Error.prepareStackTrace = orig;
// Lets make our JSON object.
this._stack = [];
for (var i = 0; i < this.__stack.length; i ++) {
var frame = this.__stack[i];
this._stack.push({
filename: frame.getFileName()
, typename: frame.getTypeName()
, linenum: frame.getLineNumber()
, funcname: frame.getFunctionName()
, method: frame.getMethodName()
});
}
// Since we provided our own prepareStackTrace, we need
// to provide a new stack getter for display. Lets make
// it look better while we are at it.
Object.defineProperty(this, 'stack', {
get: function () {
var buf = [];
buf.push('');
buf.push(pad('', 8) + colorize(this.name, 'red'));
buf.push(pad('', 8) + colorize(Array(this.name.length + 1).join('-'), 'gray'));
buf.push(pad('', 8) + colorize(this.message, 'magenta'));
buf.push(pad('', 8) + colorize((this.memory.heapTotal / 1048576).toFixed(3) + ' MB', 'blue') + colorize(' total ', 'gray'));
buf.push(pad('', 8) + colorize((this.memory.heapUsed / 1048576).toFixed(3) + ' MB', 'blue') + colorize(' used ', 'gray'));
buf.push(pad('', 8) + colorize(Array(this.name.length + 1).join('-'), 'gray'));
buf.push('');
this._stack.forEach(function (frame) {
buf.push(' ' + colorize(pad(frame.linenum + '', 5), 'blue') + colorize(' ' + frame.filename, 'gray') );
buf.push(pad('', 8) + colorize((frame.funcname ? frame.funcname : 'Anonymous'), 'green') + ' ' + colorize('[' + frame.typename + ']', 'yellow'));
});
buf.push('');
return buf.join('\n');
}
});
}
util.inherits(CustomError, Error);
CustomError.prototype.toJSON = function () {
return {
name: this.name
, message: this.message
, memory: this.memory
, stack: this._stack
};
}
var CustomError = require('./customerror');
function log (err) {
console.error(err);
}
function a (){
b();
}
function b () {
var err = new CustomError('There was a problem doing something in your app.');
log(err.toJSON());
throw err;
}
a();
@adriano-di-giovanni
Copy link

I understand that you have to define the stack property because you overridden Error.prepareStackTrace.

If you don't really need to custom format the stack, you can try to do as follows

function LoggableError(message) {
  var
    obj = {};

  this.message = message;
  this.name = 'LoggableError';

  Error.captureStackTrace(obj, LoggableError);
  this.stack = obj.stack;
}

LoggableError.prototype = Object.create(Error.prototype);
LoggableError.prototype.constructor = LoggableError;

module.exports = LoggableError;

I used this chunk of code on node-error and it works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment