UNPKG

@vtex/api

Version:
113 lines (112 loc) 5.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.metricsMiddleware = void 0; const RequestCancelledError_1 = require("../../errors/RequestCancelledError"); const requestStats_1 = require("../../service/worker/runtime/http/middlewares/requestStats"); const utils_1 = require("../../utils"); const retry_1 = require("../../utils/retry"); const status_1 = require("../../utils/status"); const metricsMiddleware = ({ metrics, serverTiming, name }) => { const serverTimingStart = process.hrtime(); const serverTimingLabel = (0, utils_1.shrinkTimings)((0, utils_1.formatTimingName)({ hopNumber: 0, source: process.env.VTEX_APP_NAME, target: name || 'unknown', })); return async (ctx, next) => { const start = process.hrtime(); let status = 'unknown'; let errorCode; let errorStatus; try { if (ctx.config.verbose && ctx.config.label) { console.log(`VERBOSE: ${name}.${ctx.config.label}`, `start`); } await next(); if (ctx.config.metric && ctx.response && ctx.response.status) { status = (0, status_1.statusLabel)(ctx.response.status); } } catch (err) { const isCancelled = (err.message === requestStats_1.cancelMessage); if (ctx.config.metric) { errorCode = err.code; errorStatus = err.response && err.response.status; if (err.code === 'ECONNABORTED') { status = 'aborted'; } else if (err.response && err.response.data && err.response.data.code === retry_1.TIMEOUT_CODE) { status = 'timeout'; } else if (err.response && err.response.status) { status = (0, status_1.statusLabel)(err.response.status); } else if (isCancelled) { status = 'cancelled'; } else { status = 'error'; } } throw isCancelled ? new RequestCancelledError_1.RequestCancelledError(err.message) : err; } finally { if (ctx.config.metric && metrics) { const label = `http-client-${ctx.config.metric}`; const extensions = {}; Object.assign(extensions, { [status]: 1 }); if (ctx.cacheHit) { Object.assign(extensions, ctx.cacheHit, { [`${status}-hit`]: 1 }); } else if (!ctx.inflightHit && !ctx.memoizedHit) { // Lets us know how many calls passed through to origin Object.assign(extensions, { [`${status}-miss`]: 1 }); } if (ctx.inflightHit) { Object.assign(extensions, { [`${status}-inflight`]: 1 }); } if (ctx.memoizedHit) { Object.assign(extensions, { [`${status}-memoized`]: 1 }); } if (ctx.config.retryCount) { const retryCount = ctx.config.retryCount; if (retryCount > 0) { extensions[`retry-${status}-${retryCount}`] = 1; } } const end = status === 'success' && !ctx.cacheHit && !ctx.inflightHit && !ctx.memoizedHit ? process.hrtime(start) : undefined; metrics.batch(label, end, extensions); if (ctx.config.verbose) { console.log(`VERBOSE: ${name}.${ctx.config.label}`, { ...extensions, ...errorCode || errorStatus ? { errorCode, errorStatus } : null, millis: end ? (0, utils_1.hrToMillis)(end) : extensions.revalidated || extensions.router || status !== 'success' ? (0, utils_1.hrToMillis)(process.hrtime(start)) : '(from cache)', status: ctx.response && ctx.response.status, headers: ctx.response && ctx.response.headers, }); } } else { if (ctx.config.verbose) { console.warn(`PROTIP: Please add a metric property to ${name} client request to get metrics in Splunk`, { baseURL: ctx.config.baseURL, url: ctx.config.url }); } } if (serverTiming) { // Timings in the client's perspective const dur = (0, utils_1.hrToMillis)(process.hrtime(serverTimingStart)); if (!serverTiming[serverTimingLabel] || Number(serverTiming[serverTimingLabel]) < dur) { serverTiming[serverTimingLabel] = `${dur}`; } } } }; }; exports.metricsMiddleware = metricsMiddleware;