diff --git a/README.md b/README.md index f8db21e..11a5751 100644 --- a/README.md +++ b/README.md @@ -279,8 +279,9 @@ console.log(info); ### Errors -The `errors` format allows you to pass in an instance of a JavaScript `Error` directly to the logger. -It allows you to specify whether not to include the stack-trace. +The `errors` format allows you to pass in an instance of a JavaScript `Error` +directly to the logger. It allows you to specify whether not to include the +stack-trace. ```js const { format } = require('logform'); @@ -304,6 +305,32 @@ console.log(info); // at REPLServer.Interface._line (readline.js:631:8) ``` +It will also handle `{ message }` properties as `Error` instances: + +```js +const { format } = require('logform'); +const { errors } = format; + +const errorsFormat = errors({ stack: true }) + +const info = errorsFormat.transform({ + message: new Error('Oh no!') +}); + +console.log(info); +// Error: Oh no! +// at repl:1:13 +// at ContextifyScript.Script.runInThisContext (vm.js:50:33) +// at REPLServer.defaultEval (repl.js:240:29) +// at bound (domain.js:301:14) +// at REPLServer.runBound [as eval] (domain.js:314:12) +// at REPLServer.onLine (repl.js:468:10) +// at emitOne (events.js:121:20) +// at REPLServer.emit (events.js:211:7) +// at REPLServer.Interface._onLine (readline.js:282:10) +// at REPLServer.Interface._line (readline.js:631:8) +``` + ### JSON The `json` format uses `fast-safe-stringify` to finalize the message. diff --git a/errors.js b/errors.js index 26fcc64..b7a0975 100644 --- a/errors.js +++ b/errors.js @@ -2,7 +2,7 @@ 'use strict'; const format = require('./format'); -const { MESSAGE } = require('triple-beam'); +const { LEVEL, MESSAGE } = require('triple-beam'); /* * function errors (info) @@ -11,15 +11,29 @@ const { MESSAGE } = require('triple-beam'); * * Optionally, the Error's `stack` property can also be appended to the `info` object. */ -module.exports = format((info, opts) => { - if (!(info.message instanceof Error)) return info; +module.exports = format((einfo, { stack }) => { + if (einfo instanceof Error) { + const info = Object.assign({}, einfo, { + level: einfo.level, + [LEVEL]: einfo[LEVEL] || einfo.level, + message: einfo.message, + [MESSAGE]: einfo[MESSAGE] || einfo.message + }); - const err = info.message; + if (stack) info.stack = einfo.stack; + return info; + } - info.message = err.message; - info[MESSAGE] = err.message; + if (!(einfo.message instanceof Error)) return einfo; - if (opts.stack) info.stack = err.stack; + // Assign all enumerable properties and the + // message property from the error provided. + Object.assign(einfo, einfo.message); + const err = einfo.message; + einfo.message = err.message; + einfo[MESSAGE] = err.message; - return info; + // Assign the stack if requested. + if (stack) einfo.stack = err.stack; + return einfo; }); diff --git a/package-lock.json b/package-lock.json index 2bc2904..0a3cdf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { @@ -21,7 +21,7 @@ "dependencies": { "acorn": { "version": "3.3.0", - "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", "dev": true } @@ -47,7 +47,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -379,13 +379,13 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", "dev": true }, @@ -966,7 +966,7 @@ }, "callsites": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, @@ -977,14 +977,14 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30000923", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000923.tgz", - "integrity": "sha512-j5ur7eeluOFjjPUkydtXP4KFAsmH3XaQNch5tvWSO+dLHYt5PE+VgJZLWtbVOodfWij6m6zas28T4gB/cLYq1w==", + "version": "1.0.30000927", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000927.tgz", + "integrity": "sha512-ogq4NbUWf1uG/j66k0AmiO3GjqJAlQyF8n4w8a954cbCyFKmYGvRtgz6qkq2fWuduTXHibX7GyYL5Pg58Aks2g==", "dev": true }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1164,7 +1164,7 @@ }, "concat-stream": { "version": "1.6.2", - "resolved": "http://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { @@ -1334,9 +1334,9 @@ } }, "electron-to-chromium": { - "version": "1.3.96", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.96.tgz", - "integrity": "sha512-ZUXBUyGLeoJxp4Nt6G/GjBRLnyz8IKQGexZ2ndWaoegThgMGFO1tdDYID5gBV32/1S83osjJHyfzvanE/8HY4Q==", + "version": "1.3.97", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.97.tgz", + "integrity": "sha512-cElMxsoUl8BoY+DnTNXebdVuDz/l0HS5ijpq1uUcHNMrzFiQRKmADn39luHVIaeISO8qtFbNmqhSBU/BQCHwig==", "dev": true }, "error-ex": { @@ -1356,7 +1356,7 @@ }, "eslint": { "version": "4.19.1", - "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "dev": true, "requires": { @@ -1529,7 +1529,7 @@ }, "espree": { "version": "3.5.4", - "resolved": "http://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { @@ -1600,7 +1600,7 @@ }, "expand-range": { "version": "1.8.2", - "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "optional": true, @@ -1631,7 +1631,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -1652,7 +1652,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, @@ -1675,7 +1675,7 @@ }, "fecha": { "version": "2.3.3", - "resolved": "http://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, "figures": { @@ -2325,7 +2325,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -2612,7 +2612,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -2643,7 +2643,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -2652,7 +2652,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -2843,7 +2843,7 @@ }, "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -2861,7 +2861,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, @@ -2915,7 +2915,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -3030,7 +3030,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, @@ -3057,7 +3057,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -3085,7 +3085,7 @@ "dependencies": { "commander": { "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -6334,7 +6334,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "optional": true, @@ -6356,7 +6356,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "optional": true, @@ -6635,7 +6635,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -6719,12 +6719,12 @@ "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "run-async": { diff --git a/test/errors.test.js b/test/errors.test.js index 0f84707..3b8944e 100644 --- a/test/errors.test.js +++ b/test/errors.test.js @@ -7,7 +7,30 @@ const { MESSAGE } = require('triple-beam'); const err = new Error('whatever'); -describe('errors', () => { +const errProps = new Error('another error'); +errProps.whatever = true; +errProps.wut = 'some string'; + +const errInfo = new Error('Already has level'); +errInfo.level = 'error'; + +const errInfoProps = new Error('Level with props'); +errInfoProps.level = 'error'; +errInfoProps.whatever = true; +errInfoProps.wut = 'some string'; + +describe('errors()({ object })', () => { + it('errors() returns the original info', assumeFormatted( + errors(), + { level: 'info', message: 'whatever' }, + (info) => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals('whatever'); + } + )); + it('errors() (default) sets info[MESSAGE]', assumeFormatted( errors(), { level: 'info', message: err }, @@ -20,7 +43,7 @@ describe('errors', () => { } )); - it('errors({ space: 2 }) sets info.stack', assumeFormatted( + it('errors({ stack: true }) sets info.stack', assumeFormatted( errors({ stack: true }), { level: 'info', message: err }, (info) => { @@ -28,8 +51,51 @@ describe('errors', () => { assume(info.message).is.a('string'); assume(info.level).equals('info'); assume(info.message).equals(err.message); - assume(info.stack).equals(err.stack); assume(info[MESSAGE]).equals(err.message); + assume(info.stack).equals(err.stack); } )); + + it('errors() sets custom error properties', assumeFormatted( + errors(), + { level: 'info', message: errProps }, + (info) => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals('info'); + assume(info.message).equals(errProps.message); + assume(info[MESSAGE]).equals(errProps.message); + assume(info.whatever).true(); + assume(info.wut).equals('some string'); + } + )); +}); + +describe('errors()(Error)', () => { + it('errors() (default) sets info[MESSAGE]', assumeFormatted( + errors(), + errInfo, + (info) => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals(errInfo.level); + assume(info.message).equals(errInfo.message); + assume(info[MESSAGE]).equals(errInfo.message); + }, + { immutable: false } + )); + + it('errors({ space: 2 }) sets info.stack', assumeFormatted( + errors({ stack: true }), + errInfo, + (info) => { + assume(info.level).is.a('string'); + assume(info.message).is.a('string'); + assume(info.level).equals(errInfo.level); + assume(info.message).equals(errInfo.message); + assume(info[MESSAGE]).equals(errInfo.message); + assume(info.stack).equals(errInfo.stack); + }, + { immutable: false } + )); }); diff --git a/test/helpers.js b/test/helpers.js index 4a60fad..360aa48 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -39,14 +39,18 @@ exports.infoify = info => { * of the `colorize` format and asserts that the * correct `info` object was processed. */ -exports.assumeFormatted = (fmt, info, assertion) => { +exports.assumeFormatted = (fmt, info, assertion, opts = {}) => { return done => { const writable = exports.writable(actual => { assertion(actual, info); done(); }); - writable.write(fmt.transform(Object.assign({}, info), fmt.options)); + const value = opts.immutable === false + ? info + : Object.assign({}, info); + + writable.write(fmt.transform(value, fmt.options)); }; };