[OError] getFullInfo returns the error context of nested causes (#14)

* [OError] add getFullInfoIncludeCause for retrieving nested cause info

* Revert "[OError] add getFullInfoIncludeCause for retrieving nested cause info"

This reverts commit 4c7517255a0f37ba94223e559a3926f19bab618d

* [OError] getFullInfo returns the error context of nested causes

* [OError] getFullInfo flip sequence of merging, add test case for it
This commit is contained in:
Jakob Ackermann 2020-12-02 11:44:17 +00:00 committed by GitHub
parent 9b739f1c7d
commit a5e5d9b1cd
4 changed files with 38 additions and 10 deletions

View file

@ -442,7 +442,7 @@ async function cleanup() {
<a name="OError.getFullInfo"></a> <a name="OError.getFullInfo"></a>
### OError.getFullInfo(error) ⇒ <code>Object</code> ### OError.getFullInfo(error) ⇒ <code>Object</code>
The merged info from any `tag`s on the given error. The merged info from any `tag`s and causes on the given error.
If an info property is repeated, the last one wins. If an info property is repeated, the last one wins.
@ -450,7 +450,7 @@ If an info property is repeated, the last one wins.
| Param | Type | Description | | Param | Type | Description |
| --- | --- | --- | | --- | --- | --- |
| error | <code>Error</code> \| <code>null</code> \| <code>undefined</code> | any errror (may or may not be an `OError`) | | error | <code>Error</code> \| <code>null</code> \| <code>undefined</code> | any error (may or may not be an `OError`) |
<a name="OError.getFullStack"></a> <a name="OError.getFullStack"></a>

View file

@ -63,11 +63,11 @@ declare namespace OError {
*/ */
export function tag(error: Error, message?: string, info?: any): Error; export function tag(error: Error, message?: string, info?: any): Error;
/** /**
* The merged info from any `tag`s on the given error. * The merged info from any `tag`s and causes on the given error.
* *
* If an info property is repeated, the last one wins. * If an info property is repeated, the last one wins.
* *
* @param {Error | null | undefined} error any errror (may or may not be an `OError`) * @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @return {Object} * @return {Object}
*/ */
export function getFullInfo(error: Error): any; export function getFullInfo(error: Error): any;

View file

@ -98,11 +98,11 @@ class OError extends Error {
} }
/** /**
* The merged info from any `tag`s on the given error. * The merged info from any `tag`s and causes on the given error.
* *
* If an info property is repeated, the last one wins. * If an info property is repeated, the last one wins.
* *
* @param {Error | null | undefined} error any errror (may or may not be an `OError`) * @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @return {Object} * @return {Object}
*/ */
static getFullInfo(error) { static getFullInfo(error) {
@ -112,6 +112,8 @@ class OError extends Error {
const oError = /** @type{OError} */ (error) const oError = /** @type{OError} */ (error)
if (oError.cause) Object.assign(info, OError.getFullInfo(oError.cause))
if (typeof oError.info === 'object') Object.assign(info, oError.info) if (typeof oError.info === 'object') Object.assign(info, oError.info)
if (oError._oErrorTags) { if (oError._oErrorTags) {

View file

@ -282,12 +282,38 @@ describe('OError.getFullInfo', function () {
}) })
}) })
it('does not merge info from a cause', function () { it('merges info from a cause', function () {
const err1 = new Error('foo') const err1 = new Error('foo')
const err2 = new Error('bar') const err2 = new Error('bar')
err1.cause = err2 err1.cause = err2
err2.info = { userId: 123 } err2.info = { userId: 123 }
expect(OError.getFullInfo(err1)).to.deep.equal({}) expect(OError.getFullInfo(err1)).to.deep.equal({ userId: 123 })
})
it('merges info from a nested cause', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
const err3 = new Error('baz')
err1.cause = err2
err2.info = { userId: 123 }
err2.cause = err3
err3.info = { foo: 42 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 123,
foo: 42,
})
})
it('merges info from cause with duplicate keys', function () {
const err1 = new Error('foo')
const err2 = new Error('bar')
err1.info = { userId: 42, foo: 1337 }
err1.cause = err2
err2.info = { userId: 1 }
expect(OError.getFullInfo(err1)).to.deep.equal({
userId: 42,
foo: 1337,
})
}) })
it('merges info from tags with duplicate keys', function () { it('merges info from tags with duplicate keys', function () {
@ -371,8 +397,8 @@ describe('OError.getFullStack', function () {
' TaggedError: failed to foo', ' TaggedError: failed to foo',
]) ])
// The info from the wrapped cause should not leak out. // The info from the wrapped cause should be picked up for logging.
expect(OError.getFullInfo(error)).to.eql({ bat: 1 }) expect(OError.getFullInfo(error)).to.eql({ bat: 1, foo: 1 })
// But it should still be recorded. // But it should still be recorded.
expect(OError.getFullInfo(error.cause)).to.eql({ foo: 1 }) expect(OError.getFullInfo(error.cause)).to.eql({ foo: 1 })