From 2ed9e5712c98211c2802a4c6d4004bdbca8d202f Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 7 Apr 2020 17:04:07 -0400 Subject: [PATCH 1/7] feat: use global API instances --- packages/opentelemetry-api/src/api/context.ts | 40 ++++++++++++++--- packages/opentelemetry-api/src/api/metrics.ts | 28 ++++++++++-- .../opentelemetry-api/src/api/propagation.ts | 34 +++++++++++++-- packages/opentelemetry-api/src/api/trace.ts | 31 +++++++++++-- .../opentelemetry-api/test/api/api.test.ts | 13 ++++-- .../test/NodeTracerProvider.test.ts | 1 + .../test/registration.test.ts | 40 ++++++++--------- .../test/grpc.test.ts | 2 +- .../test/functionals/http-enable.test.ts | 2 +- .../test/functionals/http-package.test.ts | 15 ++++--- .../test/integrations/http-enable.test.ts | 11 ++++- .../test/functionals/https-enable.test.ts | 1 + .../test/functionals/https-package.test.ts | 34 +++++++++------ .../test/integrations/https-enable.test.ts | 12 +++++- .../test/xhr.test.ts | 2 +- .../test/BasicTracerProvider.test.ts | 18 ++------ .../test/WebTracerProvider.test.ts | 13 +++--- .../test/registration.test.ts | 43 ++++++++----------- 18 files changed, 230 insertions(+), 110 deletions(-) diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 3c5f7f0ea7..04134813eb 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -20,12 +20,16 @@ import { Context, } from '@opentelemetry/context-base'; +const NOOP_CONTEXT_MANAGER = new NoopContextManager(); + +const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for("io.opentelemetry.js.api.context"); +const API_VERSION = 0; + /** * 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,15 +49,28 @@ export class ContextAPI { public setGlobalContextManager( contextManager: ContextManager ): ContextManager { - this._contextManager = contextManager; + if ((global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + // global context manager has already been set + return NOOP_CONTEXT_MANAGER; + } + + (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY] = function getTraceApi (version: number) { + if (version !== API_VERSION) { + return NOOP_CONTEXT_MANAGER; + } + + return contextManager; + } + return contextManager; } + /** * 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,19 @@ 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 { + if (!(global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + return NOOP_CONTEXT_MANAGER; + } + + return (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY](API_VERSION); + } + + public disable() { + this._getContextManager().disable(); + delete (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]; } } diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 118c20db99..5ed3f2c386 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -18,12 +18,14 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; +const GLOBAL_METRICS_API_KEY = Symbol.for("io.opentelemetry.js.api.metrics"); +const API_VERSION = 0; + /** * 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 +43,19 @@ export class MetricsAPI { * Set the current global meter. Returns the initialized global meter provider. */ public setGlobalMeterProvider(provider: MeterProvider): MeterProvider { - this._meterProvider = provider; + if ((global as any)[GLOBAL_METRICS_API_KEY]) { + // global meter provider has already been set + return NOOP_METER_PROVIDER; + } + + (global as any)[GLOBAL_METRICS_API_KEY] = function getTraceApi (version: number) { + if (version !== API_VERSION) { + return NOOP_METER_PROVIDER; + } + + return provider; + } + return provider; } @@ -49,7 +63,11 @@ export class MetricsAPI { * Returns the global meter provider. */ public getMeterProvider(): MeterProvider { - return this._meterProvider; + if (!(global as any)[GLOBAL_METRICS_API_KEY]) { + return NOOP_METER_PROVIDER; + } + + return (global as any)[GLOBAL_METRICS_API_KEY](API_VERSION); } /** @@ -58,4 +76,8 @@ export class MetricsAPI { public getMeter(name: string, version?: string): Meter { return this.getMeterProvider().getMeter(name, version); } + + public disable() { + delete (global as any)[GLOBAL_METRICS_API_KEY]; + } } diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index f26c3c6f80..b080ec5250 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -23,12 +23,14 @@ import { ContextAPI } from './context'; const contextApi = ContextAPI.getInstance(); +const GLOBAL_PROPAGATION_API_KEY = Symbol.for("io.opentelemetry.js.api.propagation"); +const API_VERSION = 0; + /** * Singleton object which represents the entry point to the OpenTelemetry Propagation API */ 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 +50,19 @@ export class PropagationAPI { public setGlobalPropagator( propagator: HttpTextPropagator ): HttpTextPropagator { - this._propagator = propagator; + if ((global as any)[GLOBAL_PROPAGATION_API_KEY]) { + // global propagator has already been set + return NOOP_HTTP_TEXT_PROPAGATOR; + } + + (global as any)[GLOBAL_PROPAGATION_API_KEY] = function getTraceApi (version: number) { + if (version !== API_VERSION) { + return NOOP_HTTP_TEXT_PROPAGATOR; + } + + return propagator; + } + return propagator; } @@ -64,7 +78,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 +93,18 @@ export class PropagationAPI { getter: GetterFunction = defaultGetter, context = contextApi.active() ): Context { - return this._propagator.extract(context, carrier, getter); + return this._getGlobalPropagator().extract(context, carrier, getter); + } + + public disable() { + delete (global as any)[GLOBAL_PROPAGATION_API_KEY]; + } + + private _getGlobalPropagator(): HttpTextPropagator { + if (!(global as any)[GLOBAL_PROPAGATION_API_KEY]) { + return NOOP_HTTP_TEXT_PROPAGATOR; + } + + return (global as any)[GLOBAL_PROPAGATION_API_KEY](API_VERSION); } } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 4af88e70e6..d46594228f 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -18,12 +18,14 @@ import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider'; import { TracerProvider } from '../trace/tracer_provider'; import { Tracer } from '../trace/tracer'; +const GLOBAL_TRACE_API_KEY = Symbol.for("io.opentelemetry.js.api.trace"); +const API_VERSION = 0; + /** * 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 +43,32 @@ 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 as any)[GLOBAL_TRACE_API_KEY]) { + // global tracer provider has already been set + return NOOP_TRACER_PROVIDER; + } + + (global as any)[GLOBAL_TRACE_API_KEY] = function getTraceApi (version: number) { + if (version !== API_VERSION) { + return NOOP_TRACER_PROVIDER; + } + + return provider; + } + + return this.getTracerProvider(); } /** * Returns the global tracer provider. */ public getTracerProvider(): TracerProvider { - return this._tracerProvider; + if (!(global as any)[GLOBAL_TRACE_API_KEY]) { + // global tracer provider has already been set + return NOOP_TRACER_PROVIDER; + } + + return (global as any)[GLOBAL_TRACE_API_KEY](API_VERSION); } /** @@ -58,4 +77,8 @@ export class TraceAPI { public getTracer(name: string, version?: string): Tracer { return this.getTracerProvider().getTracer(name, version); } + + public disable() { + delete (global as any)[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..adb435426a 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,9 +45,12 @@ 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', () => { functions.forEach(fn => { diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index 1cd0298e62..c10ac94d3c 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..354c789563 100644 --- a/packages/opentelemetry-node/test/registration.test.ts +++ b/packages/opentelemetry-node/test/registration.test.ts @@ -14,33 +14,27 @@ * limitations under the License. */ -import { - context, - NoopHttpTextPropagator, - NoopTracerProvider, - propagation, - trace, -} from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; +import { context, NoopHttpTextPropagator, propagation, trace } from '@opentelemetry/api'; 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 +48,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 +60,10 @@ 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 +72,9 @@ 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..b2d1221fa2 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..307a005a0f 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..a9e27e08b1 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -14,13 +14,11 @@ * 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 { - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/tracing'; +import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import * as assert from 'assert'; import axios, { AxiosResponse } from 'axios'; import * as got from 'got'; @@ -40,6 +38,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..93d8b1c0cd 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..15ee02737d 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..48a2373c4a 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,25 @@ * 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 +41,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..67106ac29d 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..cdbf11e658 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..ad9950854f 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -15,26 +15,15 @@ */ import { Context, context, SpanContext, TraceFlags } from '@opentelemetry/api'; -import { - ALWAYS_SAMPLER, - NEVER_SAMPLER, - NoopLogger, - NoRecordingSpan, - setActiveSpan, - setExtractedSpanContext, - TraceState, -} from '@opentelemetry/core'; +import { ContextManager } from '@opentelemetry/context-base'; +import { ALWAYS_SAMPLER, NEVER_SAMPLER, NoopLogger, NoRecordingSpan, setActiveSpan, setExtractedSpanContext, 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 +327,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..d382760577 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'; @@ -31,8 +31,8 @@ class DummyPlugin extends BasePlugin { } moduleName = 'dummy'; - patch() {} - unpatch() {} + patch() { } + unpatch() { } } describe('WebTracerProvider', () => { @@ -48,6 +48,7 @@ describe('WebTracerProvider', () => { afterEach(() => { contextManager.disable(); + context.disable() }); it('should construct an instance with required only options', () => { @@ -91,7 +92,7 @@ describe('WebTracerProvider', () => { assert.strictEqual( error, 'contextManager should be defined in' + - ' register method not in constructor' + ' register method not in constructor' ); }); @@ -107,7 +108,7 @@ describe('WebTracerProvider', () => { assert.strictEqual( error, 'propagator should be defined in register' + - ' method not in constructor' + ' method not in constructor' ); }); diff --git a/packages/opentelemetry-web/test/registration.test.ts b/packages/opentelemetry-web/test/registration.test.ts index 497bc868d0..79adce9bfc 100644 --- a/packages/opentelemetry-web/test/registration.test.ts +++ b/packages/opentelemetry-web/test/registration.test.ts @@ -14,32 +14,27 @@ * limitations under the License. */ -import { - context, - NoopHttpTextPropagator, - NoopTracerProvider, - propagation, - trace, -} from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; +import { context, NoopHttpTextPropagator, propagation, trace } from '@opentelemetry/api'; 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 +48,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 +60,10 @@ 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 +72,9 @@ 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); }); }); From 5b12da18cd68567491a1059e7667755a518646e7 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 7 Apr 2020 17:23:29 -0400 Subject: [PATCH 2/7] chore: add jsdoc for api remove methods --- packages/opentelemetry-api/src/api/context.ts | 1 + packages/opentelemetry-api/src/api/metrics.ts | 1 + packages/opentelemetry-api/src/api/propagation.ts | 1 + packages/opentelemetry-api/src/api/trace.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 04134813eb..b93aabeffc 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -104,6 +104,7 @@ export class ContextAPI { return (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY](API_VERSION); } + /** Disable and remove the global context manager */ public disable() { this._getContextManager().disable(); delete (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]; diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 5ed3f2c386..5db11cbce3 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -77,6 +77,7 @@ export class MetricsAPI { return this.getMeterProvider().getMeter(name, version); } + /** Remove the global meter provider */ public disable() { delete (global as any)[GLOBAL_METRICS_API_KEY]; } diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index b080ec5250..35fe337e92 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -96,6 +96,7 @@ export class PropagationAPI { return this._getGlobalPropagator().extract(context, carrier, getter); } + /** Remove the global propagator */ public disable() { delete (global as any)[GLOBAL_PROPAGATION_API_KEY]; } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index d46594228f..008bb5b370 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -78,6 +78,7 @@ export class TraceAPI { return this.getTracerProvider().getTracer(name, version); } + /** Remove the global tracer provider */ public disable() { delete (global as any)[GLOBAL_TRACE_API_KEY]; } From 8f377e72e41b70ea4d82ae8c7bb0a74076657d26 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 7 Apr 2020 17:48:32 -0400 Subject: [PATCH 3/7] chore: lint --- packages/opentelemetry-api/src/api/context.ts | 11 ++++--- packages/opentelemetry-api/src/api/metrics.ts | 8 +++-- .../opentelemetry-api/src/api/propagation.ts | 10 +++++-- packages/opentelemetry-api/src/api/trace.ts | 8 +++-- .../opentelemetry-api/test/api/api.test.ts | 4 +-- .../test/NodeTracerProvider.test.ts | 2 +- .../test/registration.test.ts | 29 ++++++++++++++----- .../test/grpc.test.ts | 2 +- .../test/functionals/http-enable.test.ts | 2 +- .../test/functionals/http-package.test.ts | 7 +++-- .../test/integrations/http-enable.test.ts | 4 +-- .../test/functionals/https-enable.test.ts | 2 +- .../test/functionals/https-package.test.ts | 9 ++++-- .../test/integrations/https-enable.test.ts | 4 +-- .../test/xhr.test.ts | 2 +- .../test/BasicTracerProvider.test.ts | 12 ++++++-- .../test/WebTracerProvider.test.ts | 10 +++---- .../test/registration.test.ts | 22 ++++++++++---- 18 files changed, 99 insertions(+), 49 deletions(-) diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index b93aabeffc..1044311b3f 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -22,7 +22,9 @@ import { const NOOP_CONTEXT_MANAGER = new NoopContextManager(); -const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for("io.opentelemetry.js.api.context"); +const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.context' +); const API_VERSION = 0; /** @@ -54,18 +56,19 @@ export class ContextAPI { return NOOP_CONTEXT_MANAGER; } - (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY] = function getTraceApi (version: number) { + (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY] = function getTraceApi( + version: number + ) { if (version !== API_VERSION) { return NOOP_CONTEXT_MANAGER; } return contextManager; - } + }; return contextManager; } - /** * Get the currently active context */ diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 5db11cbce3..0659d90e28 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -18,7 +18,7 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; -const GLOBAL_METRICS_API_KEY = Symbol.for("io.opentelemetry.js.api.metrics"); +const GLOBAL_METRICS_API_KEY = Symbol.for('io.opentelemetry.js.api.metrics'); const API_VERSION = 0; /** @@ -48,13 +48,15 @@ export class MetricsAPI { return NOOP_METER_PROVIDER; } - (global as any)[GLOBAL_METRICS_API_KEY] = function getTraceApi (version: number) { + (global as any)[GLOBAL_METRICS_API_KEY] = function getTraceApi( + version: number + ) { if (version !== API_VERSION) { return NOOP_METER_PROVIDER; } return provider; - } + }; return provider; } diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index 35fe337e92..a07a66ea15 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -23,7 +23,9 @@ import { ContextAPI } from './context'; const contextApi = ContextAPI.getInstance(); -const GLOBAL_PROPAGATION_API_KEY = Symbol.for("io.opentelemetry.js.api.propagation"); +const GLOBAL_PROPAGATION_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.propagation' +); const API_VERSION = 0; /** @@ -55,13 +57,15 @@ export class PropagationAPI { return NOOP_HTTP_TEXT_PROPAGATOR; } - (global as any)[GLOBAL_PROPAGATION_API_KEY] = function getTraceApi (version: number) { + (global as any)[GLOBAL_PROPAGATION_API_KEY] = function getTraceApi( + version: number + ) { if (version !== API_VERSION) { return NOOP_HTTP_TEXT_PROPAGATOR; } return propagator; - } + }; return propagator; } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 008bb5b370..827c1100fc 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -18,7 +18,7 @@ import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider'; import { TracerProvider } from '../trace/tracer_provider'; import { Tracer } from '../trace/tracer'; -const GLOBAL_TRACE_API_KEY = Symbol.for("io.opentelemetry.js.api.trace"); +const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace'); const API_VERSION = 0; /** @@ -48,13 +48,15 @@ export class TraceAPI { return NOOP_TRACER_PROVIDER; } - (global as any)[GLOBAL_TRACE_API_KEY] = function getTraceApi (version: number) { + (global as any)[GLOBAL_TRACE_API_KEY] = function getTraceApi( + version: number + ) { if (version !== API_VERSION) { return NOOP_TRACER_PROVIDER; } return provider; - } + }; return this.getTracerProvider(); } diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index adb435426a..d02453d252 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -46,11 +46,11 @@ describe('API', () => { const dummySpan = new NoopSpan(spanContext); beforeEach(() => { - context.disable() + context.disable(); trace.disable(); propagation.disable(); metrics.disable(); - }) + }); it('should not crash', () => { functions.forEach(fn => { diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index c10ac94d3c..d38dda5319 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -58,7 +58,7 @@ describe('NodeTracerProvider', () => { Object.keys(require.cache).forEach(key => delete require.cache[key]); provider.stop(); contextManager.disable(); - context.disable() + context.disable(); }); describe('constructor', () => { diff --git a/packages/opentelemetry-node/test/registration.test.ts b/packages/opentelemetry-node/test/registration.test.ts index 354c789563..d305673470 100644 --- a/packages/opentelemetry-node/test/registration.test.ts +++ b/packages/opentelemetry-node/test/registration.test.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { context, NoopHttpTextPropagator, propagation, trace } from '@opentelemetry/api'; +import { + context, + NoopHttpTextPropagator, + propagation, + trace, +} from '@opentelemetry/api'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopContextManager } from '@opentelemetry/context-base'; import { HttpTraceContext } from '@opentelemetry/core'; @@ -23,7 +28,7 @@ import { NodeTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.disable() + context.disable(); trace.disable(); propagation.disable(); }); @@ -32,8 +37,12 @@ describe('API registration', () => { const tracerProvider = new NodeTracerProvider(); tracerProvider.register(); - assert.ok(context['_getContextManager']() instanceof AsyncHooksContextManager); - assert.ok(propagation['_getGlobalPropagator']() instanceof HttpTraceContext); + assert.ok( + context['_getContextManager']() instanceof AsyncHooksContextManager + ); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); assert.ok(trace.getTracerProvider() === tracerProvider); }); @@ -62,7 +71,9 @@ describe('API registration', () => { assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_getGlobalPropagator']() instanceof HttpTraceContext); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); assert.ok(trace.getTracerProvider() === tracerProvider); }); @@ -72,9 +83,13 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); - assert.ok(context['_getContextManager']() instanceof AsyncHooksContextManager); + 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 b2d1221fa2..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(() => { - context.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 307a005a0f..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(() => { - context.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 a9e27e08b1..9b69793d28 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -18,7 +18,10 @@ import { context, SpanKind } from '@opentelemetry/api'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; -import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; import * as assert from 'assert'; import axios, { AxiosResponse } from 'axios'; import * as got from 'got'; @@ -43,7 +46,7 @@ describe('Packages', () => { }); afterEach(() => { - context.disable() + context.disable(); }); describe('get', () => { const logger = new NoopLogger(); 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 93d8b1c0cd..8b08378576 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -48,8 +48,8 @@ describe('HttpPlugin Integration tests', () => { }); afterEach(() => { - context.disable() - }) + 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 15ee02737d..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,7 +92,7 @@ describe('HttpsPlugin', () => { afterEach(() => { contextManager.disable(); - context.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 48a2373c4a..0b6935fe36 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -19,7 +19,10 @@ import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; import { Http } from '@opentelemetry/plugin-http'; -import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; import * as assert from 'assert'; import axios, { AxiosResponse } from 'axios'; import * as got from 'got'; @@ -47,8 +50,8 @@ describe('Packages', () => { }); afterEach(() => { - context.disable() - }) + 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 67106ac29d..d66ee4ae90 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -53,8 +53,8 @@ describe('HttpsPlugin Integration tests', () => { }); afterEach(() => { - context.disable() - }) + context.disable(); + }); describe('enable()', () => { before(function(done) { 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 cdbf11e658..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(() => { - types.context.disable() + types.context.disable(); }); before(() => { diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index ad9950854f..4b38b09046 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -16,14 +16,22 @@ import { Context, context, SpanContext, TraceFlags } from '@opentelemetry/api'; import { ContextManager } from '@opentelemetry/context-base'; -import { ALWAYS_SAMPLER, NEVER_SAMPLER, NoopLogger, NoRecordingSpan, setActiveSpan, setExtractedSpanContext, TraceState } from '@opentelemetry/core'; +import { + ALWAYS_SAMPLER, + NEVER_SAMPLER, + NoopLogger, + NoRecordingSpan, + setActiveSpan, + setExtractedSpanContext, + TraceState, +} from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; import { BasicTracerProvider, Span } from '../src'; describe('BasicTracerProvider', () => { beforeEach(() => { - context.disable() + context.disable(); }); describe('constructor', () => { diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index d382760577..60007a4479 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -31,8 +31,8 @@ class DummyPlugin extends BasePlugin { } moduleName = 'dummy'; - patch() { } - unpatch() { } + patch() {} + unpatch() {} } describe('WebTracerProvider', () => { @@ -48,7 +48,7 @@ describe('WebTracerProvider', () => { afterEach(() => { contextManager.disable(); - context.disable() + context.disable(); }); it('should construct an instance with required only options', () => { @@ -92,7 +92,7 @@ describe('WebTracerProvider', () => { assert.strictEqual( error, 'contextManager should be defined in' + - ' register method not in constructor' + ' register method not in constructor' ); }); @@ -108,7 +108,7 @@ describe('WebTracerProvider', () => { assert.strictEqual( error, 'propagator should be defined in register' + - ' method not in constructor' + ' method not in constructor' ); }); diff --git a/packages/opentelemetry-web/test/registration.test.ts b/packages/opentelemetry-web/test/registration.test.ts index 79adce9bfc..adcee3a94e 100644 --- a/packages/opentelemetry-web/test/registration.test.ts +++ b/packages/opentelemetry-web/test/registration.test.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { context, NoopHttpTextPropagator, propagation, trace } from '@opentelemetry/api'; +import { + context, + NoopHttpTextPropagator, + propagation, + trace, +} from '@opentelemetry/api'; import { NoopContextManager } from '@opentelemetry/context-base'; import { HttpTraceContext } from '@opentelemetry/core'; import * as assert from 'assert'; @@ -22,7 +27,7 @@ import { StackContextManager, WebTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.disable() + context.disable(); trace.disable(); propagation.disable(); }); @@ -31,9 +36,10 @@ describe('API registration', () => { const tracerProvider = new WebTracerProvider(); tracerProvider.register(); - assert.ok(context['_getContextManager']() instanceof StackContextManager); - assert.ok(propagation['_getGlobalPropagator']() instanceof HttpTraceContext); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); assert.ok(trace.getTracerProvider() === tracerProvider); }); @@ -62,7 +68,9 @@ describe('API registration', () => { assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_getGlobalPropagator']() instanceof HttpTraceContext); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); assert.ok(trace.getTracerProvider() === tracerProvider); }); @@ -72,7 +80,9 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); assert.ok(context['_getContextManager']() instanceof StackContextManager); assert.ok(trace.getTracerProvider() === tracerProvider); From a1c408e09a869ae5fbe53db4be25cbd0841d6128 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 7 Apr 2020 22:01:42 -0400 Subject: [PATCH 4/7] chore: share context utilities --- packages/opentelemetry-api/src/api/context.ts | 33 ++++---- .../opentelemetry-api/src/api/global-utils.ts | 50 ++++++++++++ packages/opentelemetry-api/src/api/metrics.ts | 24 +++--- .../opentelemetry-api/src/api/propagation.ts | 30 ++++--- packages/opentelemetry-api/src/api/trace.ts | 26 +++--- .../opentelemetry-api/test/api/global.test.ts | 81 +++++++++++++++++++ 6 files changed, 181 insertions(+), 63 deletions(-) create mode 100644 packages/opentelemetry-api/src/api/global-utils.ts create mode 100644 packages/opentelemetry-api/test/api/global.test.ts diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 1044311b3f..741677c3e0 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -15,16 +15,17 @@ */ import { + Context, ContextManager, NoopContextManager, - Context, } from '@opentelemetry/context-base'; +import { + GLOBAL_CONTEXT_MANAGER_API_KEY, + makeGetter, + _global, +} from './global-utils'; const NOOP_CONTEXT_MANAGER = new NoopContextManager(); - -const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for( - 'io.opentelemetry.js.api.context' -); const API_VERSION = 0; /** @@ -51,20 +52,16 @@ export class ContextAPI { public setGlobalContextManager( contextManager: ContextManager ): ContextManager { - if ((global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + if (_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { // global context manager has already been set return NOOP_CONTEXT_MANAGER; } - (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY] = function getTraceApi( - version: number - ) { - if (version !== API_VERSION) { - return NOOP_CONTEXT_MANAGER; - } - - return contextManager; - }; + _global[GLOBAL_CONTEXT_MANAGER_API_KEY] = makeGetter( + API_VERSION, + contextManager, + NOOP_CONTEXT_MANAGER + ); return contextManager; } @@ -100,16 +97,16 @@ export class ContextAPI { } private _getContextManager(): ContextManager { - if (!(global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + if (!_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { return NOOP_CONTEXT_MANAGER; } - return (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY](API_VERSION); + return _global[GLOBAL_CONTEXT_MANAGER_API_KEY]!(API_VERSION); } /** Disable and remove the global context manager */ public disable() { this._getContextManager().disable(); - delete (global as any)[GLOBAL_CONTEXT_MANAGER_API_KEY]; + 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..79a77fd222 --- /dev/null +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -0,0 +1,50 @@ +/*! + * 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; + +export function makeGetter( + requiredVersion: number, + instance: T, + fallback: T +): Get { + return (version: number): T => + version === requiredVersion ? instance : fallback; +} diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 0659d90e28..6677b9f9e4 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -17,8 +17,8 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; +import { GLOBAL_METRICS_API_KEY, makeGetter, _global } from './global-utils'; -const GLOBAL_METRICS_API_KEY = Symbol.for('io.opentelemetry.js.api.metrics'); const API_VERSION = 0; /** @@ -43,20 +43,16 @@ export class MetricsAPI { * Set the current global meter. Returns the initialized global meter provider. */ public setGlobalMeterProvider(provider: MeterProvider): MeterProvider { - if ((global as any)[GLOBAL_METRICS_API_KEY]) { + if (_global[GLOBAL_METRICS_API_KEY]) { // global meter provider has already been set return NOOP_METER_PROVIDER; } - (global as any)[GLOBAL_METRICS_API_KEY] = function getTraceApi( - version: number - ) { - if (version !== API_VERSION) { - return NOOP_METER_PROVIDER; - } - - return provider; - }; + _global[GLOBAL_METRICS_API_KEY] = makeGetter( + API_VERSION, + provider, + NOOP_METER_PROVIDER + ); return provider; } @@ -65,11 +61,11 @@ export class MetricsAPI { * Returns the global meter provider. */ public getMeterProvider(): MeterProvider { - if (!(global as any)[GLOBAL_METRICS_API_KEY]) { + if (!_global[GLOBAL_METRICS_API_KEY]) { return NOOP_METER_PROVIDER; } - return (global as any)[GLOBAL_METRICS_API_KEY](API_VERSION); + return _global[GLOBAL_METRICS_API_KEY]!(API_VERSION); } /** @@ -81,6 +77,6 @@ export class MetricsAPI { /** Remove the global meter provider */ public disable() { - delete (global as any)[GLOBAL_METRICS_API_KEY]; + 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 a07a66ea15..efef42441f 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -20,12 +20,14 @@ 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 { + GLOBAL_PROPAGATION_API_KEY, + makeGetter, + _global, +} from './global-utils'; const contextApi = ContextAPI.getInstance(); -const GLOBAL_PROPAGATION_API_KEY = Symbol.for( - 'io.opentelemetry.js.api.propagation' -); const API_VERSION = 0; /** @@ -52,20 +54,16 @@ export class PropagationAPI { public setGlobalPropagator( propagator: HttpTextPropagator ): HttpTextPropagator { - if ((global as any)[GLOBAL_PROPAGATION_API_KEY]) { + if (_global[GLOBAL_PROPAGATION_API_KEY]) { // global propagator has already been set return NOOP_HTTP_TEXT_PROPAGATOR; } - (global as any)[GLOBAL_PROPAGATION_API_KEY] = function getTraceApi( - version: number - ) { - if (version !== API_VERSION) { - return NOOP_HTTP_TEXT_PROPAGATOR; - } - - return propagator; - }; + _global[GLOBAL_PROPAGATION_API_KEY] = makeGetter( + API_VERSION, + propagator, + NOOP_HTTP_TEXT_PROPAGATOR + ); return propagator; } @@ -102,14 +100,14 @@ export class PropagationAPI { /** Remove the global propagator */ public disable() { - delete (global as any)[GLOBAL_PROPAGATION_API_KEY]; + delete _global[GLOBAL_PROPAGATION_API_KEY]; } private _getGlobalPropagator(): HttpTextPropagator { - if (!(global as any)[GLOBAL_PROPAGATION_API_KEY]) { + if (!_global[GLOBAL_PROPAGATION_API_KEY]) { return NOOP_HTTP_TEXT_PROPAGATOR; } - return (global as any)[GLOBAL_PROPAGATION_API_KEY](API_VERSION); + return _global[GLOBAL_PROPAGATION_API_KEY]!(API_VERSION); } } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 827c1100fc..4353cfd1f2 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -15,10 +15,10 @@ */ 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 { GLOBAL_TRACE_API_KEY, makeGetter, _global } from './global-utils'; -const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace'); const API_VERSION = 0; /** @@ -43,20 +43,16 @@ export class TraceAPI { * Set the current global tracer. Returns the initialized global tracer provider */ public setGlobalTracerProvider(provider: TracerProvider): TracerProvider { - if ((global as any)[GLOBAL_TRACE_API_KEY]) { + if (_global[GLOBAL_TRACE_API_KEY]) { // global tracer provider has already been set return NOOP_TRACER_PROVIDER; } - (global as any)[GLOBAL_TRACE_API_KEY] = function getTraceApi( - version: number - ) { - if (version !== API_VERSION) { - return NOOP_TRACER_PROVIDER; - } - - return provider; - }; + _global[GLOBAL_TRACE_API_KEY] = makeGetter( + API_VERSION, + provider, + NOOP_TRACER_PROVIDER + ); return this.getTracerProvider(); } @@ -65,12 +61,12 @@ export class TraceAPI { * Returns the global tracer provider. */ public getTracerProvider(): TracerProvider { - if (!(global as any)[GLOBAL_TRACE_API_KEY]) { + if (!_global[GLOBAL_TRACE_API_KEY]) { // global tracer provider has already been set return NOOP_TRACER_PROVIDER; } - return (global as any)[GLOBAL_TRACE_API_KEY](API_VERSION); + return _global[GLOBAL_TRACE_API_KEY]!(API_VERSION); } /** @@ -82,6 +78,6 @@ export class TraceAPI { /** Remove the global tracer provider */ public disable() { - delete (global as any)[GLOBAL_TRACE_API_KEY]; + delete _global[GLOBAL_TRACE_API_KEY]; } } 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); + }); +}); From a01c20a98da3fdea963bd286f918a7d86c127885 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Fri, 24 Apr 2020 15:23:34 -0400 Subject: [PATCH 5/7] chore: use a shared API backwards compatibility version --- packages/opentelemetry-api/src/api/context.ts | 16 +++++++------- .../opentelemetry-api/src/api/global-utils.ts | 17 +++++++++++++++ packages/opentelemetry-api/src/api/metrics.ts | 20 ++++++++++-------- .../opentelemetry-api/src/api/propagation.ts | 15 +++++++------ packages/opentelemetry-api/src/api/trace.ts | 21 ++++++++++--------- 5 files changed, 54 insertions(+), 35 deletions(-) diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 741677c3e0..b127917990 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -20,13 +20,13 @@ import { NoopContextManager, } 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(); -const API_VERSION = 0; /** * Singleton object which represents the entry point to the OpenTelemetry Context API @@ -54,11 +54,11 @@ export class ContextAPI { ): ContextManager { if (_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { // global context manager has already been set - return NOOP_CONTEXT_MANAGER; + return this._getContextManager(); } _global[GLOBAL_CONTEXT_MANAGER_API_KEY] = makeGetter( - API_VERSION, + API_BACKWARDS_COMPATIBILITY_VERSION, contextManager, NOOP_CONTEXT_MANAGER ); @@ -97,11 +97,11 @@ export class ContextAPI { } private _getContextManager(): ContextManager { - if (!_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { - return NOOP_CONTEXT_MANAGER; - } - - return _global[GLOBAL_CONTEXT_MANAGER_API_KEY]!(API_VERSION); + return ( + _global[GLOBAL_CONTEXT_MANAGER_API_KEY]?.( + API_BACKWARDS_COMPATIBILITY_VERSION + ) ?? NOOP_CONTEXT_MANAGER + ); } /** Disable and remove the global context manager */ diff --git a/packages/opentelemetry-api/src/api/global-utils.ts b/packages/opentelemetry-api/src/api/global-utils.ts index 79a77fd222..3114d1b6d0 100644 --- a/packages/opentelemetry-api/src/api/global-utils.ts +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -40,6 +40,14 @@ type MyGlobals = Partial<{ 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, @@ -48,3 +56,12 @@ export function makeGetter( 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 6677b9f9e4..60124d26c9 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -17,9 +17,12 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; -import { GLOBAL_METRICS_API_KEY, makeGetter, _global } from './global-utils'; - -const API_VERSION = 0; +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 @@ -49,7 +52,7 @@ export class MetricsAPI { } _global[GLOBAL_METRICS_API_KEY] = makeGetter( - API_VERSION, + API_BACKWARDS_COMPATIBILITY_VERSION, provider, NOOP_METER_PROVIDER ); @@ -61,11 +64,10 @@ export class MetricsAPI { * Returns the global meter provider. */ public getMeterProvider(): MeterProvider { - if (!_global[GLOBAL_METRICS_API_KEY]) { - return NOOP_METER_PROVIDER; - } - - return _global[GLOBAL_METRICS_API_KEY]!(API_VERSION); + return ( + _global[GLOBAL_METRICS_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_METER_PROVIDER + ); } /** diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index efef42441f..12acd1bc1a 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -21,6 +21,7 @@ import { NOOP_HTTP_TEXT_PROPAGATOR } from '../context/propagation/NoopHttpTextPr import { defaultSetter, SetterFunction } from '../context/propagation/setter'; import { ContextAPI } from './context'; import { + API_BACKWARDS_COMPATIBILITY_VERSION, GLOBAL_PROPAGATION_API_KEY, makeGetter, _global, @@ -28,8 +29,6 @@ import { const contextApi = ContextAPI.getInstance(); -const API_VERSION = 0; - /** * Singleton object which represents the entry point to the OpenTelemetry Propagation API */ @@ -60,7 +59,7 @@ export class PropagationAPI { } _global[GLOBAL_PROPAGATION_API_KEY] = makeGetter( - API_VERSION, + API_BACKWARDS_COMPATIBILITY_VERSION, propagator, NOOP_HTTP_TEXT_PROPAGATOR ); @@ -104,10 +103,10 @@ export class PropagationAPI { } private _getGlobalPropagator(): HttpTextPropagator { - if (!_global[GLOBAL_PROPAGATION_API_KEY]) { - return NOOP_HTTP_TEXT_PROPAGATOR; - } - - return _global[GLOBAL_PROPAGATION_API_KEY]!(API_VERSION); + 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 4353cfd1f2..346d60def8 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -17,9 +17,12 @@ import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider'; import { Tracer } from '../trace/tracer'; import { TracerProvider } from '../trace/tracer_provider'; -import { GLOBAL_TRACE_API_KEY, makeGetter, _global } from './global-utils'; - -const API_VERSION = 0; +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 @@ -49,7 +52,7 @@ export class TraceAPI { } _global[GLOBAL_TRACE_API_KEY] = makeGetter( - API_VERSION, + API_BACKWARDS_COMPATIBILITY_VERSION, provider, NOOP_TRACER_PROVIDER ); @@ -61,12 +64,10 @@ export class TraceAPI { * Returns the global tracer provider. */ public getTracerProvider(): TracerProvider { - if (!_global[GLOBAL_TRACE_API_KEY]) { - // global tracer provider has already been set - return NOOP_TRACER_PROVIDER; - } - - return _global[GLOBAL_TRACE_API_KEY]!(API_VERSION); + return ( + _global[GLOBAL_TRACE_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_TRACER_PROVIDER + ); } /** From 254d28ab9f8455045237a08c3624b14c63d9650d Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Fri, 24 Apr 2020 15:27:30 -0400 Subject: [PATCH 6/7] chore: return current api if already set --- packages/opentelemetry-api/src/api/metrics.ts | 2 +- packages/opentelemetry-api/src/api/propagation.ts | 2 +- packages/opentelemetry-api/src/api/trace.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 60124d26c9..dedf58be54 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -48,7 +48,7 @@ export class MetricsAPI { public setGlobalMeterProvider(provider: MeterProvider): MeterProvider { if (_global[GLOBAL_METRICS_API_KEY]) { // global meter provider has already been set - return NOOP_METER_PROVIDER; + return this.getMeterProvider(); } _global[GLOBAL_METRICS_API_KEY] = makeGetter( diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index 12acd1bc1a..a8af524244 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -55,7 +55,7 @@ export class PropagationAPI { ): HttpTextPropagator { if (_global[GLOBAL_PROPAGATION_API_KEY]) { // global propagator has already been set - return NOOP_HTTP_TEXT_PROPAGATOR; + return this._getGlobalPropagator(); } _global[GLOBAL_PROPAGATION_API_KEY] = makeGetter( diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 346d60def8..bae7353e08 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -48,7 +48,7 @@ export class TraceAPI { public setGlobalTracerProvider(provider: TracerProvider): TracerProvider { if (_global[GLOBAL_TRACE_API_KEY]) { // global tracer provider has already been set - return NOOP_TRACER_PROVIDER; + return this.getTracerProvider(); } _global[GLOBAL_TRACE_API_KEY] = makeGetter( From bb1495791c7edb18fb40a52b271aa66a4ad63d9c Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Fri, 24 Apr 2020 16:26:37 -0400 Subject: [PATCH 7/7] chore: add version compatibility explainer to api readme --- packages/opentelemetry-api/README.md | 4 ++++ 1 file changed, 4 insertions(+) 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