UNPKG

@instana/core

Version:
78 lines (64 loc) 2.66 kB
/* * (c) Copyright IBM Corp. 2021 * (c) Copyright Instana Inc. and contributors 2020 */ 'use strict'; const shimmer = require('../../shimmer'); const hook = require('../../../util/hook'); const cls = require('../../cls'); let logger; exports.init = function (config) { logger = config.logger; hook.onModuleLoad('mongoose', exports.instrument); }; // This instruments the Aggregate object exported by Mongoose. The Mongoose library uses the standard MongoDB driver // under the hood and thus would not need custom instrumentation to capture MongoDB exit spans. But: Its Aggregate // object is a custom thenable, and async_hooks currently does not propagate the async context for those (only for // actual promise instances). // // Thus, we loose async context in Mongoose.Model.aggregate(...).then. // // To work around that issue, we attach the async context that is active when _creating_ the Aggregate object and // restore it in Aggregate#then. exports.instrument = function instrument(Mongoose) { if (!Mongoose.Model || !Mongoose.Model.aggregate) { logger.debug('Failed to instrument Mongoose, no Model or Model.aggregate property.'); return; } const originalAggregate = Mongoose.Model.aggregate; // Instrument Mongoose.Model#aggregate to attach the async context. Mongoose.Model.aggregate = function instanaAggregate() { const aggr = originalAggregate.apply(this, arguments); if (!aggr) { return aggr; } if (typeof aggr.then === 'function' && typeof aggr.catch === 'function') { aggr.__inctx = cls.getAsyncContext(); shimmer.wrap(aggr, 'then', instrumentThenOrCatch); shimmer.wrap(aggr, 'catch', instrumentThenOrCatch); } return aggr; }; }; function instrumentThenOrCatch(original) { return function instrumentedThenOrCatch() { if (!this.__inctx) { return original.apply(this, arguments); } else { const originalThis = this; const originalArgs = new Array(arguments.length); for (let i = 0; i < arguments.length; i++) { originalArgs[i] = arguments[i]; } return cls.runInAsyncContext(this.__inctx, () => original.apply(originalThis, originalArgs)); } }; } exports.activate = function () { // This instrumentation does not record spans on its own, it just helps propagating the async context. Thus the // instrumentation is always on and cannot be activted or deactivated. }; exports.deactivate = function () { // This instrumentation does not record spans on its own, it just helps propagating the async context. Thus the // instrumentation is always on and cannot be activted or deactivated. };