diff --git a/CHANGELOG.md b/CHANGELOG.md index 6efc8342cd2..2454fe6f55c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -120,6 +120,10 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se * (user-facing): `ENVIRONMENT` has been removed without replacement * (user-facing): `RAW_ENVIRONMENT` has been removed without replacement * (user-facing): `parseEnvironment` has been removed without replacement +* feat(sdk-trace-base): remove `BasicTracerProvider#register()` to improve tree-shaking [#5503](https://github.com/open-telemetry/opentelemetry-js/pull/5503) @pichlermarc + * (user-facing): `BasicTracerProvider#register()` has been removed + * to register a global propagator, please use `propagation.setGlobalPropagator()` from `@opentelemetry/api` + * to register a global context manager, please use `context.setGlobalContextManager()` from `@opentelemetry/api` * feat!: set compilation target to ES2022 for all packages except `@opentelemetry/api`, `@opentelemetry/api-logs`, `@opentelemetry/api-events`, and `@opentelemetry/semantic-conventions` [#5456](https://github.com/open-telemetry/opentelemetry-js/pull/5456) @david-luna * (user-facing): drops browser runtimes which do not support ES2022 features diff --git a/examples/basic-tracer-node/index.js b/examples/basic-tracer-node/index.js index b23651137ce..d9fe7aaf105 100644 --- a/examples/basic-tracer-node/index.js +++ b/examples/basic-tracer-node/index.js @@ -5,20 +5,13 @@ const { resourceFromAttributes } = require('@opentelemetry/resources'); const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-conventions'); const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); +const { AsyncLocalStorageContextManager } = require("@opentelemetry/context-async-hooks"); +const {CompositePropagator, W3CTraceContextPropagator, W3CBaggagePropagator} = require("@opentelemetry/core"); // Configure span processor to send spans to the exporter const exporter = new JaegerExporter({ endpoint: 'http://localhost:14268/api/traces', }); -const provider = new BasicTracerProvider({ - resource: resourceFromAttributes({ - [SEMRESATTRS_SERVICE_NAME]: 'basic-service', - }), - spanProcessors: [ - new SimpleSpanProcessor(exporter), - new SimpleSpanProcessor(new ConsoleSpanExporter()), - ] -}); /** * Initialize the OpenTelemetry APIs to use the BasicTracerProvider bindings. @@ -29,7 +22,21 @@ const provider = new BasicTracerProvider({ * do not register a global tracer provider, instrumentation which calls these * methods will receive no-op implementations. */ -provider.register(); +opentelemetry.trace.setGlobalTracerProvider(new BasicTracerProvider({ + resource: resourceFromAttributes({ + [SEMRESATTRS_SERVICE_NAME]: 'basic-service', + }), + spanProcessors: [ + new SimpleSpanProcessor(exporter), + new SimpleSpanProcessor(new ConsoleSpanExporter()), + ] +})); +opentelemetry.context.setGlobalContextManager(new AsyncLocalStorageContextManager()); +opentelemetry.propagation.setGlobalPropagator(new CompositePropagator({ propagators: [ + new W3CTraceContextPropagator(), + new W3CBaggagePropagator()] +})); + const tracer = opentelemetry.trace.getTracer('example-basic-tracer-node'); // Create a span. A span must be closed. diff --git a/experimental/packages/exporter-trace-otlp-grpc/README.md b/experimental/packages/exporter-trace-otlp-grpc/README.md index a18a7a787bf..240295aa054 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/README.md +++ b/experimental/packages/exporter-trace-otlp-grpc/README.md @@ -24,7 +24,7 @@ To see documentation and sample code for the metric exporter, see the [exporter- The OTLPTraceExporter in Node expects the URL to only be the hostname. It will not work with `/v1/traces`. ```js -const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { NodeTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); const collectorOptions = { @@ -34,7 +34,7 @@ const collectorOptions = { }; const exporter = new OTLPTraceExporter(collectorOptions); -const provider = new BasicTracerProvider({ +const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); @@ -50,7 +50,7 @@ By default, plaintext connection is used. In order to use TLS in Node.js, provid const fs = require('fs'); const grpc = require('@grpc/grpc-js'); -const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { NodeTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); const collectorOptions = { @@ -61,7 +61,7 @@ const collectorOptions = { }; const exporter = new OTLPTraceExporter(collectorOptions); -const provider = new BasicTracerProvider({ +const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); @@ -88,7 +88,7 @@ The exporter can be configured to send custom metadata with each request as in t ```js const grpc = require('@grpc/grpc-js'); -const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { NodeTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc'); const metadata = new grpc.Metadata(); @@ -103,7 +103,7 @@ const collectorOptions = { }; const exporter = new OTLPTraceExporter(collectorOptions); -const provider = new BasicTracerProvider({ +const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); diff --git a/experimental/packages/exporter-trace-otlp-http/README.md b/experimental/packages/exporter-trace-otlp-http/README.md index 427792eff5a..10f71e5811e 100644 --- a/experimental/packages/exporter-trace-otlp-http/README.md +++ b/experimental/packages/exporter-trace-otlp-http/README.md @@ -59,7 +59,7 @@ provider.register(); ## Traces in Node - JSON over http ```js -const { BasicTracerProvider, BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { NodeTracerProvider, BatchSpanProcessor } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); const collectorOptions = { @@ -71,7 +71,7 @@ const collectorOptions = { }; const exporter = new OTLPTraceExporter(collectorOptions); -const provider = new BasicTracerProvider({ +const provider = new NodeTracerProvider({ spanProcessors: [ new BatchSpanProcessor(exporter, { // The maximum queue size. After the size is reached spans are dropped. diff --git a/experimental/packages/exporter-trace-otlp-proto/README.md b/experimental/packages/exporter-trace-otlp-proto/README.md index 984fbaa4603..c72b18c993c 100644 --- a/experimental/packages/exporter-trace-otlp-proto/README.md +++ b/experimental/packages/exporter-trace-otlp-proto/README.md @@ -22,7 +22,7 @@ To see documentation and sample code for the metric exporter, see the [exporter- ## Traces in Node - PROTO over http ```js -const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); +const { NodeTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-node'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-proto'); const collectorOptions = { @@ -33,7 +33,7 @@ const collectorOptions = { }; const exporter = new OTLPTraceExporter(collectorOptions); -const provider = new BasicTracerProvider({ +const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] }); diff --git a/integration-tests/propagation-validation-server/validation-server.js b/integration-tests/propagation-validation-server/validation-server.js index 40c1f4ff3f9..7027cb33a23 100644 --- a/integration-tests/propagation-validation-server/validation-server.js +++ b/integration-tests/propagation-validation-server/validation-server.js @@ -13,11 +13,8 @@ propagation.setGlobalPropagator(new W3CTraceContextPropagator()); // 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(); +// set global tracer provider +trace.setGlobalTracerProvider(new BasicTracerProvider()); // Get a tracer const tracer = trace.getTracer("w3c-tests"); diff --git a/packages/opentelemetry-sdk-trace-base/README.md b/packages/opentelemetry-sdk-trace-base/README.md index 6d7b6558943..7146a8529d6 100644 --- a/packages/opentelemetry-sdk-trace-base/README.md +++ b/packages/opentelemetry-sdk-trace-base/README.md @@ -7,11 +7,14 @@ The `tracing` module contains the foundation for all tracing SDKs of [openteleme Used standalone, this module provides methods for manual instrumentation of code, offering full control over span creation for client-side JavaScript (browser) and Node.js. -It does **not** provide automated instrumentation of known libraries, context propagation for asynchronous invocations or distributed-context out-of-the-box. +It does **not** provide automated instrumentation of known libraries, context propagation or distributed-context out-of-the-box. -For automated instrumentation for Node.js, please see +For a `TracerProvider` that includes default context management and propagation for Node.js, please see [@opentelemetry/sdk-trace-node](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node). +For a `TracerProvider` that includes default context management and propagation for Browser, please see +[@opentelemetry/sdk-trace-web](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-web). + ## Installation ```bash @@ -22,16 +25,20 @@ npm install --save @opentelemetry/sdk-trace-base ## Usage ```js -const opentelemetry = require('@opentelemetry/api'); +const { trace } = require('@opentelemetry/api'); const { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base'); // To start a trace, you first need to initialize the Tracer provider. // NOTE: The default OpenTelemetry tracer provider does not record any tracing information. // Registering a working tracer provider allows the API methods to record traces. -new BasicTracerProvider().register(); +trace.setGlobalTracerProvider(new BasicTracerProvider()); + +// Important: requires a context manager and propagator to be registered manually. +// propagation.setGlobalPropagator(propagator); // replace `propagator` with your `TextMapPropagator`, for example: `W3CTraceContextPropagator` from `@openetelemetry/core` +// context.setGlobalContextManager(contextManager); // replace `contextManager` with your `ContextManager`: `AsyncLocalStorageContextManager` from `@openetelemetry/async-hooks` // To create a span in a trace, we used the global singleton tracer to start a new span. -const span = opentelemetry.trace.getTracer('default').startSpan('foo'); +const span = trace.getTracer('default').startSpan('foo'); // Set a span attribute span.setAttribute('key', 'value'); diff --git a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts index db3186c123b..50a445e389a 100644 --- a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts @@ -14,26 +14,14 @@ * limitations under the License. */ -import { - context, - propagation, - TextMapPropagator, - trace, - TracerProvider, - Tracer as ApiTracer, -} from '@opentelemetry/api'; -import { - CompositePropagator, - W3CBaggagePropagator, - W3CTraceContextPropagator, - merge, -} from '@opentelemetry/core'; +import { TracerProvider, Tracer as ApiTracer } from '@opentelemetry/api'; +import { merge } from '@opentelemetry/core'; import { defaultResource, Resource } from '@opentelemetry/resources'; import { SpanProcessor } from './SpanProcessor'; import { Tracer } from './Tracer'; import { loadDefaultConfig } from './config'; import { MultiSpanProcessor } from './MultiSpanProcessor'; -import { SDKRegistrationConfig, TracerConfig } from './types'; +import { TracerConfig } from './types'; import { reconfigureLimits } from './utility'; export enum ForceFlushState { @@ -43,10 +31,6 @@ export enum ForceFlushState { 'unresolved', } -function getDefaultPropagators(): TextMapPropagator[] { - return [new W3CTraceContextPropagator(), new W3CBaggagePropagator()]; -} - /** * This class represents a basic tracer provider which platform libraries can extend */ @@ -99,31 +83,6 @@ export class BasicTracerProvider implements TracerProvider { return this._tracers.get(key)!; } - /** - * Register this TracerProvider for use with the OpenTelemetry API. - * Undefined values may be replaced with defaults, and - * null values will be skipped. - * - * @param config Configuration object for SDK registration - */ - register(config: SDKRegistrationConfig = {}): void { - trace.setGlobalTracerProvider(this); - - if (config.contextManager) { - context.setGlobalContextManager(config.contextManager); - } - - // undefined means "unset", null means don't register propagator - if (config.propagator !== null) { - propagation.setGlobalPropagator( - config.propagator ?? - new CompositePropagator({ - propagators: getDefaultPropagators(), - }) - ); - } - } - forceFlush(): Promise { const timeout = this._config.forceFlushTimeoutMillis; const promises = this._activeSpanProcessor['_spanProcessors'].map( diff --git a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts index 696aac0a954..6a3e86efe99 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts @@ -20,15 +20,8 @@ import { SpanContext, TraceFlags, ROOT_CONTEXT, - TextMapPropagator, - TextMapSetter, - Context, - TextMapGetter, - propagation, diag, - ContextManager, } from '@opentelemetry/api'; -import { CompositePropagator } from '@opentelemetry/core'; import { TraceState } from '@opentelemetry/core'; import { defaultResource, @@ -49,28 +42,8 @@ import { SpanImpl } from '../../src/Span'; import { MultiSpanProcessor } from '../../src/MultiSpanProcessor'; import { Tracer } from '../../src/Tracer'; -class DummyPropagator implements TextMapPropagator { - inject(context: Context, carrier: any, setter: TextMapSetter): void { - throw new Error('Method not implemented.'); - } - extract(context: Context, carrier: any, getter: TextMapGetter): Context { - throw new Error('Method not implemented.'); - } - fields(): string[] { - throw new Error('Method not implemented.'); - } -} - describe('BasicTracerProvider', () => { - let setGlobalPropagatorStub: sinon.SinonSpy<[TextMapPropagator], boolean>; - let setGlobalContextManagerStub: sinon.SinonSpy<[ContextManager], boolean>; - beforeEach(() => { - // to avoid actually registering the TraceProvider and leaking env to other tests - sinon.stub(trace, 'setGlobalTracerProvider'); - setGlobalPropagatorStub = sinon.spy(propagation, 'setGlobalPropagator'); - setGlobalContextManagerStub = sinon.spy(context, 'setGlobalContextManager'); - context.disable(); }); @@ -312,65 +285,6 @@ describe('BasicTracerProvider', () => { }); }); - describe('.register()', () => { - describe('propagator', () => { - it('should be set to a given value if it it provided', () => { - const provider = new BasicTracerProvider(); - provider.register({ - propagator: new DummyPropagator(), - }); - - sinon.assert.calledOnceWithExactly( - setGlobalPropagatorStub, - sinon.match.instanceOf(DummyPropagator) - ); - }); - - it('should use w3c trace context and baggage propagators by default', () => { - const provider = new BasicTracerProvider(); - provider.register(); - - sinon.assert.calledOnceWithExactly( - setGlobalPropagatorStub, - sinon.match.instanceOf(CompositePropagator) - ); - assert.deepStrictEqual(setGlobalPropagatorStub.args[0][0].fields(), [ - 'traceparent', - 'tracestate', - 'baggage', - ]); - }); - }); - describe('contextManager', () => { - it('should not be set if not provided', () => { - const provider = new BasicTracerProvider(); - provider.register(); - - sinon.assert.notCalled(setGlobalContextManagerStub); - }); - - it('should be set if provided', () => { - const provider = new BasicTracerProvider(); - const mockContextManager: ContextManager = { - active: sinon.stub(), - bind: sinon.stub(), - disable: sinon.stub(), - enable: sinon.stub(), - with: sinon.stub(), - }; - - provider.register({ - contextManager: mockContextManager, - }); - - sinon.assert.calledOnceWithExactly( - setGlobalContextManagerStub, - mockContextManager - ); - }); - }); - }); - describe('.startSpan()', () => { it('should start a span with name only', () => { const tracer = new BasicTracerProvider().getTracer('default'); diff --git a/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts b/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts index ee6c67dbbbc..cfee572cb94 100644 --- a/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts @@ -19,6 +19,60 @@ import { SDKRegistrationConfig, } from '@opentelemetry/sdk-trace-base'; import { NodeTracerConfig } from './config'; +import { + context, + ContextManager, + propagation, + TextMapPropagator, + trace, +} from '@opentelemetry/api'; +import { + CompositePropagator, + W3CBaggagePropagator, + W3CTraceContextPropagator, +} from '@opentelemetry/core'; + +function setupContextManager( + contextManager: ContextManager | null | undefined +) { + // null means 'do not register' + if (contextManager === null) { + return; + } + + // undefined means 'register default' + if (contextManager === undefined) { + const defaultContextManager = new AsyncLocalStorageContextManager(); + defaultContextManager.enable(); + context.setGlobalContextManager(defaultContextManager); + return; + } + + contextManager.enable(); + context.setGlobalContextManager(contextManager); +} + +function setupPropagator(propagator: TextMapPropagator | null | undefined) { + // null means 'do not register' + if (propagator === null) { + return; + } + + // undefined means 'register default' + if (propagator === undefined) { + propagation.setGlobalPropagator( + new CompositePropagator({ + propagators: [ + new W3CTraceContextPropagator(), + new W3CBaggagePropagator(), + ], + }) + ); + return; + } + + propagation.setGlobalPropagator(propagator); +} /** * Register this TracerProvider for use with the OpenTelemetry API. @@ -32,12 +86,16 @@ export class NodeTracerProvider extends BasicTracerProvider { super(config); } - override register(config: SDKRegistrationConfig = {}): void { - if (config.contextManager === undefined) { - config.contextManager = new AsyncLocalStorageContextManager(); - config.contextManager.enable(); - } - - super.register(config); + /** + * Register this TracerProvider for use with the OpenTelemetry API. + * Undefined values may be replaced with defaults, and + * null values will be skipped. + * + * @param config Configuration object for SDK registration + */ + register(config: SDKRegistrationConfig = {}): void { + trace.setGlobalTracerProvider(this); + setupContextManager(config.contextManager); + setupPropagator(config.propagator); } } diff --git a/packages/opentelemetry-sdk-trace-node/test/registration.test.ts b/packages/opentelemetry-sdk-trace-node/test/registration.test.ts index 0a185b60763..bd87577dad8 100644 --- a/packages/opentelemetry-sdk-trace-node/test/registration.test.ts +++ b/packages/opentelemetry-sdk-trace-node/test/registration.test.ts @@ -64,7 +64,10 @@ describe('API registration', () => { it('should register configured implementations', () => { const tracerProvider = new NodeTracerProvider(); - const mockContextManager = { disable() {} } as any; + const mockContextManager = { + enable() {}, + disable() {}, + } as any; const mockPropagator = {} as any; tracerProvider.register({ diff --git a/packages/opentelemetry-sdk-trace-web/src/WebTracerProvider.ts b/packages/opentelemetry-sdk-trace-web/src/WebTracerProvider.ts index 17df6d3addb..479c4c887ec 100644 --- a/packages/opentelemetry-sdk-trace-web/src/WebTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-web/src/WebTracerProvider.ts @@ -20,6 +20,60 @@ import { TracerConfig, } from '@opentelemetry/sdk-trace-base'; import { StackContextManager } from './StackContextManager'; +import { + trace, + context, + ContextManager, + propagation, + TextMapPropagator, +} from '@opentelemetry/api'; +import { + CompositePropagator, + W3CBaggagePropagator, + W3CTraceContextPropagator, +} from '@opentelemetry/core'; + +function setupContextManager( + contextManager: ContextManager | null | undefined +) { + // null means 'do not register' + if (contextManager === null) { + return; + } + + // undefined means 'register default' + if (contextManager === undefined) { + const defaultContextManager = new StackContextManager(); + defaultContextManager.enable(); + context.setGlobalContextManager(defaultContextManager); + return; + } + + contextManager.enable(); + context.setGlobalContextManager(contextManager); +} + +function setupPropagator(propagator: TextMapPropagator | null | undefined) { + // null means 'do not register' + if (propagator === null) { + return; + } + + // undefined means 'register default' + if (propagator === undefined) { + propagation.setGlobalPropagator( + new CompositePropagator({ + propagators: [ + new W3CTraceContextPropagator(), + new W3CBaggagePropagator(), + ], + }) + ); + return; + } + + propagation.setGlobalPropagator(propagator); +} /** * WebTracerConfig provides an interface for configuring a Web Tracer. @@ -45,14 +99,9 @@ export class WebTracerProvider extends BasicTracerProvider { * * @param config Configuration object for SDK registration */ - override register(config: SDKRegistrationConfig = {}): void { - if (config.contextManager === undefined) { - config.contextManager = new StackContextManager(); - } - if (config.contextManager) { - config.contextManager.enable(); - } - - super.register(config); + register(config: SDKRegistrationConfig = {}): void { + trace.setGlobalTracerProvider(this); + setupPropagator(config.propagator); + setupContextManager(config.contextManager); } }