Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ const {
} = require("@opentelemetry/context-async-hooks");
const bodyParser = require("body-parser");

// set global propagator
propagation.setGlobalPropagator(new HttpTraceContext());

// set global context manager
context.setGlobalContextManager(new AsyncHooksContextManager());

// Create a provider for activating and tracking spans
const tracerProvider = new BasicTracerProvider();

// Register the tracer
tracerProvider.register();
tracerProvider.register({
propagator: new HttpTraceContext(),
contextManager: new AsyncHooksContextManager().enable(),
});

// Get a tracer
const tracer = trace.getTracer("w3c-tests");
Expand Down
4 changes: 3 additions & 1 deletion packages/opentelemetry-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@
"access": "public"
},
"dependencies": {
"@opentelemetry/context-base": "^0.14.0"
"@opentelemetry/context-base": "^0.14.0",
"semver": "^7.3.2"
},
"devDependencies": {
"@types/mocha": "8.2.0",
"@types/node": "14.14.12",
"@types/semver": "7.3.4",
"@types/sinon": "9.0.9",
"@types/webpack-env": "1.16.0",
"codecov": "3.8.1",
Expand Down
27 changes: 4 additions & 23 deletions packages/opentelemetry-api/src/api/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ import {
ContextManager,
NoopContextManager,
} from '@opentelemetry/context-base';
import {
API_BACKWARDS_COMPATIBILITY_VERSION,
GLOBAL_CONTEXT_MANAGER_API_KEY,
makeGetter,
_global,
} from './global-utils';
import { getGlobal, registerGlobal, unregisterGlobal } from './global-utils';

const NOOP_CONTEXT_MANAGER = new NoopContextManager();

Expand Down Expand Up @@ -52,17 +47,7 @@ export class ContextAPI {
public setGlobalContextManager(
contextManager: 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
);

registerGlobal('context', contextManager);
return contextManager;
}

Expand Down Expand Up @@ -97,16 +82,12 @@ export class ContextAPI {
}

private _getContextManager(): ContextManager {
return (
_global[GLOBAL_CONTEXT_MANAGER_API_KEY]?.(
API_BACKWARDS_COMPATIBILITY_VERSION
) ?? NOOP_CONTEXT_MANAGER
);
return getGlobal('context') || NOOP_CONTEXT_MANAGER;
}

/** Disable and remove the global context manager */
public disable() {
this._getContextManager().disable();
delete _global[GLOBAL_CONTEXT_MANAGER_API_KEY];
unregisterGlobal('context');
}
}
103 changes: 61 additions & 42 deletions packages/opentelemetry-api/src/api/global-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,54 +15,73 @@
*/

import { ContextManager } from '@opentelemetry/context-base';
import * as semver from 'semver';
import { TextMapPropagator } from '../context/propagation/TextMapPropagator';
import { MeterProvider } from '../metrics/MeterProvider';
import { TracerProvider } from '../trace/tracer_provider';
import { _globalThis } from '../platform';
import { TracerProvider } from '../trace/tracer_provider';
import { VERSION } from '../version';

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');
const GLOBAL_OPENTELEMETRY_API_KEY = Symbol.for('io.opentelemetry.js.api');

type Get<T> = (version: number) => T;
type OtelGlobal = Partial<{
[GLOBAL_CONTEXT_MANAGER_API_KEY]: Get<ContextManager>;
[GLOBAL_METRICS_API_KEY]: Get<MeterProvider>;
[GLOBAL_PROPAGATION_API_KEY]: Get<TextMapPropagator>;
[GLOBAL_TRACE_API_KEY]: Get<TracerProvider>;
}>;
const _global = _globalThis as OTelGlobal;
const acceptableRange = new semver.Range(`^${VERSION}`);

export const _global = _globalThis as OtelGlobal;
export function registerGlobal<Type extends keyof OTelGlobalAPI>(
type: Type,
instance: OTelGlobalAPI[Type]
): void {
_global[GLOBAL_OPENTELEMETRY_API_KEY] = _global[
GLOBAL_OPENTELEMETRY_API_KEY
] ?? {
version: VERSION,
};

/**
* 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<T>(
requiredVersion: number,
instance: T,
fallback: T
): Get<T> {
return (version: number): T =>
version === requiredVersion ? instance : fallback;
const api = _global[GLOBAL_OPENTELEMETRY_API_KEY]!;
if (api[type]) {
// already registered an API of this type
throw new Error(
`@opentelemetry/api: Attempted duplicate registration of API: ${type}`
);
}

if (api.version != VERSION) {
// All registered APIs must be of the same version exactly
throw new Error(
'@opentelemetry/api: All API registration versions must match'
);
}

api[type] = instance;
}

/**
* 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 = 3;
export function getGlobal<Type extends keyof OTelGlobalAPI>(
type: Type
): OTelGlobalAPI[Type] | undefined {
const version = _global[GLOBAL_OPENTELEMETRY_API_KEY]?.version;
if (!version || !semver.satisfies(version, acceptableRange)) {
return;
}
return _global[GLOBAL_OPENTELEMETRY_API_KEY]?.[type];
}

export function unregisterGlobal(type: keyof OTelGlobalAPI) {
const api = _global[GLOBAL_OPENTELEMETRY_API_KEY];

if (api) {
delete api[type];
}
}

type OTelGlobal = {
[GLOBAL_OPENTELEMETRY_API_KEY]?: OTelGlobalAPI;
};

type OTelGlobalAPI = {
version: string;

trace?: TracerProvider;
metrics?: MeterProvider;
context?: ContextManager;
propagation?: TextMapPropagator;
};
26 changes: 4 additions & 22 deletions packages/opentelemetry-api/src/api/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,7 @@
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';
import { getGlobal, registerGlobal, unregisterGlobal } from './global-utils';

/**
* Singleton object which represents the entry point to the OpenTelemetry Metrics API
Expand All @@ -46,28 +41,15 @@ export class MetricsAPI {
* Set the current global meter. Returns the initialized global meter provider.
*/
public setGlobalMeterProvider(provider: MeterProvider): MeterProvider {
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
);

registerGlobal('metrics', provider);
return provider;
}

/**
* Returns the global meter provider.
*/
public getMeterProvider(): MeterProvider {
return (
_global[GLOBAL_METRICS_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ??
NOOP_METER_PROVIDER
);
return getGlobal('metrics') || NOOP_METER_PROVIDER;
}

/**
Expand All @@ -79,6 +61,6 @@ export class MetricsAPI {

/** Remove the global meter provider */
public disable() {
delete _global[GLOBAL_METRICS_API_KEY];
unregisterGlobal('metrics');
}
}
27 changes: 4 additions & 23 deletions packages/opentelemetry-api/src/api/propagation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ import {
TextMapPropagator,
TextMapSetter,
} from '../context/propagation/TextMapPropagator';
import {
API_BACKWARDS_COMPATIBILITY_VERSION,
GLOBAL_PROPAGATION_API_KEY,
makeGetter,
_global,
} from './global-utils';
import { getGlobal, registerGlobal, unregisterGlobal } from './global-utils';

/**
* Singleton object which represents the entry point to the OpenTelemetry Propagation API
Expand All @@ -52,17 +47,7 @@ export class PropagationAPI {
* Set the current propagator. Returns the initialized propagator
*/
public setGlobalPropagator(propagator: TextMapPropagator): TextMapPropagator {
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_TEXT_MAP_PROPAGATOR
);

registerGlobal('propagation', propagator);
return propagator;
}

Expand Down Expand Up @@ -98,14 +83,10 @@ export class PropagationAPI {

/** Remove the global propagator */
public disable() {
delete _global[GLOBAL_PROPAGATION_API_KEY];
unregisterGlobal('propagation');
}

private _getGlobalPropagator(): TextMapPropagator {
return (
_global[GLOBAL_PROPAGATION_API_KEY]?.(
API_BACKWARDS_COMPATIBILITY_VERSION
) ?? NOOP_TEXT_MAP_PROPAGATOR
);
return getGlobal('propagation') || NOOP_TEXT_MAP_PROPAGATOR;
}
}
30 changes: 5 additions & 25 deletions packages/opentelemetry-api/src/api/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,11 @@
* limitations under the License.
*/

import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider';
import { ProxyTracerProvider } from '../trace/ProxyTracerProvider';
import { Tracer } from '../trace/tracer';
import { TracerProvider } from '../trace/tracer_provider';
import { isSpanContextValid } from '../trace/spancontext-utils';
import {
API_BACKWARDS_COMPATIBILITY_VERSION,
GLOBAL_TRACE_API_KEY,
makeGetter,
_global,
} from './global-utils';
import { getGlobal, registerGlobal, unregisterGlobal } from './global-utils';

/**
* Singleton object which represents the entry point to the OpenTelemetry Tracing API
Expand All @@ -50,30 +44,16 @@ export class TraceAPI {
* Set the current global tracer. Returns the initialized global tracer provider
*/
public setGlobalTracerProvider(provider: TracerProvider): TracerProvider {
if (_global[GLOBAL_TRACE_API_KEY]) {
// global tracer provider has already been set
return this.getTracerProvider();
}

this._proxyTracerProvider.setDelegate(provider);

_global[GLOBAL_TRACE_API_KEY] = makeGetter(
API_BACKWARDS_COMPATIBILITY_VERSION,
this._proxyTracerProvider,
NOOP_TRACER_PROVIDER
);

return this.getTracerProvider();
registerGlobal('trace', this._proxyTracerProvider);
return this._proxyTracerProvider;
}

/**
* Returns the global tracer provider.
*/
public getTracerProvider(): TracerProvider {
return (
_global[GLOBAL_TRACE_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ??
this._proxyTracerProvider
);
return getGlobal('trace') || this._proxyTracerProvider;
}

/**
Expand All @@ -85,7 +65,7 @@ export class TraceAPI {

/** Remove the global tracer provider */
public disable() {
delete _global[GLOBAL_TRACE_API_KEY];
unregisterGlobal('trace');
this._proxyTracerProvider = new ProxyTracerProvider();
}

Expand Down
Loading