Skip to content

Commit b47175c

Browse files
committed
fix(logging): report the cause of the error the line reports
1 parent 0b193db commit b47175c

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

‎packages/logger/src/index.test.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,21 @@ describe('Logger', () => {
224224
expect(parsed.errorCode).toBe('57014')
225225
})
226226

227+
test('reports the cause of the same error the line reports when given two', () => {
228+
const conflict = Object.assign(new Error('duplicate key value'), {
229+
name: 'PostgresError',
230+
code: '23505',
231+
})
232+
const second = new Error('Failed query: insert into "t" values ($1)', { cause: conflict })
233+
234+
createEnabledLogger().error('Retry failed', queryError('tbl_1'), second)
235+
236+
const parsed = JSON.parse(consoleErrorSpy.mock.calls[0][0] as string)
237+
expect(parsed.error).toBe(second.message)
238+
expect(parsed.errorCause).toBe('PostgresError: duplicate key value')
239+
expect(parsed.errorCode).toBe('23505')
240+
})
241+
227242
test.each([
228243
['an object field', (error: Error) => [{ error }]],
229244
['a bare argument', (error: Error) => [error]],

‎packages/logger/src/index.ts‎

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,15 @@ const formatObject = (obj: unknown, isDev: boolean): string => {
210210
}
211211
}
212212

213-
/** The error a line is about: the first bare `Error` argument, else the first `{ error }` field. */
213+
/**
214+
* The error a line is about, chosen as `mergeArgs` chooses it: the last bare
215+
* `Error` argument, else the first `{ error }` field.
216+
*/
214217
const primaryError = (args: unknown[]): Error | undefined => {
215-
const bare = args.find((arg) => arg instanceof Error)
216-
if (bare) return bare as Error
218+
for (let i = args.length - 1; i >= 0; i--) {
219+
const arg = args[i]
220+
if (arg instanceof Error) return arg
221+
}
217222
for (const arg of args) {
218223
if (isRecordLike(arg) && arg.error instanceof Error) return arg.error
219224
}
@@ -238,13 +243,14 @@ const assignErrorCause = (entry: Record<string, unknown>, logged: LoggedError) =
238243
* cause and its code go in `errorCause` and `errorCode`.
239244
*/
240245
const mergeArgs = (entry: Record<string, unknown>, args: unknown[]): Record<string, unknown> => {
246+
/** The error whose stack the line carries; its cause is assigned last so a later error cannot inherit an earlier one's. */
247+
let reported: LoggedError | undefined
241248
for (const arg of args) {
242249
if (arg === null || arg === undefined) continue
243250
if (arg instanceof Error) {
244-
const logged = toLoggedError(arg)
245-
entry.error = logged.message
246-
entry.stack = logged.stack
247-
assignErrorCause(entry, logged)
251+
reported = toLoggedError(arg)
252+
entry.error = reported.message
253+
entry.stack = reported.stack
248254
} else if (typeof arg === 'object') {
249255
const source = arg as Record<string, unknown>
250256
for (const key of Object.keys(source)) {
@@ -254,7 +260,7 @@ const mergeArgs = (entry: Record<string, unknown>, args: unknown[]): Record<stri
254260
entry[key] = logged.message
255261
if (key === 'error' && entry.stack === undefined) {
256262
entry.stack = logged.stack
257-
assignErrorCause(entry, logged)
263+
reported = logged
258264
}
259265
} else {
260266
entry[key] = value
@@ -264,6 +270,7 @@ const mergeArgs = (entry: Record<string, unknown>, args: unknown[]): Record<stri
264270
entry.extra = arg
265271
}
266272
}
273+
if (reported) assignErrorCause(entry, reported)
267274
return entry
268275
}
269276

0 commit comments

Comments
 (0)