From f8369047bf9646e43ef2e5efce3007300611a8c7 Mon Sep 17 00:00:00 2001 From: Ryan Ling Date: Sun, 13 Dec 2020 21:08:30 +1100 Subject: [PATCH] feat(RequestLogging): Include `err` field (#56) Consuming applications tend towards the following `logFn` boilerplate: ```typescript const data = { ...fields, err: err ?? ErrorMiddleware.thrown(ctx), }; ``` While Koala provides a simplified `internalErrorString`, rich error details are often handy for troubleshooting, and the `err` property name is blessed by common logging frameworks like Bunyan and Pino. This preserves `internalErrorString` for backward compatibility. --- src/requestLogging/README.md | 5 +++++ src/requestLogging/requestLogging.test.ts | 1 + src/requestLogging/requestLogging.ts | 14 ++++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/requestLogging/README.md b/src/requestLogging/README.md index aa11b2e..5f4aa49 100644 --- a/src/requestLogging/README.md +++ b/src/requestLogging/README.md @@ -153,6 +153,11 @@ const healthCheckHandler = async (ctx: Koa.Context) => { }, "status": 500, "internalErrorString": "ExpiredTokenException: The security token included in the request is expired", + "err": { + "message": "The security token included in the request is expired", + "name": "ExpiredTokenException", + "stack": "..." + }, "msg": "request log", "time": "2018-10-16T00:44:41.055Z", "v": 0 diff --git a/src/requestLogging/requestLogging.test.ts b/src/requestLogging/requestLogging.test.ts index 63723ec..9d6a045 100644 --- a/src/requestLogging/requestLogging.test.ts +++ b/src/requestLogging/requestLogging.test.ts @@ -197,6 +197,7 @@ describe('RequestLogging', () => { }, ` Object { + "err": [Error: Something tragic happened], "headers": Object { "accept": undefined, "accept-encoding": "gzip, deflate", diff --git a/src/requestLogging/requestLogging.ts b/src/requestLogging/requestLogging.ts index c083b60..df6151e 100644 --- a/src/requestLogging/requestLogging.ts +++ b/src/requestLogging/requestLogging.ts @@ -1,5 +1,6 @@ import Koa from 'koa'; +import { thrown } from '../errorMiddleware/errorMiddleware'; import { tracingFromContext } from '../tracingHeaders/tracingHeaders'; /** @@ -126,7 +127,7 @@ export const createMiddleware = ( const requestFinished = ( resultFields: Record, - error?: unknown, + err?: unknown, ) => { if (ctx.state.skipRequestLogging) { return; @@ -136,20 +137,25 @@ export const createMiddleware = ( logFn( ctx, { + ...(typeof err !== 'undefined' && { + err, + internalErrorString: String(err), + }), latency, headers: replaceHeaders(ctx.request.header, headerReplacements), ...contextFields(ctx), ...resultFields, }, - error, + err, ); }; try { await next(); - requestFinished({ status: ctx.response.status }); + + requestFinished({ status: ctx.response.status }, thrown(ctx)); } catch (err: unknown) { - requestFinished({ status: 500, internalErrorString: String(err) }, err); + requestFinished({ status: 500 }, err); throw err; }