hypermark
Version:
performance and tracing
99 lines (86 loc) • 3.02 kB
JavaScript
;
const deepGet = require('deep-value');
const deepSet = require('deep-setter');
const UUID = require('./UUID');
class Tracer {
/**
* configuration - Each key in configuration is the key which will be put in request/response
* {
* 'x-request-id' : {
* in : [], //will try by order of precedence
* request : [''],
* response : [''],
* generateOnAbsence : 'uuid' || function || false || undefined
* }
* }
* @param configuration
*/
constructor (configuration) {
if(!configuration || typeof configuration !== 'object') {
configuration = {};
}
this.__traces = Object.keys(configuration);//kind of expensive so 'cache' it?
if(this.__traces.length === 0){
throw new Error('no traces');
}
const badTrace = this.__traces.find(e => !configuration[e].in);
if(badTrace) {
throw new Error(`Missing "in" value on a trace ${badTrace}`);
}
this.__config = configuration;
}
/**
*
* @param context - In aws lambda terms this might be the event, in a express app this might be req
* @returns {Trace}
*/
startTrace (context) {
return new Trace(this.__traces.reduce((acc, trace) => {
let value = null;
const cTrace = this.__config[trace];
cTrace.in.some(e => {
return value = deepGet(context, e);
});
if(typeof value === 'undefined' && cTrace.generateOnAbsence) {
if(typeof cTrace.generateOnAbsence === 'function') {
value = cTrace.generateOnAbsence(context);
}
else if(cTrace.generateOnAbsence === 'uuid') {
value = UUID();
}
}
acc.push({
value : value,
request : Array.isArray(cTrace.request)?cTrace.request:typeof cTrace.request === 'string'?[cTrace.request]:[],
response : Array.isArray(cTrace.response)?cTrace.response:typeof cTrace.response === 'string'?[cTrace.response]:[],
log : Array.isArray(cTrace.log)?cTrace.log:typeof cTrace.log === 'string'?[cTrace.log]:[]
});
return acc;
}, []));
}
}
class Trace {
constructor (traces) {
this.__traces = traces;
}
extendRequest (request) {
return this.__extend(request, 'request');
}
extendResponse (response) {
return this.__extend(response, 'response');
}
extendLogs (log) {
return this.__extend(log, 'log');
}
__extend(thing, prop) {
this.__traces.forEach(trace => {
if(Array.isArray(trace[prop])) {
trace[prop].forEach(locator => {
deepSet(thing, locator, trace.value);
});
}
});
return thing;
}
}
module.exports = Tracer;