UNPKG

@vtex/api

Version:
129 lines (128 loc) 5.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.timerForEvents = exports.timer = exports.reduceTimings = exports.parseTimingName = exports.formatTimingName = exports.shrinkTimings = exports.reduceHrToNano = exports.formatNano = exports.hrToNano = exports.nanosecondsToSeconds = exports.hrToMillisFloat = exports.hrToMillis = void 0; const ramda_1 = require("ramda"); const logger_1 = require("../service/logger"); const hrToMillis = ([seconds, nanoseconds]) => Math.round((seconds * 1e3) + (nanoseconds / 1e6)); exports.hrToMillis = hrToMillis; const hrToMillisFloat = ([seconds, nanoseconds]) => { return (seconds * 1e3) + (nanoseconds / 1e6); }; exports.hrToMillisFloat = hrToMillisFloat; const nanosecondsToSeconds = (nanoseconds) => { return nanoseconds / 1e9; }; exports.nanosecondsToSeconds = nanosecondsToSeconds; const hrToNano = ([seconds, nanoseconds]) => seconds * 1e9 + nanoseconds; exports.hrToNano = hrToNano; const formatNano = (nanoseconds) => `${(nanoseconds / 1e9).toFixed(0)}s ${((nanoseconds / 1e6) % 1e3).toFixed(0)}ms`; exports.formatNano = formatNano; exports.reduceHrToNano = (0, ramda_1.reduce)((acc, hr) => acc + (0, exports.hrToNano)(hr), 0); const shrinkTimings = (name) => name.replace(/graphql/g, 'gql').replace(/server/g, 'srv'); exports.shrinkTimings = shrinkTimings; const formatTimingName = ({ hopNumber, target, source }) => `${Number.isNaN(hopNumber) ? '' : hopNumber}.${source || ''}#${target || ''}`; exports.formatTimingName = formatTimingName; const parseTimingName = (timing) => { const [hopNumber, sourceAndTarget] = timing ? timing.split('.') : [null, null]; const [source, target] = sourceAndTarget ? sourceAndTarget.split('#') : [null, null]; return { hopNumber: Number.isNaN(hopNumber) ? null : Number(hopNumber), source, target, }; }; exports.parseTimingName = parseTimingName; const reduceTimings = (timingsObj) => (0, ramda_1.compose)((0, ramda_1.reduce)((acc, [key, dur]) => `${key};dur=${dur}, ${acc}`, ''), ramda_1.toPairs)(timingsObj); exports.reduceTimings = reduceTimings; function recordTimings(start, name, timings, middlewareMetrics, success) { // Capture the total amount of time spent in this middleware, which includes following middlewares const end = process.hrtime(start); // Elapsed for this middleware must disconsider total so far const elapsed = [ end[0] - timings.total[0], end[1] - timings.total[1], ]; // Only record successful executions if (success) { timings[name] = elapsed; } // This middlewares end is now the total timings.total = end; // Batch metric const label = `middleware-${name}`; metrics.batch(label, success ? elapsed : undefined, { success: success ? 1 : 0 }); // This middleware has added it's own metrics // Just add them to `timings` scoped by the middleware's name and batch them const middlewareMetricsKeys = (0, ramda_1.keys)(middlewareMetrics); if (success && middlewareMetricsKeys.length > 0) { (0, ramda_1.forEach)((k) => { const metricEnd = middlewareMetrics[k]; // Delete own metrics so next middleware can have empty state but still accumulate metrics batched after `await` delete middlewareMetrics[k]; const metricName = `${label}-${k}`; timings[metricName] = metricEnd; metrics.batch(metricName, metricEnd); }, middlewareMetricsKeys); } } function timer(middleware) { if (middleware.skipTimer) { return middleware; } if (!middleware.name) { (0, logger_1.logOnceToDevConsole)(`Please use a named function as handler for better metrics. ${middleware.toString()}`, logger_1.LogLevel.Warn); } return async (ctx, next) => { if (!ctx.serverTiming) { ctx.serverTiming = {}; } if (!ctx.timings) { ctx.timings = { total: [0, 0], }; } if (!ctx.metrics) { ctx.metrics = {}; } const start = process.hrtime(); try { await middleware(ctx, next); // At this point, this middleware *and all following ones* have executed recordTimings(start, middleware.name, ctx.timings, ctx.metrics, true); } catch (e) { recordTimings(start, middleware.name, ctx.timings, ctx.metrics, false); throw e; } }; } exports.timer = timer; function timerForEvents(middleware) { if (middleware.skipTimer) { return middleware; } if (!middleware.name) { (0, logger_1.logOnceToDevConsole)(`Please use a named function as handler for better metrics. ${middleware.toString()}`, logger_1.LogLevel.Warn); } return async (ctx, next) => { if (!ctx.timings) { ctx.timings = { total: [0, 0], }; } if (!ctx.metrics) { ctx.metrics = {}; } const start = process.hrtime(); try { await middleware(ctx, next); // At this point, this middleware *and all following ones* have executed recordTimings(start, middleware.name, ctx.timings, ctx.metrics, true); } catch (e) { recordTimings(start, middleware.name, ctx.timings, ctx.metrics, false); throw e; } }; } exports.timerForEvents = timerForEvents;