microservice-utilities
Version:
Utilities supporting authorization, request logging and other often reused parts of microservices.
78 lines (68 loc) • 2.95 kB
JavaScript
const stringify = require('json-stringify-safe');
const uuid = require('uuid');
class RequestLogger {
/**
* Constructor
* @param {Object} configuration configuration object
* @param {Function} configuration.logFunction optional log function, by default RequestLogger uses console.log
* @param {Boolean} configuration.extendErrorObjects extends Error object globally in order to provide proper JSON
* representation of Error objects.
* @param {Number} configuration.jsonSpace the number of spaces that are used then stringifying the message.
*/
constructor(configuration = { logFunction: console.log, extendErrorObjects: true, jsonSpace: 2 }) {
this.logFunction = configuration.logFunction;
this.jsonSpace = configuration.jsonSpace === null || configuration.jsonSpace === undefined ? 2 : configuration.jsonSpace;
if (configuration.extendErrorObjects) {
require('error-object-polyfill');
}
this.invocationId = null;
}
/**
* Create a new invocation which will end up setting the additional invocation metadata for the request, which will be used when logging.
* @param {Object} staticData Any static data that are assigned to every log message. Typical might be an environment parameter or version number.
*/
startInvocation(staticData) {
this.staticData = staticData;
this.invocationId = uuid.v4();
}
log(message) {
let type = typeof message;
let messageAsObject = message;
if (type === 'undefined' || (type === 'string' && message === '')) {
console.error('Empty message string.');
return;
} else if (type === 'string') {
messageAsObject = {
title: message
};
} else if (type === 'object' && Object.keys(message).length === 0) {
console.error('Empty message object.');
return;
}
if (this.staticData && typeof this.staticData === 'object') {
messageAsObject = Object.assign({}, this.staticData, messageAsObject);
}
let payload = {
invocationId: this.invocationId,
message: messageAsObject
};
let truncateToken = innerPayload => {
return innerPayload.replace(/(eyJ[a-zA-Z0-9_-]{5,}\.eyJ[a-zA-Z0-9_-]{5,})\.[a-zA-Z0-9_-]*/gi, (m, p1) => `${p1}.<sig>`);
};
let stringifiedPayload = truncateToken(stringify(payload, null, this.jsonSpace));
// https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html 256KB => 32768 characters
if (stringifiedPayload.length >= 32768) {
let replacementPayload = {
invocationId: this.invocationId,
message: {
title: 'Payload too large',
fields: Object.keys(payload),
truncatedPayload: stringifiedPayload.substring(0, 10000)
}
};
stringifiedPayload = stringify(replacementPayload, null, this.jsonSpace);
}
this.logFunction(stringifiedPayload);
}
}
module.exports = RequestLogger;