UNPKG

@instana/core

Version:
87 lines (70 loc) 2.67 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 cls = require('../../cls'); let isActive = false; const CLS_CONTEXT_SYMBOL = Symbol('_instana_cls_context'); exports.init = () => { hook.onModuleLoad('graphql-subscriptions', instrumentModule); // In v3, pubsub-async-iterator is replaced with pubsub-async-iterable-iterator hook.onFileLoad(/\/graphql-subscriptions\/dist\/pubsub-async-iterable-iterator\.js/, instrumentAsyncIterableIterator); // In v2, pubsub-async-iterator is available hook.onFileLoad(/\/graphql-subscriptions\/dist\/pubsub-async-iterator\.js/, instrumentAsyncIterator); }; function instrumentModule(graphQlSubscriptions) { shimmer.wrap(graphQlSubscriptions.PubSub.prototype, 'publish', shimPublish); } function shimPublish(originalPublish) { return function () { if (isActive && cls.isTracing()) { // Keep cls context in GraphQL subscriptions by binding the associated event emitters. if (this.ee && this.ee.on && this.ee.addListener && this.ee.emit) { cls.ns.bindEmitter(this.ee); } } return originalPublish.apply(this, arguments); }; } function instrumentAsyncIterator(pubSubAsyncIterator) { shimmer.wrap(pubSubAsyncIterator.PubSubAsyncIterator.prototype, 'pushValue', shimPushValue); shimmer.wrap(pubSubAsyncIterator.PubSubAsyncIterator.prototype, 'pullValue', shimPullValue); } function instrumentAsyncIterableIterator(pubSubAsyncIterator) { shimmer.wrap(pubSubAsyncIterator.PubSubAsyncIterableIterator.prototype, 'pushValue', shimPushValue); shimmer.wrap(pubSubAsyncIterator.PubSubAsyncIterableIterator.prototype, 'pullValue', shimPullValue); } function shimPushValue(originalFunction) { return function (event) { if (isActive && event && typeof event === 'object' && cls.ns.active) { event[CLS_CONTEXT_SYMBOL] = cls.ns.active; } return originalFunction.apply(this, arguments); }; } function shimPullValue(originalFunction) { return function () { const pullPromise = originalFunction.apply(this, arguments); return pullPromise.then(result => { if (result && result.value && result.value[CLS_CONTEXT_SYMBOL]) { const clsContext = result.value[CLS_CONTEXT_SYMBOL]; if (isActive && clsContext) { cls.ns.enter(clsContext); setImmediate(() => { cls.ns.exit(clsContext); }); } } return result; }); }; } exports.activate = () => { isActive = true; }; exports.deactivate = () => { isActive = false; };