Skip to content

Commit

Permalink
fix: use circular-json to format error properties (#26)
Browse files Browse the repository at this point in the history
util.inspect can lead to OOM in some situation
  • Loading branch information
dead-horse authored and popomore committed Jul 9, 2018
1 parent 08f255e commit b80560b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
36 changes: 35 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const chalk = require('chalk');
const utility = require('utility');
const iconv = require('iconv-lite');
const levels = require('./level');
const circularJSON = require('circular-json');

const hostname = os.hostname();
const duartionRegexp = /([0-9]+ms)/g;
Expand Down Expand Up @@ -154,5 +155,38 @@ function formatError(err) {
}

function inspect(key, value) {
return `${key}: ${util.inspect(value, { breakLength: Infinity })}`;
return `${key}: ${formatObject(value)}`;
}

function formatString(str) {
if (str.length > 10000) {
return `${str.substr(0, 10000)}...(${str.length})`;
}
return str;
}

function formatBuffer(buf) {
const tail = buf.data.length > 50 ? ` ...(${buf.data.length}) ` : '';
const bufStr = buf.data.slice(0, 50).map(i => {
i = i.toString(16);
if (i.length === 1) i = `0${i}`;
return i;
}).join(' ');
return `<Buffer ${bufStr}${tail}>`;
}

function formatObject(obj) {
try {
return circularJSON.stringify(obj, (key, v) => {
if (typeof v === 'string') return formatString(v);
if (v && v.type === 'Buffer' && Array.isArray(v.data)) {
return formatBuffer(v);
}
if (v instanceof RegExp) return util.inspect(v);
return v;
});
} catch (_) {
/* istanbul ignore next */
return String(obj);
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "index.js",
"dependencies": {
"chalk": "^1.1.3",
"circular-json": "^0.5.4",
"debug": "^2.6.2",
"depd": "^1.1.0",
"iconv-lite": "^0.4.15",
Expand Down
21 changes: 11 additions & 10 deletions test/lib/formatter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,26 @@ describe('test/lib/formatter.test.js', () => {
}];
err.content = '123\n123';
err.buf = new Buffer(1000).fill(0);
err.shortBuf = new Buffer(30).fill(101);
err.regex = /^hello!+$/;
err.userId = 100;
err.longText = new Array(20000).join('1');
err.isTrue = true;
logger.error(err);

yield sleep(10);

const content = fs.readFileSync(filepath, 'utf8');
content.should.containEql('nodejs.MySomeError: foo (eggjs.org)\n');
content.should.containEql('addition: { userId: 12345, message: \'mock error\\n\\n\', sub: { foo: {} } }');
content.should.containEql('content: \'123\\n123\'');
content.should.containEql('buf: <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >');
content.should.containEql('regex: /^hello!+$/');
content.should.containEql('addition: {"userId":12345,"message":"mock error\\n\\n","sub":{"foo":{}}}');
content.should.containEql('content: "123\\n123"');
content.should.containEql('buf: "<Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...(1000) >"');
content.should.containEql('shortBuf: "<Buffer 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65>"');
content.should.containEql('regex: "/^hello!+$/"');
content.should.containEql('userId: 100');
// node 4 don't support inspectOptions.breakLength
if (parseInt(process.version.slice(1)) <= 4) {
content.should.containEql('errors: [ { code: \'missing_field\', field: \'name\', message: \'required\' },\n { code: \'invalid\',\n field: \'age\',\n message: \'should be an integer\' } ]');
} else {
content.should.containEql('errors: [ { code: \'missing_field\', field: \'name\', message: \'required\' }, { code: \'invalid\', field: \'age\', message: \'should be an integer\' } ]');
}
content.should.containEql('errors: [{"code":"missing_field","field":"name","message":"required"},{"code":"invalid","field":"age","message":"should be an integer"}]');
content.should.containEql('...(19999)');
content.should.containEql('isTrue: true');
});

it('should format error with options.formatter', function*() {
Expand Down

0 comments on commit b80560b

Please sign in to comment.