@kasa/koa-logging
Version:
A middleware that logs request and response in Koa
96 lines (79 loc) • 2.9 kB
JavaScript
;
const debug = require('debug')('koa:logging');
const defaultSerializers = require('./serializers');
const utils = require('./utils');
/**
* Return middleware that attachs logger to context and
* logs HTTP request/response and error.
*
* @param {Object} options={} - Optional configuration.
* @param {Object} options.logger - Logger instance of pino.
* @param {Object} [options.serializers] - Serializers to override defaults provided.
* @param {boolean} [options.overrideSerializers=true] - Override serializers if true.
* @param {function} [options.getReqId] - Function to get the request id from `ctx`.
* @param {function} [options.getRequestLogLevel] - Function to decide log level of the request from `ctx`.
* @param {function} [options.getResponseLogLevel] - Function to decide log level of the response from `ctx`.
* @param {function} [options.getErrorLogLevel] - Function to decide log level of the error from `error`.
* @return {function} Koa middleware.
*/
module.exports = (options = {}) => {
const {
logger = null,
overrideSerializers = true,
getReqId = () => null,
getRequestLogLevel = utils.getRequestLogLevel,
getResponseLogLevel = utils.getResponseLogLevel,
getErrorLogLevel = utils.getErrorLogLevel
} = options;
const serializers = {
...defaultSerializers,
...options.serializers
};
if (typeof logger !== 'object' || logger === null) {
throw new TypeError('Logger required');
}
debug('Create a middleware');
return async function logging(ctx, next) {
// Try to get the request id
const reqId = getReqId(ctx)
|| ctx.state.reqId
|| ctx.reqId
|| ctx.req.id
|| ctx.get('X-Request-Id');
const startTime = new Date();
ctx.log = logger.child({
reqId,
serializers: (overrideSerializers ? serializers : {})
});
debug(`Created a child logger from parent logger (reqId=${reqId})`);
const reqLogLevel = getRequestLogLevel(ctx);
ctx.log[reqLogLevel](
{ req: ctx, event: 'request' },
`${ctx.method} ${ctx.path} (${reqId})`
);
debug('Logged a request event');
// Handle response logging when response is sent
ctx.res.on('finish', () => {
ctx.duration = new Date() - startTime;
const resLogLevel = getResponseLogLevel(ctx);
ctx.log[resLogLevel](
{ req: ctx, res: ctx, event: 'response' },
`${ctx.status} ${ctx.message} - ${ctx.duration}ms (${reqId})`
);
debug('Logged a response event');
// Remove log object to mitigate accidental leaks
delete ctx.log;
});
try {
await next();
} catch (err) {
const errLogLevel = getErrorLogLevel(ctx);
ctx.log[errLogLevel](
{ err, event: 'error' },
`Unhandled exception occured (${reqId})`
);
debug('Logged an error event');
throw err;
}
};
};