UNPKG

@instana/core

Version:
144 lines (124 loc) 4.59 kB
/* * (c) Copyright IBM Corp. 2021 * (c) Copyright Instana Inc. and contributors 2019 */ 'use strict'; const shimmer = require('../../shimmer'); const hook = require('../../../util/hook'); const httpServer = require('../protocols/httpServer'); const cls = require('../../cls'); let logger; let active = false; exports.activate = function activate() { active = true; }; exports.deactivate = function deactivate() { active = false; }; exports.init = function init(config) { logger = config.logger; // Note: koa-router is deprecated from v9 with @koa/router being the recommended replacement // We maintain instrumentation for both packages since customers may be using it hook.onModuleLoad('koa-router', module => { logDeprecatedWarning(); instrumentRouter(module); }); hook.onModuleLoad('@koa/router', instrumentRouter, { nativeEsm: true }); }; function instrumentRouter(Router) { shimmer.wrap(Router.prototype, 'routes', shimRoutes); // Return Router for ESM compatibility: iitmHook reassigns the return value to exports.default return Router; } function shimRoutes(originalFunction) { return function () { return instrumentedRoutes(this, originalFunction, arguments); }; } function instrumentedRoutes(thisContext, originalRoutes, originalArgs) { // We need to hook into the dispatch function, which does not exist on Router.prototype but is created on the fly in // Router.routes, so we need to hook into Router.routes to get access to the dispatch function. const dispatch = originalRoutes.apply(thisContext, originalArgs); // Actually, we could just use ctx._matchedRoute, which would be the path template we are looking for and which gets // set by koa-router. Unfortunately, this is broken, see // https://github.com/ZijianHe/koa-router/issues/478 and // https://github.com/ZijianHe/koa-router/issues/444. // eslint-disable-next-line no-unused-vars const instrumentedDispatch = function (ctx, next) { if (active && cls.isTracing()) { const dispatchResult = dispatch.apply(this, arguments); return dispatchResult.then(resolvedValue => { if (ctx.matched && ctx.matched.length && ctx.matched.length > 0) { const matchedRouteLayers = ctx.matched.slice(); matchedRouteLayers.sort(byLeastSpecificLayer); const mostSpecificPath = normalizeLayerPath(matchedRouteLayers[matchedRouteLayers.length - 1].path); annotateHttpEntrySpanWithPathTemplate(mostSpecificPath); } return resolvedValue; }); } else { return dispatch.apply(this, arguments); } }; // The router attaches itself as a property to the dispatch function and other methods in koa-router rely on this, so // we need to attach this property to our dispatch function, too. instrumentedDispatch.router = dispatch.router; return instrumentedDispatch; } /** * Copied from * https://github.com/ZijianHe/koa-router/pull/475, which would fix the mentioned issues with ctx._matchedRoute (if * it got merged). * * Sort function for array of Layers. Will sort the layers with least specific first * and most specific last. * * @param {Layer} a * @param {Layer} b */ function byLeastSpecificLayer(a, b) { const regexpA = a.path && typeof a.path === 'object'; const regexpB = b.path && typeof b.path === 'object'; let pathA = normalizeLayerPath(a.path); let pathB = normalizeLayerPath(b.path); const wildA = pathA.endsWith('(.*)'); const wildB = pathB.endsWith('(.*)'); if (wildA && wildB) return pathA.length - pathB.length; pathA = wildA ? pathA.slice(0, -4) : pathA; pathB = wildB ? pathB.slice(0, -4) : pathB; if (pathA !== pathB) { if (pathA.startsWith(pathB)) return 1; if (pathB.startsWith(pathA)) return -1; } if (wildA) return -1; if (wildB) return 1; if (regexpA && !regexpB) { return -1; } if (!regexpA && regexpB) { return 1; } return 0; } function normalizeLayerPath(p) { if (p == null) { return ''; } if (typeof p === 'object') { return p.toString(); } return p; } function annotateHttpEntrySpanWithPathTemplate(pathTemplate) { const span = cls.getCurrentEntrySpan(); if (!span || span.n !== httpServer.spanName || span.pathTplFrozen) { return; } span.data.http.path_tpl = pathTemplate; } function logDeprecatedWarning() { logger.warn( // eslint-disable-next-line max-len '[Deprecation Warning] The support for koa-router library is deprecated and will be removed in the next major release. Please consider using @koa/router instead.' ); }