diff --git a/packages/opentelemetry-api/README.md b/packages/opentelemetry-api/README.md index 2e8d75cd41..46ca4fd212 100644 --- a/packages/opentelemetry-api/README.md +++ b/packages/opentelemetry-api/README.md @@ -91,6 +91,10 @@ const meterProvider = new MeterProvider({ api.metrics.setGlobalMeterProvider(meterProvider); ``` +## Version Compatibility + +Because the npm installer and node module resolution algorithm could potentially allow two or more copies of any given package to exist within the same `node_modules` structure, the OpenTelemetry API takes advantage of a variable on the `global` object to store the global API. When an API method in the API package is called, it checks if this `global` API exists and proxies calls to it if and only if it is a compatible API version. This means if a package has a dependency on an OpenTelemetry API version which is not compatible with the API used by the end user, the package will receive a no-op implementation of the API. + ## Advanced Use ### API Registration Options diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 3c5f7f0ea7..b127917990 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -15,17 +15,24 @@ */ import { + Context, ContextManager, NoopContextManager, - Context, } from '@opentelemetry/context-base'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_CONTEXT_MANAGER_API_KEY, + makeGetter, + _global, +} from './global-utils'; + +const NOOP_CONTEXT_MANAGER = new NoopContextManager(); /** * Singleton object which represents the entry point to the OpenTelemetry Context API */ export class ContextAPI { private static _instance?: ContextAPI; - private _contextManager: ContextManager = new NoopContextManager(); /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -45,7 +52,17 @@ export class ContextAPI { public setGlobalContextManager( contextManager: ContextManager ): ContextManager { - this._contextManager = contextManager; + if (_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + // global context manager has already been set + return this._getContextManager(); + } + + _global[GLOBAL_CONTEXT_MANAGER_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + contextManager, + NOOP_CONTEXT_MANAGER + ); + return contextManager; } @@ -53,7 +70,7 @@ export class ContextAPI { * Get the currently active context */ public active(): Context { - return this._contextManager.active(); + return this._getContextManager().active(); } /** @@ -66,7 +83,7 @@ export class ContextAPI { context: Context, fn: T ): ReturnType { - return this._contextManager.with(context, fn); + return this._getContextManager().with(context, fn); } /** @@ -76,6 +93,20 @@ export class ContextAPI { * @param context context to bind to the event emitter or function. Defaults to the currently active context */ public bind(target: T, context: Context = this.active()): T { - return this._contextManager.bind(target, context); + return this._getContextManager().bind(target, context); + } + + private _getContextManager(): ContextManager { + return ( + _global[GLOBAL_CONTEXT_MANAGER_API_KEY]?.( + API_BACKWARDS_COMPATIBILITY_VERSION + ) ?? NOOP_CONTEXT_MANAGER + ); + } + + /** Disable and remove the global context manager */ + public disable() { + this._getContextManager().disable(); + delete _global[GLOBAL_CONTEXT_MANAGER_API_KEY]; } } diff --git a/packages/opentelemetry-api/src/api/global-utils.ts b/packages/opentelemetry-api/src/api/global-utils.ts new file mode 100644 index 0000000000..3114d1b6d0 --- /dev/null +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -0,0 +1,67 @@ +/*! + * Copyright 2020, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ContextManager } from '@opentelemetry/context-base'; +import { HttpTextPropagator } from '../context/propagation/HttpTextPropagator'; +import { MeterProvider } from '../metrics/MeterProvider'; +import { TracerProvider } from '../trace/tracer_provider'; + +export const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.context' +); +export const GLOBAL_METRICS_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.metrics' +); +export const GLOBAL_PROPAGATION_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.propagation' +); +export const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace'); + +type Get = (version: number) => T; +type MyGlobals = Partial<{ + [GLOBAL_CONTEXT_MANAGER_API_KEY]: Get; + [GLOBAL_METRICS_API_KEY]: Get; + [GLOBAL_PROPAGATION_API_KEY]: Get; + [GLOBAL_TRACE_API_KEY]: Get; +}>; + +export const _global = global as typeof global & MyGlobals; + +/** + * Make a function which accepts a version integer and returns the instance of an API if the version + * is compatible, or a fallback version (usually NOOP) if it is not. + * + * @param requiredVersion Backwards compatibility version which is required to return the instance + * @param instance Instance which should be returned if the required version is compatible + * @param fallback Fallback instance, usually NOOP, which will be returned if the required version is not compatible + */ +export function makeGetter( + requiredVersion: number, + instance: T, + fallback: T +): Get { + return (version: number): T => + version === requiredVersion ? instance : fallback; +} + +/** + * A number which should be incremented each time a backwards incompatible + * change is made to the API. This number is used when an API package + * attempts to access the global API to ensure it is getting a compatible + * version. If the global API is not compatible with the API package + * attempting to get it, a NOOP API implementation will be returned. + */ +export const API_BACKWARDS_COMPATIBILITY_VERSION = 0; diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 118c20db99..dedf58be54 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -17,13 +17,18 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_METRICS_API_KEY, + makeGetter, + _global, +} from './global-utils'; /** * Singleton object which represents the entry point to the OpenTelemetry Metrics API */ export class MetricsAPI { private static _instance?: MetricsAPI; - private _meterProvider: MeterProvider = NOOP_METER_PROVIDER; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -41,7 +46,17 @@ export class MetricsAPI { * Set the current global meter. Returns the initialized global meter provider. */ public setGlobalMeterProvider(provider: MeterProvider): MeterProvider { - this._meterProvider = provider; + if (_global[GLOBAL_METRICS_API_KEY]) { + // global meter provider has already been set + return this.getMeterProvider(); + } + + _global[GLOBAL_METRICS_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + provider, + NOOP_METER_PROVIDER + ); + return provider; } @@ -49,7 +64,10 @@ export class MetricsAPI { * Returns the global meter provider. */ public getMeterProvider(): MeterProvider { - return this._meterProvider; + return ( + _global[GLOBAL_METRICS_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_METER_PROVIDER + ); } /** @@ -58,4 +76,9 @@ export class MetricsAPI { public getMeter(name: string, version?: string): Meter { return this.getMeterProvider().getMeter(name, version); } + + /** Remove the global meter provider */ + public disable() { + delete _global[GLOBAL_METRICS_API_KEY]; + } } diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index f26c3c6f80..a8af524244 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -20,6 +20,12 @@ import { HttpTextPropagator } from '../context/propagation/HttpTextPropagator'; import { NOOP_HTTP_TEXT_PROPAGATOR } from '../context/propagation/NoopHttpTextPropagator'; import { defaultSetter, SetterFunction } from '../context/propagation/setter'; import { ContextAPI } from './context'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_PROPAGATION_API_KEY, + makeGetter, + _global, +} from './global-utils'; const contextApi = ContextAPI.getInstance(); @@ -28,7 +34,6 @@ const contextApi = ContextAPI.getInstance(); */ export class PropagationAPI { private static _instance?: PropagationAPI; - private _propagator: HttpTextPropagator = NOOP_HTTP_TEXT_PROPAGATOR; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -48,7 +53,17 @@ export class PropagationAPI { public setGlobalPropagator( propagator: HttpTextPropagator ): HttpTextPropagator { - this._propagator = propagator; + if (_global[GLOBAL_PROPAGATION_API_KEY]) { + // global propagator has already been set + return this._getGlobalPropagator(); + } + + _global[GLOBAL_PROPAGATION_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + propagator, + NOOP_HTTP_TEXT_PROPAGATOR + ); + return propagator; } @@ -64,7 +79,7 @@ export class PropagationAPI { setter: SetterFunction = defaultSetter, context = contextApi.active() ): void { - return this._propagator.inject(context, carrier, setter); + return this._getGlobalPropagator().inject(context, carrier, setter); } /** @@ -79,6 +94,19 @@ export class PropagationAPI { getter: GetterFunction = defaultGetter, context = contextApi.active() ): Context { - return this._propagator.extract(context, carrier, getter); + return this._getGlobalPropagator().extract(context, carrier, getter); + } + + /** Remove the global propagator */ + public disable() { + delete _global[GLOBAL_PROPAGATION_API_KEY]; + } + + private _getGlobalPropagator(): HttpTextPropagator { + return ( + _global[GLOBAL_PROPAGATION_API_KEY]?.( + API_BACKWARDS_COMPATIBILITY_VERSION + ) ?? NOOP_HTTP_TEXT_PROPAGATOR + ); } } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 4af88e70e6..bae7353e08 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -15,15 +15,20 @@ */ import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider'; -import { TracerProvider } from '../trace/tracer_provider'; import { Tracer } from '../trace/tracer'; +import { TracerProvider } from '../trace/tracer_provider'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_TRACE_API_KEY, + makeGetter, + _global, +} from './global-utils'; /** * Singleton object which represents the entry point to the OpenTelemetry Tracing API */ export class TraceAPI { private static _instance?: TraceAPI; - private _tracerProvider: TracerProvider = NOOP_TRACER_PROVIDER; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -41,15 +46,28 @@ export class TraceAPI { * Set the current global tracer. Returns the initialized global tracer provider */ public setGlobalTracerProvider(provider: TracerProvider): TracerProvider { - this._tracerProvider = provider; - return provider; + if (_global[GLOBAL_TRACE_API_KEY]) { + // global tracer provider has already been set + return this.getTracerProvider(); + } + + _global[GLOBAL_TRACE_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + provider, + NOOP_TRACER_PROVIDER + ); + + return this.getTracerProvider(); } /** * Returns the global tracer provider. */ public getTracerProvider(): TracerProvider { - return this._tracerProvider; + return ( + _global[GLOBAL_TRACE_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_TRACER_PROVIDER + ); } /** @@ -58,4 +76,9 @@ export class TraceAPI { public getTracer(name: string, version?: string): Tracer { return this.getTracerProvider().getTracer(name, version); } + + /** Remove the global tracer provider */ + public disable() { + delete _global[GLOBAL_TRACE_API_KEY]; + } } diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index e9994038cc..d02453d252 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -22,6 +22,10 @@ import api, { NoopTracer, SpanOptions, Span, + context, + trace, + propagation, + metrics, } from '../../src'; describe('API', () => { @@ -41,8 +45,11 @@ describe('API', () => { }; const dummySpan = new NoopSpan(spanContext); - afterEach(() => { - api.trace.setGlobalTracerProvider(new NoopTracerProvider()); + beforeEach(() => { + context.disable(); + trace.disable(); + propagation.disable(); + metrics.disable(); }); it('should not crash', () => { diff --git a/packages/opentelemetry-api/test/api/global.test.ts b/packages/opentelemetry-api/test/api/global.test.ts new file mode 100644 index 0000000000..5ff4e25a2b --- /dev/null +++ b/packages/opentelemetry-api/test/api/global.test.ts @@ -0,0 +1,81 @@ +/*! + * Copyright 2020, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; +import { NoopContextManager } from '@opentelemetry/context-base'; +import { + _global, + GLOBAL_CONTEXT_MANAGER_API_KEY, +} from '../../src/api/global-utils'; + +const api1 = require('../../src') as typeof import('../../src'); + +// clear cache and load a second instance of the api +for (const key of Object.keys(require.cache)) { + delete require.cache[key]; +} +const api2 = require('../../src') as typeof import('../../src'); + +describe('Global Utils', () => { + // prove they are separate instances + assert.notEqual(api1, api2); + // that return separate noop instances to start + assert.notStrictEqual( + api1.context['_getContextManager'](), + api2.context['_getContextManager']() + ); + + beforeEach(() => { + api1.context.disable(); + api1.propagation.disable(); + api1.trace.disable(); + api1.metrics.disable(); + }); + + it('should change the global context manager', () => { + const original = api1.context['_getContextManager'](); + const newContextManager = new NoopContextManager(); + api1.context.setGlobalContextManager(newContextManager); + assert.notStrictEqual(api1.context['_getContextManager'](), original); + assert.strictEqual(api1.context['_getContextManager'](), newContextManager); + }); + + it('should load an instance from one which was set in the other', () => { + api1.context.setGlobalContextManager(new NoopContextManager()); + assert.strictEqual( + api1.context['_getContextManager'](), + api2.context['_getContextManager']() + ); + }); + + it('should disable both if one is disabled', () => { + const original = api1.context['_getContextManager'](); + + api1.context.setGlobalContextManager(new NoopContextManager()); + + assert.notStrictEqual(original, api1.context['_getContextManager']()); + api2.context.disable(); + assert.strictEqual(original, api1.context['_getContextManager']()); + }); + + it('should return the module NoOp implementation if the version is a mismatch', () => { + const original = api1.context['_getContextManager'](); + api1.context.setGlobalContextManager(new NoopContextManager()); + const afterSet = _global[GLOBAL_CONTEXT_MANAGER_API_KEY]!(-1); + + assert.strictEqual(original, afterSet); + }); +}); diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index 1cd0298e62..d38dda5319 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -58,6 +58,7 @@ describe('NodeTracerProvider', () => { Object.keys(require.cache).forEach(key => delete require.cache[key]); provider.stop(); contextManager.disable(); + context.disable(); }); describe('constructor', () => { diff --git a/packages/opentelemetry-node/test/registration.test.ts b/packages/opentelemetry-node/test/registration.test.ts index e36d910d45..d305673470 100644 --- a/packages/opentelemetry-node/test/registration.test.ts +++ b/packages/opentelemetry-node/test/registration.test.ts @@ -17,30 +17,33 @@ import { context, NoopHttpTextPropagator, - NoopTracerProvider, propagation, trace, } from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopContextManager } from '@opentelemetry/context-base'; +import { HttpTraceContext } from '@opentelemetry/core'; import * as assert from 'assert'; import { NodeTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); - propagation.setGlobalPropagator(new NoopHttpTextPropagator()); - trace.setGlobalTracerProvider(new NoopTracerProvider()); + context.disable(); + trace.disable(); + propagation.disable(); }); it('should register default implementations', () => { const tracerProvider = new NodeTracerProvider(); tracerProvider.register(); - assert.ok(context['_contextManager'] instanceof AsyncHooksContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + context['_getContextManager']() instanceof AsyncHooksContextManager + ); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should register configured implementations', () => { @@ -54,10 +57,10 @@ describe('API registration', () => { propagator, }); - assert.ok(context['_contextManager'] === contextManager); - assert.ok(propagation['_propagator'] === propagator); + assert.ok(context['_getContextManager']() === contextManager); + assert.ok(propagation['_getGlobalPropagator']() === propagator); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null context manager', () => { @@ -66,10 +69,12 @@ describe('API registration', () => { contextManager: null, }); - assert.ok(context['_contextManager'] instanceof NoopContextManager); + assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null propagator', () => { @@ -78,9 +83,13 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_propagator'] instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); - assert.ok(context['_contextManager'] instanceof AsyncHooksContextManager); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + context['_getContextManager']() instanceof AsyncHooksContextManager + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); }); diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index 56ad4f09bf..c137361b24 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -312,7 +312,7 @@ describe('GrpcPlugin', () => { }); afterEach(() => { - contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index 94c9c410f6..10fa530ba3 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -85,7 +85,7 @@ describe('HttpPlugin', () => { }); afterEach(() => { - contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts index c6880fda54..9b69793d28 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { SpanKind } from '@opentelemetry/api'; +import { context, SpanKind } from '@opentelemetry/api'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; import { @@ -40,6 +41,13 @@ const memoryExporter = new InMemorySpanExporter(); const protocol = 'http'; describe('Packages', () => { + beforeEach(() => { + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('get', () => { const logger = new NoopLogger(); const provider = new NodeTracerProvider({ diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index 0a529c684e..8b08378576 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { SpanKind, Span, context } from '@opentelemetry/api'; import * as assert from 'assert'; import * as http from 'http'; import { plugin } from '../../src/http'; @@ -31,6 +31,7 @@ import { } from '@opentelemetry/tracing'; import { HttpPluginConfig } from '../../src/types'; import { AttributeNames } from '../../src/enums/AttributeNames'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; const protocol = 'http'; const serverPort = 32345; const hostname = 'localhost'; @@ -41,6 +42,14 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpPlugin Integration tests', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('enable()', () => { before(function(done) { // mandatory diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts index 16ed7f67e8..5648223fe0 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -92,6 +92,7 @@ describe('HttpsPlugin', () => { afterEach(() => { contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts index 106d00a32e..0b6935fe36 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -14,27 +14,28 @@ * limitations under the License. */ +import { context, Span, SpanKind } from '@opentelemetry/api'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { NodeTracerProvider } from '@opentelemetry/node'; +import { Http } from '@opentelemetry/plugin-http'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; import * as assert from 'assert'; -import * as https from 'https'; +import axios, { AxiosResponse } from 'axios'; +import * as got from 'got'; import * as http from 'http'; +import * as https from 'https'; import * as nock from 'nock'; +import * as path from 'path'; +import * as request from 'request-promise-native'; +import * as superagent from 'superagent'; +import * as url from 'url'; import { plugin } from '../../src/https'; import { assertSpan } from '../utils/assertSpan'; import { DummyPropagation } from '../utils/DummyPropagation'; -import * as url from 'url'; -import axios, { AxiosResponse } from 'axios'; -import * as superagent from 'superagent'; -import * as got from 'got'; -import * as request from 'request-promise-native'; -import * as path from 'path'; -import { - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/tracing'; -import { Http } from '@opentelemetry/plugin-http'; -import { NodeTracerProvider } from '@opentelemetry/node'; const memoryExporter = new InMemorySpanExporter(); @@ -43,6 +44,14 @@ export const customAttributeFunction = (span: Span): void => { }; describe('Packages', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('get', () => { const logger = new NoopLogger(); diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index fa8be0e518..d66ee4ae90 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -20,7 +20,7 @@ import { Http, AttributeNames, } from '@opentelemetry/plugin-http'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { SpanKind, Span, context } from '@opentelemetry/api'; import * as assert from 'assert'; import * as http from 'http'; import * as https from 'https'; @@ -35,6 +35,7 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; const protocol = 'https'; const serverPort = 42345; @@ -46,6 +47,15 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpsPlugin Integration tests', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); + describe('enable()', () => { before(function(done) { // mandatory diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index c35741cd38..52693d840a 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -105,7 +105,7 @@ describe('xhr', () => { }); afterEach(() => { - contextManager.disable(); + types.context.disable(); }); before(() => { diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index 832128e9c4..4b38b09046 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -15,6 +15,7 @@ */ import { Context, context, SpanContext, TraceFlags } from '@opentelemetry/api'; +import { ContextManager } from '@opentelemetry/context-base'; import { ALWAYS_SAMPLER, NEVER_SAMPLER, @@ -25,16 +26,12 @@ import { TraceState, } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { - NoopContextManager, - ContextManager, -} from '@opentelemetry/context-base'; import * as assert from 'assert'; import { BasicTracerProvider, Span } from '../src'; describe('BasicTracerProvider', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); + context.disable(); }); describe('constructor', () => { @@ -338,6 +335,7 @@ describe('BasicTracerProvider', () => { context.setGlobalContextManager({ active: () => setActiveSpan(Context.ROOT_CONTEXT, ('foo' as any) as Span), + disable: () => {}, } as ContextManager); const tracer = new BasicTracerProvider().getTracer('default'); diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index e22d4cef86..60007a4479 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -15,11 +15,11 @@ */ import { context } from '@opentelemetry/api'; -import { B3Propagator, BasePlugin, NoopLogger } from '@opentelemetry/core'; import { ContextManager } from '@opentelemetry/context-base'; import { ZoneContextManager } from '@opentelemetry/context-zone'; -import { Tracer, Span } from '@opentelemetry/tracing'; +import { B3Propagator, BasePlugin, NoopLogger } from '@opentelemetry/core'; import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources'; +import { Span, Tracer } from '@opentelemetry/tracing'; import * as assert from 'assert'; import * as sinon from 'sinon'; import { WebTracerConfig } from '../src'; @@ -48,6 +48,7 @@ describe('WebTracerProvider', () => { afterEach(() => { contextManager.disable(); + context.disable(); }); it('should construct an instance with required only options', () => { diff --git a/packages/opentelemetry-web/test/registration.test.ts b/packages/opentelemetry-web/test/registration.test.ts index 497bc868d0..adcee3a94e 100644 --- a/packages/opentelemetry-web/test/registration.test.ts +++ b/packages/opentelemetry-web/test/registration.test.ts @@ -17,29 +17,30 @@ import { context, NoopHttpTextPropagator, - NoopTracerProvider, propagation, trace, } from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; import { NoopContextManager } from '@opentelemetry/context-base'; +import { HttpTraceContext } from '@opentelemetry/core'; import * as assert from 'assert'; -import { WebTracerProvider, StackContextManager } from '../src'; +import { StackContextManager, WebTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); - propagation.setGlobalPropagator(new NoopHttpTextPropagator()); - trace.setGlobalTracerProvider(new NoopTracerProvider()); + context.disable(); + trace.disable(); + propagation.disable(); }); it('should register default implementations', () => { const tracerProvider = new WebTracerProvider(); tracerProvider.register(); - assert.ok(context['_contextManager'] instanceof StackContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(context['_getContextManager']() instanceof StackContextManager); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should register configured implementations', () => { @@ -53,10 +54,10 @@ describe('API registration', () => { propagator, }); - assert.ok(context['_contextManager'] === contextManager); - assert.ok(propagation['_propagator'] === propagator); + assert.ok(context['_getContextManager']() === contextManager); + assert.ok(propagation['_getGlobalPropagator']() === propagator); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null context manager', () => { @@ -65,10 +66,12 @@ describe('API registration', () => { contextManager: null, }); - assert.ok(context['_contextManager'] instanceof NoopContextManager); + assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null propagator', () => { @@ -77,9 +80,11 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_propagator'] instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); - assert.ok(context['_contextManager'] instanceof StackContextManager); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(context['_getContextManager']() instanceof StackContextManager); + assert.ok(trace.getTracerProvider() === tracerProvider); }); });