diff --git a/README.md b/README.md index a5dda53e57..4f55cd5259 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,16 @@ To request automatic tracing support for a module not on this list, please [file |----------------------------------------------------------|-----------------------------------------------------------------------------------------| | [@opentelemetry/shim-opentracing][otel-shim-opentracing] | OpenTracing shim allows existing OpenTracing instrumentation to report to OpenTelemetry | +## Upgrade guidelines + +### 0.14.0 to 0.15.0 + +[PR-1764](https://github.com/open-telemetry/opentelemetry-js/pull/1764) removed some APIs from `Tracer`: + +- `Tracer.getCurrentSpan()`: use `api.getSpan(api.context.active())` +- `Tracer.withSpan(span)`: use `api.context.with(api.setSpan(api.context.active(), span))` +- `Tracer.bind(target)`: use `api.context.bind(target)` + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/examples/basic-tracer-node/index.js b/examples/basic-tracer-node/index.js index 45888437c2..fd046c0d45 100644 --- a/examples/basic-tracer-node/index.js +++ b/examples/basic-tracer-node/index.js @@ -37,9 +37,8 @@ exporter.shutdown(); function doWork(parent) { // Start another span. In this example, the main method already started a // span, so that'll be the parent span, and this will be a child span. - const span = tracer.startSpan('doWork', { - parent, - }); + const ctx = opentelemetry.setSpan(opentelemetry.context.active(), parent); + const span = tracer.startSpan('doWork', undefined, ctx); // simulate some random work. for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { diff --git a/examples/collector-exporter-node/tracing.js b/examples/collector-exporter-node/tracing.js index cb522c01ee..af9b617b04 100644 --- a/examples/collector-exporter-node/tracing.js +++ b/examples/collector-exporter-node/tracing.js @@ -39,9 +39,8 @@ setTimeout(() => { function doWork(parent) { // Start another span. In this example, the main method already started a // span, so that'll be the parent span, and this will be a child span. - const span = tracer.startSpan('doWork', { - parent, - }); + const ctx = opentelemetry.setSpan(opentelemetry.context.active(), parent); + const span = tracer.startSpan('doWork', undefined, ctx); // simulate some random work. for (let i = 0; i <= Math.floor(Math.random() * 40000000); i += 1) { diff --git a/examples/grpc-js/client.js b/examples/grpc-js/client.js index ee4090260e..958f29ef11 100644 --- a/examples/grpc-js/client.js +++ b/examples/grpc-js/client.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')('example-grpc-client'); // eslint-disable-next-line import/order const grpc = require('@grpc/grpc-js'); @@ -14,7 +15,7 @@ function main() { // the span, which is created to track work that happens outside of the // request lifecycle entirely. const span = tracer.startSpan('client.js:main()'); - tracer.withSpan(span, () => { + api.context.with(api.setSpan(api.context.active(), span), () => { console.log('Client traceId ', span.context().traceId); const client = new services.GreeterClient( `localhost:${PORT}`, diff --git a/examples/grpc-js/server.js b/examples/grpc-js/server.js index 1d71833ff1..6bd451b918 100644 --- a/examples/grpc-js/server.js +++ b/examples/grpc-js/server.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')(('example-grpc-server')); // eslint-disable-next-line import/order const grpc = require('@grpc/grpc-js'); @@ -21,11 +22,10 @@ function startServer() { } function sayHello(call, callback) { - const currentSpan = tracer.getCurrentSpan(); + const currentSpan = api.getSpan(api.context.active()); // display traceid in the terminal console.log(`traceid: ${currentSpan.context().traceId}`); const span = tracer.startSpan('server.js:sayHello()', { - parent: currentSpan, kind: 1, // server attributes: { key: 'value' }, }); diff --git a/examples/grpc/client.js b/examples/grpc/client.js index 5541113af7..5bb4b630aa 100644 --- a/examples/grpc/client.js +++ b/examples/grpc/client.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')('example-grpc-client'); // eslint-disable-next-line import/order const grpc = require('grpc'); @@ -14,7 +15,7 @@ function main() { // the span, which is created to track work that happens outside of the // request lifecycle entirely. const span = tracer.startSpan('client.js:main()'); - tracer.withSpan(span, () => { + api.context.with(api.setSpan(api.context.active(), span), () => { console.log('Client traceId ', span.context().traceId); const client = new services.GreeterClient( `localhost:${PORT}`, diff --git a/examples/grpc/server.js b/examples/grpc/server.js index 1b9d533172..40db771365 100644 --- a/examples/grpc/server.js +++ b/examples/grpc/server.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')(('example-grpc-server')); // eslint-disable-next-line import/order const grpc = require('grpc'); @@ -20,7 +21,7 @@ function startServer() { } function sayHello(call, callback) { - const currentSpan = tracer.getCurrentSpan(); + const currentSpan = api.getSpan(api.context.active()); // display traceid in the terminal console.log(`traceid: ${currentSpan.context().traceId}`); const span = tracer.startSpan('server.js:sayHello()', { diff --git a/examples/http/client.js b/examples/http/client.js index 5a88497f66..a27ba0355e 100644 --- a/examples/http/client.js +++ b/examples/http/client.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')('example-http-client'); // eslint-disable-next-line import/order const http = require('http'); @@ -10,7 +11,7 @@ function makeRequest() { // the span, which is created to track work that happens outside of the // request lifecycle entirely. const span = tracer.startSpan('makeRequest'); - tracer.withSpan(span, () => { + api.context.with(api.setSpan(api.context.active(), span), () => { http.get({ host: 'localhost', port: 8080, diff --git a/examples/http/server.js b/examples/http/server.js index d142badf83..d7a90310fb 100644 --- a/examples/http/server.js +++ b/examples/http/server.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')('example-http-server'); // eslint-disable-next-line import/order const http = require('http'); @@ -19,11 +20,10 @@ function startServer(port) { /** A function which handles requests and send response. */ function handleRequest(request, response) { - const currentSpan = tracer.getCurrentSpan(); + const currentSpan = api.getSpan(api.context.active()); // display traceid in the terminal console.log(`traceid: ${currentSpan.context().traceId}`); const span = tracer.startSpan('handleRequest', { - parent: currentSpan, kind: 1, // server attributes: { key: 'value' }, }); diff --git a/examples/https/client.js b/examples/https/client.js index e5b1825163..d842becef3 100644 --- a/examples/https/client.js +++ b/examples/https/client.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); const tracer = require('./tracer')('example-https-client'); // eslint-disable-next-line import/order const https = require('https'); @@ -10,7 +11,7 @@ function makeRequest() { // the span, which is created to track work that happens outside of the // request lifecycle entirely. const span = tracer.startSpan('makeRequest'); - tracer.withSpan(span, () => { + api.context.with(api.setSpan(api.context.active(), span), () => { https.get({ host: 'localhost', port: 443, diff --git a/examples/https/server.js b/examples/https/server.js index 105005fea8..a3d480f568 100644 --- a/examples/https/server.js +++ b/examples/https/server.js @@ -1,5 +1,6 @@ 'use strict'; +const api = require('@opentelemetry/api'); // eslint-disable-next-line import/order const tracer = require('./tracer')('example-https-server'); const fs = require('fs'); @@ -24,11 +25,10 @@ function startServer(port) { /** A function which handles requests and send response. */ function handleRequest(request, response) { - const currentSpan = tracer.getCurrentSpan(); + const currentSpan = api.getSpan(api.context.active()); // display traceid in the terminal console.log(`traceid: ${currentSpan.context().traceId}`); const span = tracer.startSpan('handleRequest', { - parent: currentSpan, kind: 1, // server attributes: { key: 'value' }, }); diff --git a/examples/tracer-web/examples/document-load/index.js b/examples/tracer-web/examples/document-load/index.js index fe72746a5e..148bbe6c64 100644 --- a/examples/tracer-web/examples/document-load/index.js +++ b/examples/tracer-web/examples/document-load/index.js @@ -1,3 +1,4 @@ +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; import { DocumentLoad } from '@opentelemetry/plugin-document-load'; @@ -52,31 +53,29 @@ const prepareClickEvent = () => { } const mainSpan = tracer.startSpan('click button'); - tracer.withSpan(mainSpan, () => { - const span1 = tracer.startSpan('files-series-info-1', { - parent: tracer.getCurrentSpan(), - }); + context.with(setSpan(context.active(), mainSpan), () => { + const span1 = tracer.startSpan('files-series-info-1'); - const span2 = tracer.startSpan('files-series-info-2', { - parent: tracer.getCurrentSpan(), - }); + const span2 = tracer.startSpan('files-series-info-2'); - tracer.withSpan(span1, () => { + context.with(setSpan(context.active(), span1), () => { getData(url1).then((data) => { - console.log('current span is span1', tracer.getCurrentSpan() === span1); + const curSpan = getSpan(context.active()); + console.log('current span is span1', curSpan === span1); console.log('info from package.json', data.description, data.version); - tracer.getCurrentSpan().addEvent('fetching-span1-completed'); + curSpan.addEvent('fetching-span1-completed'); span1.end(); finish(); }); }); - tracer.withSpan(span2, () => { + context.with(setSpan(context.active(), span2), () => { getData(url2).then((data) => { setTimeout(() => { - console.log('current span is span2', tracer.getCurrentSpan() === span2); + const curSpan = getSpan(context.active()); + console.log('current span is span2', curSpan === span2); console.log('info from package.json', data.description, data.version); - tracer.getCurrentSpan().addEvent('fetching-span2-completed'); + curSpan.addEvent('fetching-span2-completed'); span2.end(); finish(); }, 100); diff --git a/examples/tracer-web/examples/fetch/index.js b/examples/tracer-web/examples/fetch/index.js index 6717136bee..3ee96052b6 100644 --- a/examples/tracer-web/examples/fetch/index.js +++ b/examples/tracer-web/examples/fetch/index.js @@ -1,5 +1,6 @@ 'use strict'; +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { CollectorTraceExporter } from '@opentelemetry/exporter-collector'; import { WebTracerProvider } from '@opentelemetry/web'; @@ -44,22 +45,18 @@ const prepareClickEvent = () => { const element = document.getElementById('button1'); const onClick = () => { - const singleSpan = webTracerWithZone.startSpan(`files-series-info`, { - parent: webTracerWithZone.getCurrentSpan(), - }); - webTracerWithZone.withSpan(singleSpan, () => { + const singleSpan = webTracerWithZone.startSpan(`files-series-info`); + context.with(setSpan(context.active(), singleSpan), () => { getData(url).then((_data) => { - webTracerWithZone.getCurrentSpan().addEvent('fetching-single-span-completed'); + getSpan(context.active()).addEvent('fetching-single-span-completed'); singleSpan.end(); }); }); for (let i = 0, j = 5; i < j; i += 1) { - const span = webTracerWithZone.startSpan(`files-series-info-${i}`, { - parent: webTracerWithZone.getCurrentSpan(), - }); - webTracerWithZone.withSpan(span, () => { + const span = webTracerWithZone.startSpan(`files-series-info-${i}`); + context.with(setSpan(context.active(), span), () => { getData(url).then((_data) => { - webTracerWithZone.getCurrentSpan().addEvent(`fetching-span-${i}-completed`); + getSpan(context.active()).addEvent(`fetching-span-${i}-completed`); span.end(); }); }); diff --git a/examples/tracer-web/examples/xml-http-request/index.js b/examples/tracer-web/examples/xml-http-request/index.js index 2532037bc9..cc8a8a4839 100644 --- a/examples/tracer-web/examples/xml-http-request/index.js +++ b/examples/tracer-web/examples/xml-http-request/index.js @@ -1,3 +1,4 @@ +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; @@ -49,15 +50,13 @@ const prepareClickEvent = () => { const onClick = () => { for (let i = 0, j = 5; i < j; i += 1) { - const span1 = webTracerWithZone.startSpan(`files-series-info-${i}`, { - parent: webTracerWithZone.getCurrentSpan(), - }); - webTracerWithZone.withSpan(span1, () => { + const span1 = webTracerWithZone.startSpan(`files-series-info-${i}`); + context.with(setSpan(context.active(), span1), () => { getData(url1).then((_data) => { - webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); + getSpan(context.active()).addEvent('fetching-span1-completed'); span1.end(); }, ()=> { - webTracerWithZone.getCurrentSpan().addEvent('fetching-error'); + getSpan(context.active()).addEvent('fetching-error'); span1.end(); }); }); diff --git a/integration-tests/propagation-validation-server/validation-server.js b/integration-tests/propagation-validation-server/validation-server.js index 4818fb2761..badcddb769 100644 --- a/integration-tests/propagation-validation-server/validation-server.js +++ b/integration-tests/propagation-validation-server/validation-server.js @@ -1,7 +1,7 @@ const axios = require("axios"); const { HttpTraceContext } = require("@opentelemetry/core"); const { BasicTracerProvider } = require("@opentelemetry/tracing"); -const { context, propagation, trace, ROOT_CONTEXT } = require("@opentelemetry/api"); +const { context, propagation, setSpan, trace, ROOT_CONTEXT } = require("@opentelemetry/api"); const { AsyncHooksContextManager, } = require("@opentelemetry/context-async-hooks"); @@ -36,7 +36,7 @@ app.post("/verify-tracecontext", (req, res) => { req.body.map((action) => { const span = tracer.startSpan("propagate-w3c"); let promise; - tracer.withSpan(span, () => { + context.with(setSpan(context.active(), span), () => { const headers = {}; propagation.inject(context.active(), headers); promise = axios diff --git a/packages/opentelemetry-api/README.md b/packages/opentelemetry-api/README.md index 180ab4c7e2..0f91bb0bca 100644 --- a/packages/opentelemetry-api/README.md +++ b/packages/opentelemetry-api/README.md @@ -160,7 +160,7 @@ const api = require("@opentelemetry/api"); const tracer = api.trace.getTracer("my-library-name", "0.2.3"); async function doSomething() { - const span = tracer.startSpan("doSomething", { parent: tracer.getCurrentSpan() }); + const span = tracer.startSpan("doSomething"); try { const result = await doSomethingElse(); span.end(); diff --git a/packages/opentelemetry-api/src/api/global-utils.ts b/packages/opentelemetry-api/src/api/global-utils.ts index 297836e009..5d6ad7de3e 100644 --- a/packages/opentelemetry-api/src/api/global-utils.ts +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -65,4 +65,4 @@ export function makeGetter( * 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 = 2; +export const API_BACKWARDS_COMPATIBILITY_VERSION = 3; diff --git a/packages/opentelemetry-api/src/trace/NoopTracer.ts b/packages/opentelemetry-api/src/trace/NoopTracer.ts index 239db89b22..bb25bcbe1d 100644 --- a/packages/opentelemetry-api/src/trace/NoopTracer.ts +++ b/packages/opentelemetry-api/src/trace/NoopTracer.ts @@ -24,10 +24,6 @@ import { getSpanContext } from '../context/context'; * No-op implementations of {@link Tracer}. */ export class NoopTracer implements Tracer { - getCurrentSpan(): Span { - return NOOP_SPAN; - } - // startSpan starts a noop span. startSpan(name: string, options?: SpanOptions, context?: Context): Span { const root = Boolean(options?.root); @@ -46,17 +42,6 @@ export class NoopTracer implements Tracer { return NOOP_SPAN; } } - - withSpan ReturnType>( - span: Span, - fn: T - ): ReturnType { - return fn(); - } - - bind(target: T, _span?: Span): T { - return target; - } } function isSpanContext(spanContext: any): spanContext is SpanContext { diff --git a/packages/opentelemetry-api/src/trace/ProxyTracer.ts b/packages/opentelemetry-api/src/trace/ProxyTracer.ts index e2216eed5e..c6e22433e7 100644 --- a/packages/opentelemetry-api/src/trace/ProxyTracer.ts +++ b/packages/opentelemetry-api/src/trace/ProxyTracer.ts @@ -31,25 +31,10 @@ export class ProxyTracer implements Tracer { public readonly version?: string ) {} - getCurrentSpan(): Span | undefined { - return this._getTracer().getCurrentSpan(); - } - startSpan(name: string, options?: SpanOptions): Span { return this._getTracer().startSpan(name, options); } - withSpan ReturnType>( - span: Span, - fn: T - ): ReturnType { - return this._getTracer().withSpan(span, fn); - } - - bind(target: T, span?: Span): T { - return this._getTracer().bind(target, span); - } - /** * Try to get a tracer from the proxy tracer provider. * If the proxy tracer provider has no delegate, return a noop tracer. diff --git a/packages/opentelemetry-api/src/trace/tracer.ts b/packages/opentelemetry-api/src/trace/tracer.ts index 6ba051cfee..abc72a53f3 100644 --- a/packages/opentelemetry-api/src/trace/tracer.ts +++ b/packages/opentelemetry-api/src/trace/tracer.ts @@ -27,24 +27,9 @@ import { SpanOptions } from './SpanOptions'; */ export interface Tracer { /** - * Returns the current Span from the current context if available. + * Starts a new {@link Span}. Start the span without setting it on context. * - * If there is no Span associated with the current context, `undefined` is - * returned. - * - * To install a {@link Span} to the current Context use - * {@link Tracer.withSpan}. - * - * @returns Span The currently active Span - */ - getCurrentSpan(): Span | undefined; - - /** - * Starts a new {@link Span}. Start the span without setting it as the current - * span in this tracer's context. - * - * This method do NOT modify the current Context. To install a {@link - * Span} to the current Context use {@link Tracer.withSpan}. + * This method do NOT modify the current Context. * * @param name The name of the span * @param [options] SpanOptions used for span creation @@ -56,32 +41,4 @@ export interface Tracer { * span.end(); */ startSpan(name: string, options?: SpanOptions, context?: Context): Span; - - /** - * Executes the function given by fn within the context provided by Span. - * - * This is a convenience method for creating spans attached to the tracer's - * context. Applications that need more control over the span lifetime should - * use {@link Tracer.startSpan} instead. - * - * @param span The span that provides the context - * @param fn The function to be executed inside the provided context - * @example - * tracer.withSpan(span, () => { - * tracer.getCurrentSpan().addEvent("parent's event"); - * doSomeOtherWork(); // Here "span" is the current Span. - * }); - */ - withSpan ReturnType>( - span: Span, - fn: T - ): ReturnType; - - /** - * Bind a span as the target's context or propagate the current one. - * - * @param target Any object to which a context need to be set - * @param [context] Optionally specify the context which you want to bind - */ - bind(target: T, context?: Span): T; } diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index d2ca5daab5..01aaf32df6 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -36,8 +36,6 @@ import api, { } from '../../src'; describe('API', () => { - const functions = ['getCurrentSpan', 'startSpan', 'withSpan']; - it('should expose a tracer provider via getTracerProvider', () => { const tracer = api.trace.getTracerProvider(); assert.ok(tracer); @@ -59,20 +57,6 @@ describe('API', () => { metrics.disable(); }); - it('should not crash', () => { - functions.forEach(fn => { - const tracer = api.trace.getTracerProvider(); - try { - ((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function - assert.ok(true, fn); - } catch (err) { - if (err.message !== 'Method not implemented.') { - assert.ok(true, fn); - } - } - }); - }); - it('should use the global tracer provider', () => { api.trace.setGlobalTracerProvider(new TestTracerProvider()); const tracer = api.trace.getTracerProvider().getTracer('name'); diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts index 232428e48d..3730968323 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts @@ -40,24 +40,6 @@ describe('NoopTracer', () => { }), NOOP_SPAN ); - - assert.deepStrictEqual(tracer.getCurrentSpan(), NOOP_SPAN); - }); - - it('should not crash when .withSpan()', done => { - const tracer = new NoopTracer(); - tracer.withSpan(NOOP_SPAN, () => { - return done(); - }); - }); - - it('should not crash when .bind()', done => { - const tracer = new NoopTracer(); - const fn = () => { - return done(); - }; - const patchedFn = tracer.bind(fn, NOOP_SPAN); - return patchedFn(); }); it('should propagate valid spanContext on the span (from context)', () => { diff --git a/packages/opentelemetry-api/test/proxy-implementations/proxy-tracer.test.ts b/packages/opentelemetry-api/test/proxy-implementations/proxy-tracer.test.ts index 7a110cbfa3..41db382f3d 100644 --- a/packages/opentelemetry-api/test/proxy-implementations/proxy-tracer.test.ts +++ b/packages/opentelemetry-api/test/proxy-implementations/proxy-tracer.test.ts @@ -56,8 +56,6 @@ describe('ProxyTracer', () => { }), NOOP_SPAN ); - - assert.deepStrictEqual(tracer.getCurrentSpan(), NOOP_SPAN); }); }); @@ -96,18 +94,9 @@ describe('ProxyTracer', () => { beforeEach(() => { delegateSpan = new NoopSpan(); delegateTracer = { - bind(target) { - return target; - }, - getCurrentSpan() { - return delegateSpan; - }, startSpan() { return delegateSpan; }, - withSpan(span, fn) { - return fn(); - }, }; tracer = provider.getTracer('test'); diff --git a/packages/opentelemetry-context-zone-peer-dep/README.md b/packages/opentelemetry-context-zone-peer-dep/README.md index 15edbcb0dd..421fa937a2 100644 --- a/packages/opentelemetry-context-zone-peer-dep/README.md +++ b/packages/opentelemetry-context-zone-peer-dep/README.md @@ -22,6 +22,7 @@ npm install --save @opentelemetry/context-zone-peer-dep ## Usage ```js +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; import { ZoneContextManager } from '@opentelemetry/context-zone-peer-dep'; @@ -35,21 +36,21 @@ providerWithZone.register({ // Example how the ZoneContextManager keeps the reference to the correct context during async operations const webTracerWithZone = providerWithZone.getTracer('default'); const span1 = webTracerWithZone.startSpan('foo1'); -webTracerWithZone.withSpan(span1, () => { - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); +context.with(setSpan(context.active(), span1, () => { + console.log('Current span is span1', getSpan(context.active()) === span1); setTimeout(() => { const span2 = webTracerWithZone.startSpan('foo2'); - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); - webTracerWithZone.withSpan(span2, () => { - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span1', getSpan(context.active()) === span1); + context.with(setSpan(context.active(), span2, () => { + console.log('Current span is span2', getSpan(context.active()) === span2); setTimeout(() => { - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span2', getSpan(context.active()) === span2); }, 500); }); // there is a timeout which still keeps span2 active - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span2', getSpan(context.active()) === span2); }, 500); - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); + console.log('Current span is span1', getSpan(context.active()) === span1); }); ``` diff --git a/packages/opentelemetry-context-zone/README.md b/packages/opentelemetry-context-zone/README.md index 4e26999004..e2c3ae72e1 100644 --- a/packages/opentelemetry-context-zone/README.md +++ b/packages/opentelemetry-context-zone/README.md @@ -19,6 +19,7 @@ npm install --save @opentelemetry/context-zone ## Usage ```js +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; import { ZoneContextManager } from '@opentelemetry/context-zone'; @@ -32,21 +33,22 @@ provider.register({ // Example how the ZoneContextManager keeps the reference to the correct context during async operations const webTracerWithZone = providerWithZone.getTracer('default'); const span1 = webTracerWithZone.startSpan('foo1'); -webTracerWithZone.withSpan(span1, () => { - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); + +context.with(setSpan(context.active(), span1), () => { + console.log('Current span is span1', getSpan(context.active()) === span1); setTimeout(() => { const span2 = webTracerWithZone.startSpan('foo2'); - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); - webTracerWithZone.withSpan(span2, () => { - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span1', getSpan(context.active()) === span1); + context.with(setSpan(context.active(), span2), () => { + console.log('Current span is span2', getSpan(context.active()) === span2); setTimeout(() => { - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span2', getSpan(context.active()) === span2); }, 500); }); // there is a timeout which still keeps span2 active - console.log('Current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('Current span is span2', getSpan(context.active()) === span2); }, 500); - console.log('Current span is span1', webTracerWithZone.getCurrentSpan() === span1); + console.log('Current span is span1', getSpan(context.active()) === span1); }); ``` diff --git a/packages/opentelemetry-grpc-utils/test/grpcUtils.test.ts b/packages/opentelemetry-grpc-utils/test/grpcUtils.test.ts index c2f877455a..ffb857088d 100644 --- a/packages/opentelemetry-grpc-utils/test/grpcUtils.test.ts +++ b/packages/opentelemetry-grpc-utils/test/grpcUtils.test.ts @@ -19,6 +19,8 @@ import { NoopTracerProvider, SpanKind, propagation, + getSpan, + setSpan, } from '@opentelemetry/api'; import { NoopLogger, @@ -527,8 +529,8 @@ export const runTests = ( const span = provider .getTracer('default') .startSpan('TestSpan', { kind: SpanKind.PRODUCER }); - return provider.getTracer('default').withSpan(span, async () => { - const rootSpan = provider.getTracer('default').getCurrentSpan(); + return context.with(setSpan(context.active(), span), async () => { + const rootSpan = getSpan(context.active()); if (!rootSpan) { return assert.ok(false); } @@ -623,8 +625,8 @@ export const runTests = ( const span = provider .getTracer('default') .startSpan('TestSpan', { kind: SpanKind.PRODUCER }); - return provider.getTracer('default').withSpan(span, async () => { - const rootSpan = provider.getTracer('default').getCurrentSpan(); + return context.with(setSpan(context.active(), span), async () => { + const rootSpan = getSpan(context.active()); if (!rootSpan) { return assert.ok(false); } diff --git a/packages/opentelemetry-instrumentation-http/src/http.ts b/packages/opentelemetry-instrumentation-http/src/http.ts index ffc037b26f..7e97214387 100644 --- a/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/packages/opentelemetry-instrumentation-http/src/http.ts @@ -25,6 +25,7 @@ import { SpanContext, TraceFlags, ROOT_CONTEXT, + getSpan, } from '@opentelemetry/api'; import { NoRecordingSpan } from '@opentelemetry/core'; import type * as http from 'http'; @@ -304,7 +305,7 @@ export class HttpInstrumentation extends InstrumentationBase { this._callResponseHook(span, response); } - this.tracer.bind(response); + context.bind(response); this._logger.debug('outgoingRequest on response()'); response.on('end', () => { this._logger.debug('outgoingRequest on end()'); @@ -410,7 +411,7 @@ export class HttpInstrumentation extends InstrumentationBase { spanOptions ); - return instrumentation.tracer.withSpan(span, () => { + return context.with(setSpan(context.active(), span), () => { context.bind(request); context.bind(response); @@ -559,7 +560,7 @@ export class HttpInstrumentation extends InstrumentationBase { '%s instrumentation outgoingRequest', component ); - instrumentation.tracer.bind(request); + context.bind(request); return instrumentation._traceClientRequest( component, request, @@ -580,7 +581,7 @@ export class HttpInstrumentation extends InstrumentationBase { : this._getConfig().requireParentforIncomingSpans; let span: Span; - const currentSpan = this.tracer.getCurrentSpan(); + const currentSpan = getSpan(context.active()); if (requireParent === true && currentSpan === undefined) { // TODO: Refactor this when a solution is found in diff --git a/packages/opentelemetry-instrumentation-http/test/functionals/http-disable.test.ts b/packages/opentelemetry-instrumentation-http/test/functionals/http-disable.test.ts index 7a962a56e3..babf8502c1 100644 --- a/packages/opentelemetry-instrumentation-http/test/functionals/http-disable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/functionals/http-disable.test.ts @@ -55,7 +55,6 @@ describe('HttpInstrumentation', () => { beforeEach(() => { NOOP_TRACER.startSpan = sinon.spy(); - NOOP_TRACER.withSpan = sinon.spy(); }); afterEach(() => { @@ -79,11 +78,6 @@ describe('HttpInstrumentation', () => { (NOOP_TRACER.startSpan as sinon.SinonSpy).called, false ); - - assert.strictEqual( - (NOOP_TRACER.withSpan as sinon.SinonSpy).called, - false - ); }); }); }); diff --git a/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts index 38f0a2a8b6..95627f134c 100644 --- a/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts @@ -20,6 +20,7 @@ import { Span as ISpan, SpanKind, getSpan, + setSpan, } from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; @@ -321,7 +322,7 @@ describe('HttpInstrumentation', () => { doNock(hostname, testPath, 200, 'Ok'); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - return provider.getTracer('default').withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -364,7 +365,7 @@ describe('HttpInstrumentation', () => { ); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - return provider.getTracer('default').withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -403,7 +404,7 @@ describe('HttpInstrumentation', () => { doNock(hostname, testPath, 200, 'Ok', num); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - await provider.getTracer('default').withSpan(span, async () => { + await context.with(setSpan(context.active(), span), async () => { for (let i = 0; i < num; i++) { await httpRequest.get(`${protocol}://${hostname}${testPath}`); const spans = memoryExporter.getFinishedSpans(); @@ -794,7 +795,7 @@ describe('HttpInstrumentation', () => { const span = tracer.startSpan('parentSpan', { kind: SpanKind.INTERNAL, }); - tracer.withSpan(span, () => { + context.with(setSpan(context.active(), span), () => { httpRequest .get(`${protocol}://${hostname}:${serverPort}${testPath}`) .then(result => { diff --git a/packages/opentelemetry-instrumentation-http/test/functionals/https-disable.test.ts b/packages/opentelemetry-instrumentation-http/test/functionals/https-disable.test.ts index f0eb60b38f..c498701b29 100644 --- a/packages/opentelemetry-instrumentation-http/test/functionals/https-disable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/functionals/https-disable.test.ts @@ -64,7 +64,6 @@ describe('HttpsInstrumentation', () => { beforeEach(() => { NOOP_TRACER.startSpan = sinon.spy(); - NOOP_TRACER.withSpan = sinon.spy(); }); afterEach(() => { @@ -88,10 +87,6 @@ describe('HttpsInstrumentation', () => { ); assert.strictEqual(isWrapped(https.Server.prototype.emit), false); - assert.strictEqual( - (NOOP_TRACER.withSpan as sinon.SinonSpy).called, - false - ); }); }); }); diff --git a/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts b/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts index e8a7a18655..9c4ba49fd2 100644 --- a/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts @@ -20,6 +20,7 @@ import { propagation, Span as ISpan, SpanKind, + setSpan, } from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; @@ -308,7 +309,7 @@ describe('HttpsInstrumentation', () => { doNock(hostname, testPath, 200, 'Ok'); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpsRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -351,7 +352,7 @@ describe('HttpsInstrumentation', () => { ); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpsRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -390,7 +391,7 @@ describe('HttpsInstrumentation', () => { doNock(hostname, testPath, 200, 'Ok', num); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - await tracer.withSpan(span, async () => { + await context.with(setSpan(context.active(), span), async () => { for (let i = 0; i < num; i++) { await httpsRequest.get(`${protocol}://${hostname}${testPath}`); const spans = memoryExporter.getFinishedSpans(); diff --git a/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts b/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts index 1e5fe3e1fd..b3f96e7f43 100644 --- a/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts @@ -125,7 +125,7 @@ export class XMLHttpRequestInstrumentation extends InstrumentationBase { + api.context.with(api.setSpan(api.context.active(), span), () => { const childSpan = this.tracer.startSpan('CORS Preflight', { startTime: corsPreFlightRequest[PTN.FETCH_START], }); @@ -437,25 +437,28 @@ export class XMLHttpRequestInstrumentation extends InstrumentationBase { - plugin._tasksCount++; - xhrMem.sendStartTime = hrTime(); - currentSpan.addEvent(EventNames.METHOD_SEND); - - this.addEventListener('abort', onAbort); - this.addEventListener('error', onError); - this.addEventListener('load', onLoad); - this.addEventListener('timeout', onTimeout); - - xhrMem.callbackToRemoveEvents = () => { - unregister(this); - if (xhrMem.createdResources) { - xhrMem.createdResources.observer.disconnect(); - } - }; - plugin._addHeaders(this, spanUrl); - plugin._addResourceObserver(this, spanUrl); - }); + api.context.with( + api.setSpan(api.context.active(), currentSpan), + () => { + plugin._tasksCount++; + xhrMem.sendStartTime = hrTime(); + currentSpan.addEvent(EventNames.METHOD_SEND); + + this.addEventListener('abort', onAbort); + this.addEventListener('error', onError); + this.addEventListener('load', onLoad); + this.addEventListener('timeout', onTimeout); + + xhrMem.callbackToRemoveEvents = () => { + unregister(this); + if (xhrMem.createdResources) { + xhrMem.createdResources.observer.disconnect(); + } + }; + plugin._addHeaders(this, spanUrl); + plugin._addResourceObserver(this, spanUrl); + } + ); } return original.apply(this, args); }; diff --git a/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts index cc3c4875cf..f5acb4ebf8 100644 --- a/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts @@ -213,7 +213,7 @@ describe('xhr', () => { ); rootSpan = webTracerWithZone.startSpan('root'); - webTracerWithZone.withSpan(rootSpan, () => { + api.context.with(api.setSpan(api.context.active(), rootSpan), () => { getData( new XMLHttpRequest(), fileUrl, @@ -626,46 +626,52 @@ describe('xhr', () => { }) ); const reusableReq = new XMLHttpRequest(); - webTracerWithZone.withSpan(rootSpan, () => { - getData( - reusableReq, - firstUrl, - () => { - fakeNow = 100; - }, - testAsync - ).then(() => { - fakeNow = 0; - sandbox.clock.tick(1000); - }); - }); - - webTracerWithZone.withSpan(rootSpan, () => { - getData( - reusableReq, - secondUrl, - () => { - fakeNow = 100; - }, - testAsync - ).then(() => { - fakeNow = 0; - sandbox.clock.tick(1000); - done(); - }); - - assert.strictEqual( - requests.length, - 1, - 'first request not called' - ); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData( + reusableReq, + firstUrl, + () => { + fakeNow = 100; + }, + testAsync + ).then(() => { + fakeNow = 0; + sandbox.clock.tick(1000); + }); + } + ); - requests[0].respond( - 200, - { 'Content-Type': 'application/json' }, - '{"foo":"bar"}' - ); - }); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData( + reusableReq, + secondUrl, + () => { + fakeNow = 100; + }, + testAsync + ).then(() => { + fakeNow = 0; + sandbox.clock.tick(1000); + done(); + }); + + assert.strictEqual( + requests.length, + 1, + 'first request not called' + ); + + requests[0].respond( + 200, + { 'Content-Type': 'application/json' }, + '{"foo":"bar"}' + ); + } + ); }); it('should clear previous span information', () => { @@ -738,26 +744,29 @@ describe('xhr', () => { describe('when request loads and receives an error code', () => { beforeEach(done => { - webTracerWithZone.withSpan(rootSpan, () => { - getData( - new XMLHttpRequest(), - url, - () => { - fakeNow = 100; - }, - testAsync - ).then(() => { - fakeNow = 0; - sandbox.clock.tick(1000); - done(); - }); - assert.strictEqual(requests.length, 1, 'request not called'); - requests[0].respond( - 400, - { 'Content-Type': 'text/plain' }, - 'Bad Request' - ); - }); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData( + new XMLHttpRequest(), + url, + () => { + fakeNow = 100; + }, + testAsync + ).then(() => { + fakeNow = 0; + sandbox.clock.tick(1000); + done(); + }); + assert.strictEqual(requests.length, 1, 'request not called'); + requests[0].respond( + 400, + { 'Content-Type': 'text/plain' }, + 'Bad Request' + ); + } + ); }); it('span should have correct attributes', () => { const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; @@ -872,18 +881,21 @@ describe('xhr', () => { describe('when request encounters a network error', () => { beforeEach(done => { - webTracerWithZone.withSpan(rootSpan, () => { - getData(new XMLHttpRequest(), url, () => {}, testAsync).then( - () => { - fakeNow = 0; - sandbox.clock.tick(1000); - done(); - } - ); - - assert.strictEqual(requests.length, 1, 'request not called'); - requests[0].error(); - }); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData(new XMLHttpRequest(), url, () => {}, testAsync).then( + () => { + fakeNow = 0; + sandbox.clock.tick(1000); + done(); + } + ); + + assert.strictEqual(requests.length, 1, 'request not called'); + requests[0].error(); + } + ); }); it('span should have correct attributes', () => { @@ -961,18 +973,21 @@ describe('xhr', () => { }); beforeEach(done => { - webTracerWithZone.withSpan(rootSpan, () => { - getData(new XMLHttpRequest(), url, () => {}, testAsync).then( - () => { - fakeNow = 0; - sandbox.clock.tick(1000); - done(); - } - ); - - assert.strictEqual(requests.length, 1, 'request not called'); - requests[0].abort(); - }); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData(new XMLHttpRequest(), url, () => {}, testAsync).then( + () => { + fakeNow = 0; + sandbox.clock.tick(1000); + done(); + } + ); + + assert.strictEqual(requests.length, 1, 'request not called'); + requests[0].abort(); + } + ); }); it('span should have correct attributes', () => { @@ -1050,20 +1065,23 @@ describe('xhr', () => { }); beforeEach(done => { - webTracerWithZone.withSpan(rootSpan, () => { - getData( - new XMLHttpRequest(), - url, - () => { - sandbox.clock.tick(XHR_TIMEOUT); - }, - testAsync - ).then(() => { - fakeNow = 0; - sandbox.clock.tick(1000); - done(); - }); - }); + api.context.with( + api.setSpan(api.context.active(), rootSpan), + () => { + getData( + new XMLHttpRequest(), + url, + () => { + sandbox.clock.tick(XHR_TIMEOUT); + }, + testAsync + ).then(() => { + fakeNow = 0; + sandbox.clock.tick(1000); + done(); + }); + } + ); }); it('span should have correct attributes', () => { diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index c5de5a4a68..185c5d1613 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -19,6 +19,7 @@ import { TraceFlags, setSpan, setSpanContext, + getSpan, } from '@opentelemetry/api'; import { AlwaysOnSampler, @@ -203,49 +204,27 @@ describe('NodeTracerProvider', () => { }); }); - describe('.getCurrentSpan()', () => { - it('should return undefined with AsyncHooksContextManager when no span started', () => { - provider = new NodeTracerProvider({}); - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - undefined - ); - }); - }); - describe('.withSpan()', () => { it('should run context with AsyncHooksContextManager context manager', done => { provider = new NodeTracerProvider({}); const span = provider.getTracer('default').startSpan('my-span'); - provider.getTracer('default').withSpan(span, () => { - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - span - ); + context.with(setSpan(context.active(), span), () => { + assert.deepStrictEqual(getSpan(context.active()), span); return done(); }); - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - undefined - ); + assert.deepStrictEqual(getSpan(context.active()), undefined); }); it('should run context with AsyncHooksContextManager context manager with multiple spans', done => { provider = new NodeTracerProvider({}); const span = provider.getTracer('default').startSpan('my-span'); - provider.getTracer('default').withSpan(span, () => { - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - span - ); + context.with(setSpan(context.active(), span), () => { + assert.deepStrictEqual(getSpan(context.active()), span); const span1 = provider.getTracer('default').startSpan('my-span1'); - provider.getTracer('default').withSpan(span1, () => { - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - span1 - ); + context.with(setSpan(context.active(), span1), () => { + assert.deepStrictEqual(getSpan(context.active()), span1); assert.deepStrictEqual( span1.context().traceId, span.context().traceId @@ -255,29 +234,20 @@ describe('NodeTracerProvider', () => { }); // when span ended. // @todo: below check is not running. - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - undefined - ); + assert.deepStrictEqual(getSpan(context.active()), undefined); }); it('should find correct context with promises', async () => { provider = new NodeTracerProvider(); const span = provider.getTracer('default').startSpan('my-span'); - await provider.getTracer('default').withSpan(span, async () => { + await context.with(setSpan(context.active(), span), async () => { for (let i = 0; i < 3; i++) { await sleep(5).then(() => { - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - span - ); + assert.deepStrictEqual(getSpan(context.active()), span); }); } }); - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - undefined - ); + assert.deepStrictEqual(getSpan(context.active()), undefined); }); }); @@ -286,10 +256,7 @@ describe('NodeTracerProvider', () => { const provider = new NodeTracerProvider({}); const span = provider.getTracer('default').startSpan('my-span'); const fn = () => { - assert.deepStrictEqual( - provider.getTracer('default').getCurrentSpan(), - span - ); + assert.deepStrictEqual(getSpan(context.active()), span); return done(); }; const patchedFn = context.bind(fn, setSpan(context.active(), span)); diff --git a/packages/opentelemetry-plugin-fetch/src/fetch.ts b/packages/opentelemetry-plugin-fetch/src/fetch.ts index d366c9a356..419a80cb40 100644 --- a/packages/opentelemetry-plugin-fetch/src/fetch.ts +++ b/packages/opentelemetry-plugin-fetch/src/fetch.ts @@ -299,16 +299,19 @@ export class FetchPlugin extends core.BasePlugin> { } return new Promise((resolve, reject) => { - return plugin._tracer.withSpan(span, () => { - plugin._addHeaders(options, url); - plugin._tasksCount++; - return original - .apply(this, [url, options]) - .then( - onSuccess.bind(this, span, resolve), - onError.bind(this, span, reject) - ); - }); + return api.context.with( + api.setSpan(api.context.active(), span), + () => { + plugin._addHeaders(options, url); + plugin._tasksCount++; + return original + .apply(this, [url, options]) + .then( + onSuccess.bind(this, span, resolve), + onError.bind(this, span, reject) + ); + } + ); }); }; }; diff --git a/packages/opentelemetry-plugin-fetch/test/fetch.test.ts b/packages/opentelemetry-plugin-fetch/test/fetch.test.ts index 647537f6c3..80c3000b1f 100644 --- a/packages/opentelemetry-plugin-fetch/test/fetch.test.ts +++ b/packages/opentelemetry-plugin-fetch/test/fetch.test.ts @@ -178,7 +178,7 @@ describe('fetch', () => { ); rootSpan = webTracerWithZone.startSpan('root'); - webTracerWithZone.withSpan(rootSpan, () => { + api.context.with(api.setSpan(api.context.active(), rootSpan), () => { fakeNow = 0; getData(fileUrl, method).then( response => { diff --git a/packages/opentelemetry-plugin-grpc-js/src/client/utils.ts b/packages/opentelemetry-plugin-grpc-js/src/client/utils.ts index 9332f7ad76..70632b6ac8 100644 --- a/packages/opentelemetry-plugin-grpc-js/src/client/utils.ts +++ b/packages/opentelemetry-plugin-grpc-js/src/client/utils.ts @@ -23,6 +23,7 @@ import { Status, propagation, context, + setSpan, } from '@opentelemetry/api'; import { RpcAttribute } from '@opentelemetry/semantic-conventions'; import type * as grpcJs from '@grpc/grpc-js'; @@ -80,8 +81,8 @@ export function getPatchedClientMethods( const span = plugin.tracer.startSpan(name, { kind: SpanKind.CLIENT, }); - return plugin.tracer.withSpan(span, () => - makeGrpcClientRemoteCall(original, args, metadata, this, plugin)(span) + return context.with(setSpan(context.active(), span), () => + makeGrpcClientRemoteCall(original, args, metadata, this)(span) ); }; }; @@ -95,8 +96,7 @@ export function makeGrpcClientRemoteCall( original: GrpcClientFunc, args: unknown[], metadata: grpcJs.Metadata, - self: grpcJs.Client, - plugin: GrpcJsPlugin + self: grpcJs.Client ): (span: Span) => EventEmitter { /** * Patches a callback so that the current span for this trace is also ended @@ -130,7 +130,7 @@ export function makeGrpcClientRemoteCall( span.end(); callback(err, res); }; - return plugin.tracer.bind(wrappedFn); + return context.bind(wrappedFn); } return (span: Span) => { @@ -166,7 +166,7 @@ export function makeGrpcClientRemoteCall( spanEnded = true; } }; - plugin.tracer.bind(call); + context.bind(call); call.on('error', (err: grpcJs.ServiceError) => { if (call[CALL_SPAN_ENDED]) { return; diff --git a/packages/opentelemetry-plugin-grpc-js/src/server/clientStreamAndUnary.ts b/packages/opentelemetry-plugin-grpc-js/src/server/clientStreamAndUnary.ts index 2e92334cb0..bef98b2590 100644 --- a/packages/opentelemetry-plugin-grpc-js/src/server/clientStreamAndUnary.ts +++ b/packages/opentelemetry-plugin-grpc-js/src/server/clientStreamAndUnary.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Span, StatusCode } from '@opentelemetry/api'; +import { context, Span, StatusCode } from '@opentelemetry/api'; import type { ServerCallWithMeta, SendUnaryDataCallback } from '../types'; import { grpcStatusCodeToOpenTelemetryStatusCode } from '../utils'; import { RpcAttribute } from '@opentelemetry/semantic-conventions'; @@ -61,6 +61,6 @@ export function clientStreamAndUnaryHandler( return callback(err, value); }; - plugin.tracer.bind(call); + context.bind(call); return (original as Function).call({}, call, patchedCallback); } diff --git a/packages/opentelemetry-plugin-grpc-js/src/server/patchServer.ts b/packages/opentelemetry-plugin-grpc-js/src/server/patchServer.ts index e9e8ed6f29..efad948e9c 100644 --- a/packages/opentelemetry-plugin-grpc-js/src/server/patchServer.ts +++ b/packages/opentelemetry-plugin-grpc-js/src/server/patchServer.ts @@ -30,6 +30,7 @@ import { propagation, Span, ROOT_CONTEXT, + setSpan, } from '@opentelemetry/api'; import { RpcAttribute } from '@opentelemetry/semantic-conventions'; import { clientStreamAndUnaryHandler } from './clientStreamAndUnary'; @@ -113,7 +114,7 @@ export function patchServer( [RpcAttribute.GRPC_KIND]: spanOptions.kind, }); - plugin.tracer.withSpan(span, () => { + context.with(setSpan(context.active(), span), () => { handleServerFunction.call( self, plugin, diff --git a/packages/opentelemetry-plugin-grpc-js/src/server/serverStreamAndBidi.ts b/packages/opentelemetry-plugin-grpc-js/src/server/serverStreamAndBidi.ts index 138d98e9c9..311097996e 100644 --- a/packages/opentelemetry-plugin-grpc-js/src/server/serverStreamAndBidi.ts +++ b/packages/opentelemetry-plugin-grpc-js/src/server/serverStreamAndBidi.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Span, StatusCode } from '@opentelemetry/api'; +import { context, Span, StatusCode } from '@opentelemetry/api'; import { RpcAttribute } from '@opentelemetry/semantic-conventions'; import type * as grpcJs from '@grpc/grpc-js'; import type { GrpcJsPlugin } from '../grpcJs'; @@ -43,7 +43,7 @@ export function serverStreamAndBidiHandler( } }; - plugin.tracer.bind(call); + context.bind(call); call.on('finish', () => { // @grpc/js does not expose a way to check if this call also emitted an error, // e.g. call.status.code !== 0 diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index f27492438e..a53941c9d9 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -23,6 +23,7 @@ import { SpanOptions, Status, ROOT_CONTEXT, + setSpan, } from '@opentelemetry/api'; import { RpcAttribute } from '@opentelemetry/semantic-conventions'; import { BasePlugin } from '@opentelemetry/core'; @@ -194,7 +195,7 @@ export class GrpcPlugin extends BasePlugin { [RpcAttribute.GRPC_KIND]: spanOptions.kind, }); - plugin._tracer.withSpan(span, () => { + context.with(setSpan(context.active(), span), () => { switch (type) { case 'unary': case 'client_stream': @@ -286,7 +287,7 @@ export class GrpcPlugin extends BasePlugin { return callback(err, value, trailer, flags); } - plugin._tracer.bind(call); + context.bind(call); return (original as Function).call(self, call, patchedCallback); } @@ -305,7 +306,7 @@ export class GrpcPlugin extends BasePlugin { } }; - plugin._tracer.bind(call); + context.bind(call); call.on('finish', () => { span.setStatus(_grpcStatusCodeToSpanStatus(call.status.code)); span.setAttribute( @@ -392,7 +393,7 @@ export class GrpcPlugin extends BasePlugin { const span = plugin._tracer.startSpan(name, { kind: SpanKind.CLIENT, }); - return plugin._tracer.withSpan(span, () => + return context.with(setSpan(context.active(), span), () => plugin._makeGrpcClientRemoteCall( original, args, @@ -448,7 +449,7 @@ export class GrpcPlugin extends BasePlugin { span.end(); callback(err, res); }; - return plugin._tracer.bind(wrappedFn); + return context.bind(wrappedFn); } return (span: Span) => { @@ -490,7 +491,7 @@ export class GrpcPlugin extends BasePlugin { spanEnded = true; } }; - plugin._tracer.bind(call); + context.bind(call); ((call as unknown) as events.EventEmitter).on( 'error', (err: grpcTypes.ServiceError) => { diff --git a/packages/opentelemetry-plugin-http/src/http.ts b/packages/opentelemetry-plugin-http/src/http.ts index a88ce6e348..c4eecfb3b1 100644 --- a/packages/opentelemetry-plugin-http/src/http.ts +++ b/packages/opentelemetry-plugin-http/src/http.ts @@ -25,6 +25,7 @@ import { TraceFlags, setSpan, ROOT_CONTEXT, + getSpan, } from '@opentelemetry/api'; import { BasePlugin, NoRecordingSpan } from '@opentelemetry/core'; import type { @@ -214,7 +215,7 @@ export class HttpPlugin extends BasePlugin { this._callResponseHook(span, response); } - this._tracer.bind(response); + context.bind(response); this._logger.debug('outgoingRequest on response()'); response.on('end', () => { this._logger.debug('outgoingRequest on end()'); @@ -310,7 +311,7 @@ export class HttpPlugin extends BasePlugin { return context.with(propagation.extract(ROOT_CONTEXT, headers), () => { const span = plugin._startHttpSpan(`HTTP ${method}`, spanOptions); - return plugin._tracer.withSpan(span, () => { + return context.with(setSpan(context.active(), span), () => { context.bind(request); context.bind(response); @@ -426,7 +427,7 @@ export class HttpPlugin extends BasePlugin { ); plugin._logger.debug('%s plugin outgoingRequest', plugin.moduleName); - plugin._tracer.bind(request); + context.bind(request); return plugin._traceClientRequest(request, optionsParsed, span); }; } @@ -442,7 +443,7 @@ export class HttpPlugin extends BasePlugin { : this._config.requireParentforIncomingSpans; let span: Span; - const currentSpan = this._tracer.getCurrentSpan(); + const currentSpan = getSpan(context.active()); if (requireParent === true && currentSpan === undefined) { // TODO: Refactor this when a solution is found in diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts index 3b80fe84ba..3322b472f6 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts @@ -49,7 +49,6 @@ describe('HttpPlugin', () => { beforeEach(() => { NOOP_TRACER.startSpan = sinon.spy(); - NOOP_TRACER.withSpan = sinon.spy(); }); afterEach(() => { @@ -73,10 +72,6 @@ describe('HttpPlugin', () => { ); assert.strictEqual(http.Server.prototype.emit.__wrapped, undefined); - assert.strictEqual( - (NOOP_TRACER.withSpan as sinon.SinonSpy).called, - false - ); }); }); }); 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 52ed5a4bc3..bbfcbefa88 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -20,6 +20,7 @@ import { Span as ISpan, SpanKind, getSpan, + setSpan, } from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; @@ -338,7 +339,7 @@ describe('HttpPlugin', () => { doNock(hostname, testPath, 200, 'Ok'); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - return provider.getTracer('default').withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -381,7 +382,7 @@ describe('HttpPlugin', () => { ); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - return provider.getTracer('default').withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -420,7 +421,7 @@ describe('HttpPlugin', () => { doNock(hostname, testPath, 200, 'Ok', num); const name = 'TestRootSpan'; const span = provider.getTracer('default').startSpan(name); - await provider.getTracer('default').withSpan(span, async () => { + await context.with(setSpan(context.active(), span), async () => { for (let i = 0; i < num; i++) { await httpRequest.get(`${protocol}://${hostname}${testPath}`); const spans = memoryExporter.getFinishedSpans(); @@ -810,7 +811,7 @@ describe('HttpPlugin', () => { const span = tracer.startSpan('parentSpan', { kind: SpanKind.INTERNAL, }); - tracer.withSpan(span, () => { + context.with(setSpan(context.active(), span), () => { httpRequest .get(`${protocol}://${hostname}:${serverPort}${testPath}`) .then(result => { diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts index 9d0e8dece6..82b5f21c89 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts @@ -64,7 +64,6 @@ describe('HttpsPlugin', () => { beforeEach(() => { tracer.startSpan = sinon.spy(); - tracer.withSpan = sinon.spy(); }); afterEach(() => { @@ -88,7 +87,6 @@ describe('HttpsPlugin', () => { ); assert.strictEqual(https.Server.prototype.emit.__wrapped, undefined); - assert.strictEqual((tracer.withSpan as sinon.SinonSpy).called, false); }); }); }); 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 10cc3aeb53..cc9f66d2fe 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -20,6 +20,7 @@ import { propagation, Span as ISpan, SpanKind, + setSpan, } from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; @@ -335,7 +336,7 @@ describe('HttpsPlugin', () => { doNock(hostname, testPath, 200, 'Ok'); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpsRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -378,7 +379,7 @@ describe('HttpsPlugin', () => { ); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + return context.with(setSpan(context.active(), span), async () => { const result = await httpsRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -417,7 +418,7 @@ describe('HttpsPlugin', () => { doNock(hostname, testPath, 200, 'Ok', num); const name = 'TestRootSpan'; const span = tracer.startSpan(name); - await tracer.withSpan(span, async () => { + await context.with(setSpan(context.active(), span), async () => { for (let i = 0; i < num; i++) { await httpsRequest.get(`${protocol}://${hostname}${testPath}`); const spans = memoryExporter.getFinishedSpans(); diff --git a/packages/opentelemetry-tracing/src/Tracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts index 9cf15e1d3a..fefdb00dfd 100644 --- a/packages/opentelemetry-tracing/src/Tracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -122,38 +122,6 @@ export class Tracer implements api.Tracer { return span; } - /** - * Returns the current Span from the current context. - * - * If there is no Span associated with the current context, undefined is returned. - */ - getCurrentSpan(): api.Span | undefined { - const ctx = api.context.active(); - // Get the current Span from the context or null if none found. - return api.getSpan(ctx); - } - - /** - * Enters the context of code where the given Span is in the current context. - */ - withSpan ReturnType>( - span: api.Span, - fn: T - ): ReturnType { - // Set given span to context. - return api.context.with(api.setSpan(api.context.active(), span), fn); - } - - /** - * Bind a span (or the current one) to the target's context - */ - bind(target: T, span?: api.Span): T { - return api.context.bind( - target, - span ? api.setSpan(api.context.active(), span) : api.context.active() - ); - } - /** Returns the active {@link TraceParams}. */ getActiveTraceParams(): TraceParams { return this._traceParams; diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index 71086c2ddd..ccce863e18 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -18,10 +18,10 @@ import { context, SpanContext, TraceFlags, - ContextManager, ROOT_CONTEXT, setSpan, setSpanContext, + getSpan, } from '@opentelemetry/api'; import { AlwaysOnSampler, @@ -291,24 +291,12 @@ describe('BasicTracerProvider', () => { }); }); - describe('.getCurrentSpan()', () => { - it('should return current span when it exists', () => { - context.setGlobalContextManager({ - active: () => setSpan(ROOT_CONTEXT, ('foo' as any) as Span), - disable: () => {}, - } as ContextManager); - - const tracer = new BasicTracerProvider().getTracer('default'); - assert.deepStrictEqual(tracer.getCurrentSpan(), 'foo'); - }); - }); - describe('.withSpan()', () => { it('should run context with NoopContextManager context manager', done => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span'); - tracer.withSpan(span, () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + context.with(setSpan(context.active(), span), () => { + assert.deepStrictEqual(getSpan(context.active()), undefined); return done(); }); }); @@ -319,10 +307,10 @@ describe('BasicTracerProvider', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span'); const fn = () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + assert.deepStrictEqual(getSpan(context.active()), undefined); return done(); }; - const patchedFn = tracer.bind(fn, span); + const patchedFn = context.bind(fn, setSpan(context.active(), span)); return patchedFn(); }); }); diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index 281f901fc5..65c918193c 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { context } from '@opentelemetry/api'; +import { context, getSpan, setSpan } from '@opentelemetry/api'; import { ContextManager } from '@opentelemetry/context-base'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import { BasePlugin, NoopLogger } from '@opentelemetry/core'; @@ -133,9 +133,9 @@ describe('WebTracerProvider', () => { const rootSpan = webTracerWithZone.startSpan('rootSpan'); - webTracerWithZone.withSpan(rootSpan, () => { + context.with(setSpan(context.active(), rootSpan), () => { assert.ok( - webTracerWithZone.getCurrentSpan() === rootSpan, + getSpan(context.active()) === rootSpan, 'Current span is rootSpan' ); const concurrentSpan1 = webTracerWithZone.startSpan( @@ -145,19 +145,19 @@ describe('WebTracerProvider', () => { 'concurrentSpan2' ); - webTracerWithZone.withSpan(concurrentSpan1, () => { + context.with(setSpan(context.active(), concurrentSpan1), () => { setTimeout(() => { assert.ok( - webTracerWithZone.getCurrentSpan() === concurrentSpan1, + getSpan(context.active()) === concurrentSpan1, 'Current span is concurrentSpan1' ); }, 10); }); - webTracerWithZone.withSpan(concurrentSpan2, () => { + context.with(setSpan(context.active(), concurrentSpan2), () => { setTimeout(() => { assert.ok( - webTracerWithZone.getCurrentSpan() === concurrentSpan2, + getSpan(context.active()) === concurrentSpan2, 'Current span is concurrentSpan2' ); done();