@vtex/api
Version:
VTEX I/O API client
112 lines (111 loc) • 6.05 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.traceUserLandRemainingPipelineMiddleware = exports.nameSpanOperationMiddleware = exports.addTracingMiddleware = void 0;
const opentracing_1 = require("opentracing");
const stream_1 = require("stream");
const constants_1 = require("../../constants");
const tracing_1 = require("../../tracing");
const Tags_1 = require("../../tracing/Tags");
const utils_1 = require("../../tracing/utils");
const utils_2 = require("../../utils");
const PATHS_BLACKLISTED_FOR_TRACING = ['/_status', '/healthcheck'];
const addTracingMiddleware = (tracer) => {
return async function addTracing(ctx, next) {
var _a;
const rootSpan = tracer.extract(opentracing_1.FORMAT_HTTP_HEADERS, ctx.request.headers);
ctx.tracing = { tracer, currentSpan: undefined };
if (!shouldTrace(ctx, rootSpan)) {
await next();
return;
}
const currentSpan = tracer.startSpan('unknown-operation', {
childOf: rootSpan,
tags: { [Tags_1.OpentracingTags.SPAN_KIND]: Tags_1.OpentracingTags.SPAN_KIND_RPC_SERVER },
});
const initialSamplingDecision = (0, tracing_1.getTraceInfo)(currentSpan).isSampled;
ctx.tracing = { currentSpan, tracer };
let responseClosed = false;
ctx.res.once('close', () => (responseClosed = true));
try {
await next();
}
catch (err) {
tracing_1.ErrorReport.create({ originalError: err }).injectOnSpan(currentSpan, (_a = ctx.vtex) === null || _a === void 0 ? void 0 : _a.logger);
throw err;
}
finally {
const traceInfo = (0, tracing_1.getTraceInfo)(currentSpan);
if (traceInfo === null || traceInfo === void 0 ? void 0 : traceInfo.isSampled) {
if (!initialSamplingDecision) {
currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.setTag(Tags_1.OpentracingTags.SPAN_KIND, Tags_1.OpentracingTags.SPAN_KIND_RPC_SERVER);
}
currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.addTags({
[Tags_1.OpentracingTags.HTTP_URL]: ctx.request.href,
[Tags_1.OpentracingTags.HTTP_METHOD]: ctx.request.method,
[Tags_1.OpentracingTags.HTTP_STATUS_CODE]: ctx.response.status,
["http.path" /* CustomHttpTags.HTTP_PATH */]: ctx.request.path,
["vtex.request_id" /* VTEXIncomingRequestTags.VTEX_REQUEST_ID */]: ctx.get(constants_1.REQUEST_ID_HEADER),
["vtex.incoming.workspace" /* VTEXIncomingRequestTags.VTEX_WORKSPACE */]: ctx.get(constants_1.WORKSPACE_HEADER),
["vtex.incoming.account" /* VTEXIncomingRequestTags.VTEX_ACCOUNT */]: ctx.get(constants_1.ACCOUNT_HEADER),
});
currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.log((0, utils_1.cloneAndSanitizeHeaders)(ctx.request.headers, 'req.headers.'));
currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.log((0, utils_1.cloneAndSanitizeHeaders)(ctx.response.headers, 'res.headers.'));
ctx.set(constants_1.TRACE_ID_HEADER, traceInfo.traceId);
}
const onResFinished = () => {
currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.finish();
};
if (responseClosed) {
onResFinished();
}
else {
(0, stream_1.finished)(ctx.res, onResFinished);
}
}
};
};
exports.addTracingMiddleware = addTracingMiddleware;
const nameSpanOperationMiddleware = (operationType, operationName) => {
return function nameSpanOperation(ctx, next) {
var _a, _b;
ctx.requestHandlerName = `${operationType}:${operationName}`;
(_b = (_a = ctx.tracing) === null || _a === void 0 ? void 0 : _a.currentSpan) === null || _b === void 0 ? void 0 : _b.setOperationName(ctx.requestHandlerName);
return next();
};
};
exports.nameSpanOperationMiddleware = nameSpanOperationMiddleware;
const traceUserLandRemainingPipelineMiddleware = () => {
return async function traceUserLandRemainingPipeline(ctx, next) {
const tracingCtx = ctx.tracing;
ctx.tracing = undefined;
const span = tracingCtx === null || tracingCtx === void 0 ? void 0 : tracingCtx.currentSpan;
const userLandTracer = ctx.vtex.tracer;
userLandTracer.setFallbackSpan(span);
userLandTracer.lockFallbackSpan();
const startTime = process.hrtime();
try {
span === null || span === void 0 ? void 0 : span.log({ event: "user-middlewares-start" /* RuntimeLogEvents.USER_MIDDLEWARES_START */ });
await next();
}
catch (err) {
tracing_1.ErrorReport.create({ originalError: err }).injectOnSpan(span, ctx.vtex.logger);
throw err;
}
finally {
span === null || span === void 0 ? void 0 : span.log({
event: "user-middlewares-finish" /* RuntimeLogEvents.USER_MIDDLEWARES_FINISH */,
["user-middlewares-duration" /* RuntimeLogFields.USER_MIDDLEWARES_DURATION */]: (0, utils_2.hrToMillis)(process.hrtime(startTime)),
});
ctx.tracing = tracingCtx;
}
};
};
exports.traceUserLandRemainingPipelineMiddleware = traceUserLandRemainingPipelineMiddleware;
function shouldTrace(ctx, rootSpan) {
var _a, _b, _c;
/** Should trace if path isnt blacklisted and sampling decision came from the edge
* ((rootSpan as any).isSampled. returns whether or not this span context was sampled
* There is a cast to bypass opentracing typescript
*/
return !PATHS_BLACKLISTED_FOR_TRACING.includes(ctx.request.path) && ((_c = (_b = (_a = rootSpan).isSampled) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : false);
}