├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── index.js ├── package.json └── test └── index.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | coverage.html 17 | dump.rdb 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '1' 4 | - '2' 5 | - '3' 6 | - '4' 7 | script: make test 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 dead_horse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TESTS = test/*.test.js 2 | REPORTER = tap 3 | TIMEOUT = 3000 4 | MOCHA_OPTS = 5 | 6 | ISTANBUL = ./node_modules/.bin/istanbul 7 | MOCHA = ./node_modules/mocha/bin/_mocha 8 | 9 | install: 10 | @npm install --registry=https://registry.npmmirror.com 11 | 12 | test: 13 | @NODE_ENV=test ./node_modules/mocha/bin/mocha \ 14 | --reporter $(REPORTER) \ 15 | --timeout $(TIMEOUT) \ 16 | --require should \ 17 | $(MOCHA_OPTS) \ 18 | $(TESTS) 19 | 20 | test-cov: 21 | @$(ISTANBUL) cover --report html $(MOCHA) -- -t $(TIMEOUT) \ 22 | --require should -R spec $(TESTS) 23 | 24 | .PHONY: test 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | error-formatter 2 | --------- 3 | 4 | [![NPM version][npm-image]][npm-url] 5 | [![build status][travis-image]][travis-url] 6 | [![David deps][david-image]][david-url] 7 | [![node version][node-image]][node-url] 8 | [![Gittip][gittip-image]][gittip-url] 9 | 10 | [npm-image]: https://img.shields.io/npm/v/error-formatter.svg?style=flat-square 11 | [npm-url]: https://npmjs.org/package/error-formatter 12 | [travis-image]: https://img.shields.io/travis/node-modules/error-formatter.svg?style=flat-square 13 | [travis-url]: https://travis-ci.org/node-modules/error-formatter 14 | [coveralls-image]: https://img.shields.io/coveralls/node-modules/error-formatter.svg?style=flat-square 15 | [coveralls-url]: https://coveralls.io/r/node-modules/error-formatter?branch=master 16 | [david-image]: https://img.shields.io/david/node-modules/error-formatter.svg?style=flat-square 17 | [david-url]: https://david-dm.org/node-modules/error-formatter 18 | [node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square 19 | [node-url]: http://nodejs.org/download/ 20 | [gittip-image]: https://img.shields.io/gittip/dead-horse.svg?style=flat-square 21 | [gittip-url]: https://www.gittip.com/dead-horse/ 22 | 23 | Formate error to string or json, for log use. 24 | 25 | ## Install 26 | 27 | ```bash 28 | npm install error-formatter 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```js 34 | var formater = require('error-formatter'); 35 | 36 | var err = new Error('test error'); 37 | err.host = '127.0.0.1'; 38 | err.code = 'DUPLICATE'; 39 | err.url = '/error'; 40 | err.data = {foo: 'bar'}; 41 | 42 | var msg = formater(err); 43 | var json = formater.json(err); 44 | var both = formater.bot(err); // yield {text: text, json: json} 45 | ``` 46 | 47 | yield 48 | 49 | ``` 50 | 2014-07-07 15:11:26.421 nodejs.ErrorException: DUPLICATEError: test error (127.0.0.1) 51 | at Object. (/Users/deadhorse/git/error-formatter/test/index.test.js:15:11) 52 | at Module._compile (module.js:449:26) 53 | at Object.Module._extensions..js (module.js:467:10) 54 | at Module.load (module.js:349:32) 55 | at Function.Module._load (module.js:305:12) 56 | at Module.require (module.js:357:17) 57 | at require (module.js:373:17) 58 | at /Users/deadhorse/git/error-formatter/node_modules/mocha/lib/mocha.js:172:27 59 | at Array.forEach (native) 60 | at Mocha.loadFiles (/Users/deadhorse/git/error-formatter/node_modules/mocha/lib/mocha.js:169:14) 61 | at Mocha.run (/Users/deadhorse/git/error-formatter/node_modules/mocha/lib/mocha.js:356:31) 62 | at Object. (/Users/deadhorse/git/error-formatter/node_modules/mocha/bin/_mocha:366:16) 63 | at Module._compile (module.js:449:26) 64 | at Object.Module._extensions..js (module.js:467:10) 65 | at Module.load (module.js:349:32) 66 | at Function.Module._load (module.js:305:12) 67 | at Function.Module.runMain (module.js:490:10) 68 | at startup (node.js:124:16) 69 | at node.js:803:3 70 | pid: 91000 71 | Host: dead-horsedeMacBook-Pro.local 72 | URL: /error 73 | Data: {"foo":"bar"} 74 | 2014-07-07 15:11:26.421 75 | ``` 76 | 77 | ## License 78 | 79 | MIT 80 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * project - module 3 | * Copyright(c) 2014 dead_horse 4 | * MIT Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var os = require('os'); 14 | var util = require('util'); 15 | var utility = require('utility'); 16 | 17 | /** 18 | * Expose `formater` 19 | */ 20 | 21 | module.exports = text; 22 | text.json = json; 23 | text.both = both; 24 | 25 | 26 | function text(err) { 27 | var infos = json(err); 28 | return format(infos); 29 | } 30 | 31 | function both(err) { 32 | var infos = json(err); 33 | var text = format(infos); 34 | 35 | return { 36 | text: text, 37 | json: infos 38 | } 39 | } 40 | 41 | function json(err) { 42 | if (!(err instanceof Error)) throw new TypeError('input non-error object: ' + err); 43 | 44 | var infos = { 45 | name: err.name, 46 | message: err.message, 47 | url: err.url || '', 48 | data: err.data || '', 49 | pid: process.pid, 50 | code: err.code 51 | }; 52 | 53 | if (err.name === 'Error' && typeof err.code === 'string') { 54 | infos.name = err.code + err.name; 55 | } 56 | 57 | if (err.host) { 58 | infos.host = err.host; 59 | infos.message += ' (' + infos.host + ')'; 60 | } 61 | infos.name = infos.name + 'Exception'; 62 | infos.time = utility.logDate(); 63 | infos.hostname = os.hostname(); 64 | // name and stack could not be change on node 0.11+ 65 | var errName = err.name; 66 | 67 | var errStack = err.stack || 'no_stack'; 68 | infos.stack = errName + ': ' + infos.message + '\n' + errStack.substring(errStack.indexOf('\n') + 1); 69 | return infos; 70 | } 71 | 72 | var safeStringify = function (data, max) { 73 | var str = util.inspect(data); 74 | if (str.length > max) { 75 | str = str.substring(0, max); 76 | } 77 | return str; 78 | }; 79 | 80 | var formatTpl = '%s nodejs.%s: %s' + os.EOL + 81 | 'pid: %s' + os.EOL + 82 | 'Host: %s' + os.EOL + 83 | 'URL: %s' + os.EOL + 84 | 'Data: %s' + os.EOL + 85 | '%s'; 86 | 87 | function format(infos) { 88 | return util.format(formatTpl, 89 | infos.time, 90 | infos.name, 91 | infos.stack, 92 | infos.pid, 93 | infos.hostname, 94 | infos.url, 95 | safeStringify(infos.data, 1024), 96 | infos.time 97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "error-formatter", 3 | "version": "1.0.5", 4 | "description": "format an error into string / json for log", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "make test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:node-modules/error-formatter.git" 12 | }, 13 | "keywords": [ 14 | "error", 15 | "log", 16 | "string", 17 | "json" 18 | ], 19 | "author": "dead_horse ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/node-modules/error-formatter/issues" 23 | }, 24 | "homepage": "https://github.com/node-modules/error-formatter", 25 | "devDependencies": { 26 | "mocha": "^1.20.1", 27 | "should": "^4.0.4", 28 | "istanbul": "*" 29 | }, 30 | "dependencies": { 31 | "utility": "^1.0.0" 32 | }, 33 | "files": [ 34 | "index.js" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * error-formater - test/index.test.js 3 | * Copyright(c) 2014 dead_horse 4 | * MIT Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | var formater = require('../'); 14 | 15 | var err = new Error('test error'); 16 | err.host = '127.0.0.1'; 17 | err.code = 'DUPLICATE'; 18 | err.url = '/error'; 19 | err.data = { 20 | one: 'bar', 21 | tow: { 22 | a: 1, 23 | third: { 24 | hello: 'world', 25 | fourth: { 26 | foo: 'bar' 27 | } 28 | } 29 | } 30 | }; 31 | 32 | describe('error-formatter', function () { 33 | it('should format error to string', function () { 34 | var s = formater(err); 35 | s.should.containEql('DUPLICATEError'); 36 | s.should.containEql('pid:'); 37 | s.should.containEql('URL:'); 38 | s.should.containEql('Data: { one: \'bar\',\n tow: { a: 1, third: { hello: \'world\', fourth: [Object] } } }'); 39 | }); 40 | 41 | it('should format error to json', function () { 42 | var s = formater.json(err); 43 | s.should.have.keys([ 44 | 'name', 45 | 'message', 46 | 'url', 47 | 'data', 48 | 'pid', 49 | 'code', 50 | 'host', 51 | 'time', 52 | 'hostname', 53 | 'stack' 54 | ]); 55 | }); 56 | 57 | it('should format non-error to json with exception', function () { 58 | (function () { 59 | formater.json("non-json"); 60 | }).should.throw(/input non-error object: non-json/); 61 | }); 62 | 63 | it('should format both ok', function () { 64 | var s = formater.both(err); 65 | s.text.should.containEql('DUPLICATEError'); 66 | s.text.should.containEql('pid:'); 67 | s.text.should.containEql('URL:'); 68 | s.text.should.containEql('Data: { one: \'bar\',\n tow: { a: 1, third: { hello: \'world\', fourth: [Object] } } }'); 69 | 70 | s.json.should.have.keys([ 71 | 'name', 72 | 'message', 73 | 'url', 74 | 'data', 75 | 'pid', 76 | 'code', 77 | 'host', 78 | 'time', 79 | 'hostname', 80 | 'stack' 81 | ]); 82 | }) 83 | 84 | it('should format big data safely ok', function () { 85 | var buff = new Buffer(1025).fill('a'); 86 | err.data = buff.toString(); 87 | var s = formater(err); 88 | s.should.containEql('DUPLICATEError'); 89 | s.should.containEql('pid:'); 90 | s.should.containEql('URL:'); 91 | var matched = s.match(/Data: '([^\n]*)/); 92 | var line = matched && matched[1]; 93 | line.length.should.lessThan(1025); 94 | }) 95 | }); 96 | --------------------------------------------------------------------------------