From 5245950aa9ade311020572effe939153bae03142 Mon Sep 17 00:00:00 2001 From: vmarchaud Date: Wed, 24 Jul 2019 18:17:53 +0200 Subject: [PATCH] chore(ah-scope): remove support for event emitter and promises for now --- .../src/AsyncHooksScopeManager.ts | 148 +--------------- .../asynchooks/AsyncHooksScopeManager.test.ts | 158 ------------------ 2 files changed, 1 insertion(+), 305 deletions(-) diff --git a/packages/opentelemetry-scope-async-hooks/src/AsyncHooksScopeManager.ts b/packages/opentelemetry-scope-async-hooks/src/AsyncHooksScopeManager.ts index dc3ed0335e2..4dec239aab5 100644 --- a/packages/opentelemetry-scope-async-hooks/src/AsyncHooksScopeManager.ts +++ b/packages/opentelemetry-scope-async-hooks/src/AsyncHooksScopeManager.ts @@ -16,26 +16,6 @@ import { ScopeManager } from '@opentelemetry/scope-base'; import * as asyncHooks from 'async_hooks'; -import { EventEmitter } from 'events'; - -type Func = (...args: unknown[]) => T; - -type PatchedEventEmitter = { - /** - * Store a map for each event of all original listener and their "patched" - * version so when the listener is removed by the user, we remove the - * correspoding "patched" function. - */ - __ot_listeners?: { [name: string]: WeakMap, Func> }; -} & EventEmitter; - -const ADD_LISTENER_METHODS = [ - 'addListener' as 'addListener', - 'on' as 'on', - 'once' as 'once', - 'prependListener' as 'prependListener', - 'prependOnceListener' as 'prependOnceListener', -]; export class AsyncHooksScopeManager implements ScopeManager { private asyncHook: asyncHooks.AsyncHook; @@ -76,12 +56,8 @@ export class AsyncHooksScopeManager implements ScopeManager { if (!scope) { scope = this.active(); } - if (target instanceof EventEmitter) { - return this._bindEventEmitter(target, scope); - } else if (typeof target === 'function') { + if (typeof target === 'function') { return this._bindFunction(target, scope); - } else if (target instanceof Promise) { - return this._bindPromise(target, scope); } return target; } @@ -116,128 +92,6 @@ export class AsyncHooksScopeManager implements ScopeManager { return contextWrapper as any; } - /** - * By default, EventEmitter call their callback with their scope, which we do - * not want, instead we will bind a specific scope to all callbacks that - * go through it. - * @param target EventEmitter a instance of EventEmitter to patch - * @param scope the scope we want to bind - */ - private _bindEventEmitter( - target: T, - scope?: unknown - ): T { - const ee = (target as unknown) as PatchedEventEmitter; - if (ee.__ot_listeners !== undefined) return target; - ee.__ot_listeners = {}; - - // patch methods that add a listener to propagate scope - ADD_LISTENER_METHODS.forEach(methodName => { - ee[methodName] = this._patchEEAddListener(ee, ee[methodName], scope); - }); - // patch methods that remove a listener - ee.removeListener = this._patchEERemoveListener(ee, ee.removeListener); - ee.off = this._patchEERemoveListener(ee, ee.off); - // patch method that remove all listeners - ee.removeAllListeners = this._patchEERemoteAllListeners( - ee, - ee.removeAllListeners - ); - - return target; - } - - private _bindPromise>( - target: T, - scope?: unknown - ): T { - const scopeManager = this; - const then = target.then; - target.then = function(this: {}) { - const args = new Array(arguments.length); - for (let i = 0; i < args.length; i++) { - args[i] = scopeManager.bind(arguments[i], scope); - } - /** - * Forced to remove compilation error here, the type of Promise - * is impossible(?) to reproduce when modifying it. - */ - // tslint:disable-next-line:ban-ts-ignore - // @ts-ignore - return then.apply(this, args); - }; - return target; - } - - /** - * Patch methods that remove a given listener so that we match the "patched" - * version of that listener (the one that propagate context). - * @param ee EventEmitter instance - * @param original reference to the patched method - */ - private _patchEERemoveListener(ee: PatchedEventEmitter, original: Function) { - return function(this: {}, event: string, listener: Func) { - if ( - ee.__ot_listeners === undefined || - ee.__ot_listeners[event] === undefined - ) { - return original.call(this, event, listener); - } - const events = ee.__ot_listeners[event]; - const patchedListener = events.get(listener); - return original.call(this, event, patchedListener || listener); - }; - } - - /** - * Patch methods that remove all listeners so we remove our - * internal references for a given event. - * @param ee EventEmitter instance - * @param original reference to the patched method - */ - private _patchEERemoteAllListeners( - ee: PatchedEventEmitter, - original: Function - ) { - return function(this: {}, event: string) { - if ( - ee.__ot_listeners === undefined || - ee.__ot_listeners[event] === undefined - ) { - return original.call(this, event); - } - delete ee.__ot_listeners[event]; - return original.call(this, event); - }; - } - - /** - * Patch methods on an event emitter instance that can add listeners so we - * can force them to propagate a given context. - * @param ee EventEmitter instance - * @param original reference to the patched method - * @param [scope] scope to propagate when calling listeners - */ - private _patchEEAddListener( - ee: PatchedEventEmitter, - original: Function, - scope?: unknown - ) { - const scopeManager = this; - return function(this: {}, event: string, listener: Func) { - if (ee.__ot_listeners === undefined) ee.__ot_listeners = {}; - let listeners = ee.__ot_listeners[event]; - if (listeners === undefined) { - listeners = new WeakMap(); - ee.__ot_listeners[event] = listeners; - } - const patchedListener = scopeManager.bind(listener, scope); - // store a weak reference of the user listener to ours - listeners.set(listener, patchedListener); - return original.call(this, event, patchedListener); - }; - } - /** * Init hook will be called when userland create a async scope, setting the * scope as the current one if it exist. diff --git a/packages/opentelemetry-scope-async-hooks/test/asynchooks/AsyncHooksScopeManager.test.ts b/packages/opentelemetry-scope-async-hooks/test/asynchooks/AsyncHooksScopeManager.test.ts index e3fdac8c72a..c29f6aa33f4 100644 --- a/packages/opentelemetry-scope-async-hooks/test/asynchooks/AsyncHooksScopeManager.test.ts +++ b/packages/opentelemetry-scope-async-hooks/test/asynchooks/AsyncHooksScopeManager.test.ts @@ -16,7 +16,6 @@ import * as assert from 'assert'; import { AsyncHooksScopeManager } from '../../src'; -import { EventEmitter } from 'events'; describe('AsyncHooksScopeManager', () => { let scopeManager: AsyncHooksScopeManager; @@ -130,161 +129,4 @@ describe('AsyncHooksScopeManager', () => { fn(); }); }); - - describe('.bind(event-emitter)', () => { - it('should return the same target (when enabled)', () => { - const ee = new EventEmitter(); - assert.deepStrictEqual(scopeManager.bind(ee), ee); - }); - - it('should return the same target (when disabled)', () => { - const ee = new EventEmitter(); - scopeManager.disable(); - assert.deepStrictEqual(scopeManager.bind(ee), ee); - scopeManager.enable(); - }); - - it('should return current scope and removeListener (when enabled)', done => { - const ee = new EventEmitter(); - const scope = { a: 2 }; - const patchedEe = scopeManager.bind(ee, scope); - const handler = () => { - assert.deepStrictEqual(scopeManager.active(), scope); - patchedEe.off('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 0); - return done(); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - - it('should return current scope and removeAllListener (when enabled)', done => { - const ee = new EventEmitter(); - const scope = { a: 2 }; - const patchedEe = scopeManager.bind(ee, scope); - const handler = () => { - assert.deepStrictEqual(scopeManager.active(), scope); - patchedEe.removeAllListeners('test'); - assert.strictEqual(patchedEe.listeners('test').length, 0); - return done(); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - - /** - * Even if asynchooks is disabled, the scope propagation will - * still works but it might be lost after any async op. - */ - it('should return scope (when disabled)', done => { - scopeManager.disable(); - const ee = new EventEmitter(); - const scope = { a: 2 }; - const patchedEe = scopeManager.bind(ee, scope); - const handler = () => { - assert.deepStrictEqual(scopeManager.active(), scope); - patchedEe.off('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 0); - scopeManager.enable(); - return done(); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - - it('should not return current scope (when disabled + async op)', done => { - scopeManager.disable(); - const ee = new EventEmitter(); - const scope = { a: 3 }; - const patchedEe = scopeManager.bind(ee, scope); - const handler = () => { - setImmediate(() => { - assert.deepStrictEqual(scopeManager.active(), null); - patchedEe.removeAllListeners('test'); - assert.strictEqual(patchedEe.listeners('test').length, 0); - return done(); - }); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - - it('should return current scope (when enabled + async op)', done => { - scopeManager.enable(); - const ee = new EventEmitter(); - const scope = { a: 3 }; - const patchedEe = scopeManager.bind(ee, scope); - const handler = () => { - setImmediate(() => { - assert.deepStrictEqual(scopeManager.active(), scope); - patchedEe.removeAllListeners('test'); - assert.strictEqual(patchedEe.listeners('test').length, 0); - return done(); - }); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - }); - - describe('.bind(promise)', () => { - it('should return the same target (when enabled)', () => { - const promise = Promise.resolve(); - assert.deepStrictEqual(scopeManager.bind(promise), promise); - }); - - it('should return the scope (when enabled)', done => { - const scope = { a: 3 }; - const promise = Promise.resolve(); - scopeManager.bind(promise, scope); - promise.then(() => { - assert.deepStrictEqual(scopeManager.active(), scope); - return done(); - }); - }); - - it('should return the scope (when disabled)', done => { - scopeManager.disable(); - const scope = { a: 3 }; - const promise = Promise.resolve(); - scopeManager.bind(promise, scope); - promise.then(() => { - assert.deepStrictEqual(scopeManager.active(), scope); - scopeManager.enable(); - return done(); - }); - }); - - it('should not return the scope (when disabled + async op)', done => { - scopeManager.disable(); - const scope = { a: 3 }; - const promise = Promise.resolve(); - scopeManager.bind(promise, scope); - promise.then(() => { - setImmediate(() => { - assert.deepStrictEqual(scopeManager.active(), null); - scopeManager.enable(); - return done(); - }); - }); - }); - - it('should return the scope (when enabled + async op)', done => { - const scope = { a: 3 }; - const promise = Promise.resolve(); - scopeManager.bind(promise, scope); - promise.then(() => { - setImmediate(() => { - assert.deepStrictEqual(scopeManager.active(), scope); - scopeManager.enable(); - return done(); - }); - }); - }); - }); });