diff --git a/.github/ISSUE_TEMPLATE/request_for_instrumentation.md b/.github/ISSUE_TEMPLATE/request_for_instrumentation.md index 3bea3c9ed4..ae2218269f 100644 --- a/.github/ISSUE_TEMPLATE/request_for_instrumentation.md +++ b/.github/ISSUE_TEMPLATE/request_for_instrumentation.md @@ -5,9 +5,9 @@ labels: instrumentation --- ### Is it applicable for Node or Browser or both diff --git a/README.md b/README.md index 919f265d4f..ab9fb6f511 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ Approvers ([@open-telemetry/js-approvers](https://github.com/orgs/open-telemetry - [Naseem K. Ullah](https://github.com/naseemkullah), Transit - [Olivier Albertini](https://github.com/OlivierAlbertini), Ville de Montréal -*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver).* +*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).* Maintainers ([@open-telemetry/js-maintainers](https://github.com/orgs/open-telemetry/teams/javascript-maintainers)): @@ -143,7 +143,7 @@ Maintainers ([@open-telemetry/js-maintainers](https://github.com/orgs/open-telem - [Daniel Dyla](https://github.com/dyladan), Dynatrace - [Valentin Marchaud](https://github.com/vmarchaud), Open Source Contributor -*Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#maintainer).* +*Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#maintainer).* ### Thanks to all the people who already contributed @@ -182,18 +182,17 @@ OpenTelemetry is vendor-agnostic and can upload data to any backend with various See the [OpenTelemetry registry](https://opentelemetry.io/registry/?s=node.js) for a list of exporters available. -### Plugins +### Instrumentations & Plugins -OpenTelemetry can collect tracing data automatically using plugins. Vendors/Users can also create and use their own. Currently, OpenTelemetry supports automatic tracing for: +OpenTelemetry can collect tracing data automatically using instrumentations. Vendors/Users can also create and use their own. Currently, OpenTelemetry supports automatic tracing for: -#### Node Plugins +#### Node Instrumentations & Plugins ##### Core -- [@opentelemetry/plugin-grpc][otel-plugin-grpc] +- [@opentelemetry/instrumentation-grpc][otel-instrumentation-grpc] previous [@opentelemetry/plugin-grpc][otel-plugin-grpc] - [@opentelemetry/plugin-grpc-js][otel-plugin-grpc-js] -- [@opentelemetry/plugin-http][otel-plugin-http] -- [@opentelemetry/plugin-https][otel-plugin-https] +- [@opentelemetry/instrumentation-http][otel-plugin-http] previous [@opentelemetry/plugin-http][otel-plugin-http] and [@opentelemetry/plugin-https][otel-plugin-https] ##### Contrib @@ -215,7 +214,7 @@ These plugins are hosted at { - const provider = new NodeTracerProvider({ - plugins: { - '@grpc/grpc-js': { - enabled: true, - path: '@opentelemetry/plugin-grpc-js', + const provider = new NodeTracerProvider(); + registerInstrumentations({ + instrumentations: [ + { + plugins: { + '@grpc/grpc-js': { + enabled: true, + path: '@opentelemetry/plugin-grpc-js', + // // when boostraping with lerna for testing purposes + // path: `${__dirname}/../../packages/opentelemetry-plugin-grpc-js/build/src` + }, + // // when boostraping with lerna for testing purposes + // 'http': { + // enabled: true, + // path: `${__dirname}/../../packages/opentelemetry-plugin-http/build/src` + // }, + }, }, - }, + ], + tracerProvider: provider, }); let exporter; diff --git a/examples/grpc/package.json b/examples/grpc/package.json index 455dd7d656..376f477287 100644 --- a/examples/grpc/package.json +++ b/examples/grpc/package.json @@ -31,6 +31,7 @@ "@opentelemetry/api": "^0.16.0", "@opentelemetry/exporter-jaeger": "^0.16.0", "@opentelemetry/exporter-zipkin": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/node": "^0.16.0", "@opentelemetry/plugin-grpc": "^0.16.0", "@opentelemetry/tracing": "^0.16.0", diff --git a/examples/grpc/tracer.js b/examples/grpc/tracer.js index 34b03b1030..7dd9aaaaca 100644 --- a/examples/grpc/tracer.js +++ b/examples/grpc/tracer.js @@ -1,6 +1,7 @@ 'use strict'; const opentelemetry = require('@opentelemetry/api'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { NodeTracerProvider } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); @@ -10,6 +11,20 @@ const EXPORTER = process.env.EXPORTER || ''; module.exports = (serviceName) => { const provider = new NodeTracerProvider(); + registerInstrumentations({ + tracerProvider: provider, + // // when boostraping with lerna for testing purposes + // instrumentations: [ + // { + // plugins: { + // grpc: { + // enabled: true, + // path: `${__dirname}/../../packages/opentelemetry-plugin-grpc/build/src` + // } + // } + // } + // ], + }); let exporter; if (EXPORTER.toLowerCase().startsWith('z')) { diff --git a/examples/http/package.json b/examples/http/package.json index 62ddee9abf..bb2855589c 100644 --- a/examples/http/package.json +++ b/examples/http/package.json @@ -31,6 +31,7 @@ "@opentelemetry/api": "^0.16.0", "@opentelemetry/exporter-jaeger": "^0.16.0", "@opentelemetry/exporter-zipkin": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/node": "^0.16.0", "@opentelemetry/plugin-http": "^0.16.0", "@opentelemetry/tracing": "^0.16.0" diff --git a/examples/http/tracer.js b/examples/http/tracer.js index 9c48468b5c..1e3d5244e0 100644 --- a/examples/http/tracer.js +++ b/examples/http/tracer.js @@ -1,6 +1,7 @@ 'use strict'; const opentelemetry = require('@opentelemetry/api'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { NodeTracerProvider } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); @@ -10,6 +11,20 @@ const EXPORTER = process.env.EXPORTER || ''; module.exports = (serviceName) => { const provider = new NodeTracerProvider(); + registerInstrumentations({ + tracerProvider: provider, + // // when boostraping with lerna for testing purposes + // instrumentations: [ + // { + // plugins: { + // http: { + // enabled: true, + // path: `${__dirname}/../../packages/opentelemetry-plugin-http/build/src` + // } + // } + // } + // ], + }); let exporter; if (EXPORTER.toLowerCase().startsWith('z')) { diff --git a/examples/https/package.json b/examples/https/package.json index 6e0ce03b59..e980b874a2 100644 --- a/examples/https/package.json +++ b/examples/https/package.json @@ -32,6 +32,7 @@ "@opentelemetry/api": "^0.16.0", "@opentelemetry/exporter-jaeger": "^0.16.0", "@opentelemetry/exporter-zipkin": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/node": "^0.16.0", "@opentelemetry/plugin-https": "^0.16.0", "@opentelemetry/tracing": "^0.16.0" diff --git a/examples/https/tracer.js b/examples/https/tracer.js index 80d0a9b8ac..a91557155f 100644 --- a/examples/https/tracer.js +++ b/examples/https/tracer.js @@ -1,6 +1,7 @@ 'use strict'; const opentelemetry = require('@opentelemetry/api'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { NodeTracerProvider } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); @@ -12,6 +13,20 @@ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; module.exports = (serviceName) => { let exporter; const provider = new NodeTracerProvider(); + registerInstrumentations({ + tracerProvider: provider, + // when boostraping with lerna for testing purposes + // instrumentations: [ + // { + // plugins: { + // https: { + // enabled: true, + // path: `${__dirname}/../../packages/opentelemetry-plugin-https/build/src` + // } + // } + // } + // ], + }); if (EXPORTER.toLowerCase().startsWith('z')) { exporter = new ZipkinExporter({ diff --git a/examples/opentracing-shim/client.js b/examples/opentracing-shim/client.js index 451467e3ef..94b68ac875 100644 --- a/examples/opentracing-shim/client.js +++ b/examples/opentracing-shim/client.js @@ -2,7 +2,7 @@ const http = require('http'); const opentracing = require('opentracing'); -const shim = require('./shim').shim('http_client_service'); +const shim = require('./shim').shim('http_client_opentracing'); opentracing.initGlobalTracer(shim); const tracer = opentracing.globalTracer(); diff --git a/examples/opentracing-shim/package.json b/examples/opentracing-shim/package.json index 6956abae5d..bd07561009 100644 --- a/examples/opentracing-shim/package.json +++ b/examples/opentracing-shim/package.json @@ -31,6 +31,7 @@ "dependencies": { "@opentelemetry/exporter-jaeger": "^0.16.0", "@opentelemetry/exporter-zipkin": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/node": "^0.16.0", "@opentelemetry/shim-opentracing": "^0.16.0", "@opentelemetry/tracing": "^0.16.0", diff --git a/examples/opentracing-shim/server.js b/examples/opentracing-shim/server.js index 66c0803ccd..a21f93a149 100644 --- a/examples/opentracing-shim/server.js +++ b/examples/opentracing-shim/server.js @@ -3,7 +3,7 @@ const http = require('http'); const opentracing = require('opentracing'); const utils = require('./utils'); -const shim = require('./shim').shim('http_server_service'); +const shim = require('./shim').shim('http_server_opentracing'); opentracing.initGlobalTracer(shim); const tracer = opentracing.globalTracer(); diff --git a/examples/opentracing-shim/shim.js b/examples/opentracing-shim/shim.js index 38e6db223d..40ad299e28 100644 --- a/examples/opentracing-shim/shim.js +++ b/examples/opentracing-shim/shim.js @@ -1,5 +1,6 @@ 'use strict'; +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { NodeTracerProvider } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); @@ -8,6 +9,20 @@ const { TracerShim } = require('@opentelemetry/shim-opentracing'); function shim(serviceName) { const provider = new NodeTracerProvider(); + registerInstrumentations({ + tracerProvider: provider, + // // when boostraping with lerna for testing purposes + // instrumentations: [ + // { + // plugins: { + // 'opentracing': { + // enabled: true, + // path: `${__dirname}/../../packages/opentelemetry-shim-opentracing/build/src` + // } + // } + // } + // ], + }); provider.addSpanProcessor(new SimpleSpanProcessor(getExporter(serviceName))); // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings diff --git a/examples/tracer-web/examples/document-load/index.js b/examples/tracer-web/examples/document-load/index.js index 148bbe6c64..610862f2c9 100644 --- a/examples/tracer-web/examples/document-load/index.js +++ b/examples/tracer-web/examples/document-load/index.js @@ -4,12 +4,15 @@ import { WebTracerProvider } from '@opentelemetry/web'; import { DocumentLoad } from '@opentelemetry/plugin-document-load'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import { CollectorTraceExporter } from '@opentelemetry/exporter-collector'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const provider = new WebTracerProvider({ - plugins: [ - new DocumentLoad(), - ], +const provider = new WebTracerProvider(); + +registerInstrumentations({ + instrumentations: [new DocumentLoad()], + tracerProvider: provider, }); + provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.addSpanProcessor(new SimpleSpanProcessor(new CollectorTraceExporter())); diff --git a/examples/tracer-web/examples/fetch/index.js b/examples/tracer-web/examples/fetch/index.js index def161fa7c..ec5eb3e8c3 100644 --- a/examples/tracer-web/examples/fetch/index.js +++ b/examples/tracer-web/examples/fetch/index.js @@ -8,9 +8,12 @@ import { WebTracerProvider } from '@opentelemetry/web'; import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import { B3Propagator } from '@opentelemetry/propagator-b3'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const provider = new WebTracerProvider({ - plugins: [ +const provider = new WebTracerProvider(); + +registerInstrumentations({ + instrumentations: [ new FetchInstrumentation({ ignoreUrls: [/localhost:8090\/sockjs-node/], propagateTraceHeaderCorsUrls: [ @@ -20,6 +23,7 @@ const provider = new WebTracerProvider({ clearTimingResources: true }), ], + tracerProvider: provider, }); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); diff --git a/examples/tracer-web/examples/user-interaction/index.js b/examples/tracer-web/examples/user-interaction/index.js index de22402205..ce951d2a41 100644 --- a/examples/tracer-web/examples/user-interaction/index.js +++ b/examples/tracer-web/examples/user-interaction/index.js @@ -5,9 +5,12 @@ import { ZoneContextManager } from '@opentelemetry/context-zone'; import { CollectorTraceExporter } from '@opentelemetry/exporter-collector'; import { B3Propagator } from '@opentelemetry/propagator-b3'; import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const providerWithZone = new WebTracerProvider({ - plugins: [ +const providerWithZone = new WebTracerProvider(); + +registerInstrumentations({ + instrumentations: [ new UserInteractionPlugin(), new XMLHttpRequestInstrumentation({ ignoreUrls: [/localhost/], @@ -16,6 +19,7 @@ const providerWithZone = new WebTracerProvider({ ], }), ], + tracerProvider: providerWithZone, }); providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); diff --git a/examples/tracer-web/examples/xml-http-request/index.js b/examples/tracer-web/examples/xml-http-request/index.js index cc8a8a4839..435a74a09c 100644 --- a/examples/tracer-web/examples/xml-http-request/index.js +++ b/examples/tracer-web/examples/xml-http-request/index.js @@ -5,9 +5,12 @@ import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xm import { ZoneContextManager } from '@opentelemetry/context-zone'; import { CollectorTraceExporter } from '@opentelemetry/exporter-collector'; import { B3Propagator } from '@opentelemetry/propagator-b3'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const providerWithZone = new WebTracerProvider({ - plugins: [ +const providerWithZone = new WebTracerProvider(); + +registerInstrumentations({ + instrumentations: [ new XMLHttpRequestInstrumentation({ ignoreUrls: [/localhost:8090\/sockjs-node/], propagateTraceHeaderCorsUrls: [ @@ -15,6 +18,7 @@ const providerWithZone = new WebTracerProvider({ ], }), ], + tracerProvider: providerWithZone, }); providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); diff --git a/examples/tracer-web/package.json b/examples/tracer-web/package.json index 3cf285a43f..ca1094ecda 100644 --- a/examples/tracer-web/package.json +++ b/examples/tracer-web/package.json @@ -34,10 +34,12 @@ "webpack-merge": "^4.2.2" }, "dependencies": { + "@opentelemetry/api": "^0.16.0", "@opentelemetry/context-zone": "^0.16.0", "@opentelemetry/core": "^0.16.0", "@opentelemetry/exporter-collector": "^0.16.0", "@opentelemetry/exporter-zipkin": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/instrumentation-fetch": "^0.16.0", "@opentelemetry/instrumentation-xml-http-request": "^0.16.0", "@opentelemetry/metrics": "^0.16.0", diff --git a/getting-started/README.md b/getting-started/README.md index a845c2eb28..d97ed45270 100644 --- a/getting-started/README.md +++ b/getting-started/README.md @@ -78,12 +78,18 @@ Create a file named `tracing.js` and add the following code: const { LogLevel } = require("@opentelemetry/core"); const { NodeTracerProvider } = require("@opentelemetry/node"); +const { registerInstrumentations } = require("@opentelemetry/instrumentation"); const provider = new NodeTracerProvider({ logLevel: LogLevel.ERROR }); provider.register(); + +registerInstrumentations({ + tracerProvider: provider, +}); + ``` Now, if you run your application with `node -r ./tracing.js app.js`, your application will create and propagate traces over HTTP. If an already instrumented service that supports [Trace Context](https://www.w3.org/TR/trace-context/) headers calls your application using HTTP, and you call another application using HTTP, the Trace Context headers will be correctly propagated. @@ -116,11 +122,16 @@ const { LogLevel } = require("@opentelemetry/core"); const { NodeTracerProvider } = require("@opentelemetry/node"); const { SimpleSpanProcessor } = require("@opentelemetry/tracing"); const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); +const { registerInstrumentations } = require("@opentelemetry/instrumentation"); const provider = new NodeTracerProvider({ logLevel: LogLevel.ERROR }); +registerInstrumentations({ + tracerProvider: provider, +}); + provider.register(); provider.addSpanProcessor( diff --git a/getting-started/traced-example/package.json b/getting-started/traced-example/package.json index d3726eac06..85b6088f49 100644 --- a/getting-started/traced-example/package.json +++ b/getting-started/traced-example/package.json @@ -12,6 +12,7 @@ "@opentelemetry/core": "^0.14.0", "@opentelemetry/exporter-zipkin": "^0.14.0", "@opentelemetry/node": "^0.14.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/plugin-express": "^0.12.1", "@opentelemetry/plugin-http": "^0.14.0", "@opentelemetry/plugin-https": "^0.14.0", diff --git a/getting-started/traced-example/tracing.js b/getting-started/traced-example/tracing.js index fcb5b2e610..2f581b7d86 100644 --- a/getting-started/traced-example/tracing.js +++ b/getting-started/traced-example/tracing.js @@ -4,6 +4,7 @@ const { LogLevel } = require("@opentelemetry/core"); const { NodeTracerProvider } = require("@opentelemetry/node"); const { SimpleSpanProcessor } = require("@opentelemetry/tracing"); const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const provider = new NodeTracerProvider({ logLevel: LogLevel.ERROR }); @@ -19,4 +20,10 @@ provider.addSpanProcessor( ); provider.register(); + +// load old default plugins +registerInstrumentations({ + tracerProvider: provider, +}); + console.log("tracing initialized"); diff --git a/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts b/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts index f99636549c..28413baf1c 100644 --- a/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts +++ b/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts @@ -15,7 +15,10 @@ */ import * as api from '@opentelemetry/api'; import * as core from '@opentelemetry/core'; -import { isWrapped } from '@opentelemetry/instrumentation'; +import { + isWrapped, + registerInstrumentations, +} from '@opentelemetry/instrumentation'; import { B3Propagator, @@ -215,7 +218,10 @@ describe('fetch', () => { fetchInstrumentation = new FetchInstrumentation(config); webTracerProviderWithZone = new WebTracerProvider({ logLevel: core.LogLevel.ERROR, - plugins: [fetchInstrumentation], + }); + registerInstrumentations({ + tracerProvider: webTracerProviderWithZone, + instrumentations: [fetchInstrumentation], }); webTracerWithZone = webTracerProviderWithZone.getTracer('fetch-test'); dummySpanExporter = new DummySpanExporter(); diff --git a/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts b/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts index 61e6846f77..a5d779a3c9 100644 --- a/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts +++ b/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { Span } from '@opentelemetry/api'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { HttpAttribute } from '@opentelemetry/semantic-conventions'; import { ReadableSpan, SpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; @@ -40,8 +41,10 @@ describe('unmocked xhr', () => { let testSpans: TestSpanProcessor; let provider: WebTracerProvider; beforeEach(() => { - provider = new WebTracerProvider({ - plugins: [new XMLHttpRequestInstrumentation()], + provider = new WebTracerProvider(); + registerInstrumentations({ + instrumentations: [new XMLHttpRequestInstrumentation()], + tracerProvider: provider, }); testSpans = new TestSpanProcessor(); provider.addSpanProcessor(testSpans); 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 952ee2d211..431b82741b 100644 --- a/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts @@ -19,6 +19,7 @@ import { otperformance as performance, isWrapped, } from '@opentelemetry/core'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { B3Propagator, B3InjectEncoding, @@ -203,7 +204,10 @@ describe('xhr', () => { ); webTracerProviderWithZone = new WebTracerProvider({ logLevel: LogLevel.ERROR, - plugins: [xmlHttpRequestInstrumentation], + }); + registerInstrumentations({ + instrumentations: [xmlHttpRequestInstrumentation], + tracerProvider: webTracerProviderWithZone, }); webTracerWithZone = webTracerProviderWithZone.getTracer('xhr-test'); dummySpanExporter = new DummySpanExporter(); @@ -730,8 +734,13 @@ describe('xhr', () => { webTracerWithZoneProvider = new WebTracerProvider({ logLevel: LogLevel.ERROR, - plugins: [new XMLHttpRequestInstrumentation()], }); + + registerInstrumentations({ + instrumentations: [new XMLHttpRequestInstrumentation()], + tracerProvider: webTracerWithZoneProvider, + }); + dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); webTracerWithZoneProvider.addSpanProcessor( diff --git a/packages/opentelemetry-instrumentation/src/index.ts b/packages/opentelemetry-instrumentation/src/index.ts index 078c877124..8420c6968e 100644 --- a/packages/opentelemetry-instrumentation/src/index.ts +++ b/packages/opentelemetry-instrumentation/src/index.ts @@ -17,4 +17,5 @@ export * from './autoLoader'; export * from './platform/index'; export * from './types'; +export * from './types_internal'; export * from './utils'; diff --git a/packages/opentelemetry-instrumentation/src/platform/node/index.ts b/packages/opentelemetry-instrumentation/src/platform/node/index.ts index e5f3252405..9f5254d653 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/index.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/index.ts @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export * from './old/autoLoader'; export * from './instrumentation'; export * from './instrumentationNodeModuleDefinition'; export * from './instrumentationNodeModuleFile'; +export * from './old/autoLoader'; export * from './types'; diff --git a/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts index 62d43b75d6..8324c01cd0 100644 --- a/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts +++ b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts @@ -15,10 +15,9 @@ */ import * as assert from 'assert'; -import { Instrumentation } from '../../src'; -import { InstrumentationAbstract } from '../../src/instrumentation'; +import { Instrumentation, InstrumentationBase } from '../../src'; -class TestInstrumentation extends InstrumentationAbstract { +class TestInstrumentation extends InstrumentationBase { constructor() { super('test', '1.0.0'); } @@ -34,7 +33,7 @@ describe('BaseInstrumentation', () => { }); it('should create an instance', () => { - assert.ok(instrumentation instanceof InstrumentationAbstract); + assert.ok(instrumentation instanceof InstrumentationBase); }); it('should have a name', () => { @@ -44,4 +43,17 @@ describe('BaseInstrumentation', () => { it('should have a version', () => { assert.deepStrictEqual(instrumentation.instrumentationVersion, '1.0.0'); }); + + describe('constructor', () => { + it('should enable instrumentation by default', () => { + let called = false; + class TestInstrumentation2 extends TestInstrumentation { + enable() { + called = true; + } + } + instrumentation = new TestInstrumentation2(); + assert.strictEqual(called, true); + }); + }); }); diff --git a/packages/opentelemetry-node/README.md b/packages/opentelemetry-node/README.md index 5fc9883042..cb935a7e1a 100644 --- a/packages/opentelemetry-node/README.md +++ b/packages/opentelemetry-node/README.md @@ -12,17 +12,13 @@ For manual instrumentation see the ## How auto instrumentation works -This package exposes a `NodeTracerProvider` that will automatically hook into the module loader of Node.js. +This package exposes a `NodeTracerProvider`. +For loading plugins / instrumentations please use `registerInstrumentations` function from [opentelemetry-instrumentation](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-instrumentation) -For this to work, please make sure that `NodeTracerProvider` is initialized before any other module of your application, (like `http` or `express`) is loaded. - -OpenTelemetry comes with a growing number of instrumentation plugins for well know modules (see [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins)) and an API to create custom plugins (see [the plugin developer guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/plugin-guide.md)). - -Whenever a module is loaded `NodeTracerProvider` will check if a matching instrumentation plugin has been installed. +OpenTelemetry comes with a growing number of instrumentation plugins for well know modules (see [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins)) and an API to create custom instrumentation (see [the instrumentation developer guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/instrumentation-guide.md)). > **Please note:** This module does *not* bundle any plugins. They need to be installed separately. -If the respective plugin was found, it will be used to patch the original module to add instrumentation code. This is done by wrapping all tracing-relevant functions. This instrumentation code will automatically @@ -32,8 +28,6 @@ This instrumentation code will automatically - add this trace-context identifier to outbound requests to allow continuing the distributed trace on the next hop (if applicable) - create and end spans -In short, this means that this module will use provided plugins to automatically instrument your application to produce spans and provide end-to-end tracing by just adding a few lines of code. - ## Creating custom spans on top of auto-instrumentation Additionally to automated instrumentation, `NodeTracerProvider` exposes the same API as [@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-tracing), allowing creating custom spans if needed. @@ -45,8 +39,9 @@ npm install --save @opentelemetry/api npm install --save @opentelemetry/node # Install instrumentation plugins -npm install --save @opentelemetry/plugin-http -npm install --save @opentelemetry/plugin-https +npm install --save @opentelemetry/instrumentation-http +# and for example one additional +npm install --save instrumentation-graphql ``` ## Usage @@ -56,21 +51,28 @@ The following code will configure the `NodeTracerProvider` to instrument `http` modules](https://github.com/open-telemetry/opentelemetry-js#plugins)) using `@opentelemetry/plugin-http`. -```js +```javascript +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); const { NodeTracerProvider } = require('@opentelemetry/node'); // Create and configure NodeTracerProvider const provider = new NodeTracerProvider(); // Initialize the provider -provider.register() +provider.register(); + +// register and load instrumentation and old plugins - old plugins will be loaded automatically as previously +// but instrumentations needs to be added +registerInstrumentations({ + tracerProvider: provider, +}); // Your application code - http will automatically be instrumented if // @opentelemetry/plugin-http is present const http = require('http'); ``` -## Plugin configuration +## Instrumentation / Plugin configuration User supplied plugin configuration is merged with the default plugin configuration. Furthermore, custom plugins that are configured are implicitly @@ -83,22 +85,37 @@ In the following example: - the customPlugin is loaded from the user supplied path - all default plugins are still loaded if installed. -```js -const provider = new NodeTracerProvider({ - plugins: { - express: { - enabled: false, - }, - http: { - requestHook: (span, request) => { - span.setAttribute("custom request hook attribute", "request"); +```javascript +const { GraphQLInstrumentation } = require('@opentelemetry/instrumentation-graphql'); + +const provider = new NodeTracerProvider(); + +// register and load instrumentation and old plugins - old plugins will be loaded automatically as previously +// but instrumentations needs to be added +registerInstrumentations({ + tracerProvider: provider, + instrumentations: [ + new GraphQLInstrumentation(), + // for older plugins you can just copy paste the old configuration + { + plugins: { + express: { + enabled: false, + }, + http: { + requestHook: (span, request) => { + span.setAttribute("custom request hook attribute", "request"); + }, + }, + customPlugin: { + path: "/path/to/custom/module", + }, }, - }, - customPlugin: { - path: "/path/to/custom/module", - }, - }, + } + ], }); + + ``` ### Disable Plugins with Environment Variables diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 561592e0b2..10a6dc6881 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -47,12 +47,14 @@ "@types/node": "14.14.20", "@types/semver": "7.3.4", "@types/shimmer": "1.0.1", + "@types/sinon": "9.0.10", "codecov": "3.8.1", "gts": "3.1.0", "mocha": "7.2.0", "nyc": "15.1.0", "rimraf": "3.0.2", "shimmer": "1.2.1", + "sinon": "9.2.3", "ts-mocha": "8.0.0", "ts-node": "9.1.1", "typescript": "4.1.3" @@ -62,7 +64,6 @@ "@opentelemetry/context-async-hooks": "^0.16.0", "@opentelemetry/core": "^0.16.0", "@opentelemetry/tracing": "^0.16.0", - "require-in-the-middle": "^5.0.0", "semver": "^7.1.3" } } diff --git a/packages/opentelemetry-node/src/NodeTracerProvider.ts b/packages/opentelemetry-node/src/NodeTracerProvider.ts index 67301a2f9d..4178995ee2 100644 --- a/packages/opentelemetry-node/src/NodeTracerProvider.ts +++ b/packages/opentelemetry-node/src/NodeTracerProvider.ts @@ -22,9 +22,8 @@ import { BasicTracerProvider, SDKRegistrationConfig, } from '@opentelemetry/tracing'; -import { DEFAULT_INSTRUMENTATION_PLUGINS, NodeTracerConfig } from './config'; -import { PluginLoader, Plugins } from './instrumentation/PluginLoader'; import * as semver from 'semver'; +import { NodeTracerConfig } from './config'; /** * Register this TracerProvider for use with the OpenTelemetry API. @@ -34,25 +33,14 @@ import * as semver from 'semver'; * @param config Configuration object for SDK registration */ export class NodeTracerProvider extends BasicTracerProvider { - private readonly _pluginLoader: PluginLoader; - - /** - * Constructs a new Tracer instance. - */ constructor(config: NodeTracerConfig = {}) { super(config); - - this._pluginLoader = new PluginLoader(this, this.logger); - - config.plugins - ? this._pluginLoader.load( - this._mergePlugins(DEFAULT_INSTRUMENTATION_PLUGINS, config.plugins) - ) - : this._pluginLoader.load(DEFAULT_INSTRUMENTATION_PLUGINS); - } - - stop() { - this._pluginLoader.unload(); + if (config.plugins) { + console.warn( + 'plugins options was removed, please use' + + ' "registerInstrumentations" to load plugins' + ); + } } register(config: SDKRegistrationConfig = {}) { @@ -66,33 +54,4 @@ export class NodeTracerProvider extends BasicTracerProvider { super.register(config); } - - /** - * Two layer merge. - * First, for user supplied config of plugin(s) that are loaded by default, - * merge the user supplied and default configs of said plugin(s). - * Then merge the results with the default plugins. - * @returns 2-layer deep merge of default and user supplied plugins. - */ - private _mergePlugins( - defaultPlugins: Plugins, - userSuppliedPlugins: Plugins - ): Plugins { - const mergedUserSuppliedPlugins: Plugins = {}; - - for (const pluginName in userSuppliedPlugins) { - mergedUserSuppliedPlugins[pluginName] = { - // Any user-supplied non-default plugin should be enabled by default - ...(DEFAULT_INSTRUMENTATION_PLUGINS[pluginName] || { enabled: true }), - ...userSuppliedPlugins[pluginName], - }; - } - - const mergedPlugins: Plugins = { - ...defaultPlugins, - ...mergedUserSuppliedPlugins, - }; - - return mergedPlugins; - } } diff --git a/packages/opentelemetry-node/src/config.ts b/packages/opentelemetry-node/src/config.ts index 016a998f6a..e5122b5ad9 100644 --- a/packages/opentelemetry-node/src/config.ts +++ b/packages/opentelemetry-node/src/config.ts @@ -14,31 +14,12 @@ * limitations under the License. */ -import { Plugins } from './instrumentation/PluginLoader'; import { TracerConfig } from '@opentelemetry/tracing'; /** * NodeTracerConfig provides an interface for configuring a Node Tracer. */ export interface NodeTracerConfig extends TracerConfig { - /** Plugins options. */ - plugins?: Plugins; + /** Plugins options deprecated */ + plugins?: unknown[]; } - -/** List of all default supported plugins */ -export const DEFAULT_INSTRUMENTATION_PLUGINS: Plugins = { - mongodb: { enabled: true, path: '@opentelemetry/plugin-mongodb' }, - grpc: { enabled: true, path: '@opentelemetry/plugin-grpc' }, - '@grpc/grpc-js': { enabled: true, path: '@opentelemetry/plugin-grpc-js' }, - http: { enabled: true, path: '@opentelemetry/plugin-http' }, - https: { enabled: true, path: '@opentelemetry/plugin-https' }, - mysql: { enabled: true, path: '@opentelemetry/plugin-mysql' }, - pg: { enabled: true, path: '@opentelemetry/plugin-pg' }, - redis: { enabled: true, path: '@opentelemetry/plugin-redis' }, - ioredis: { enabled: true, path: '@opentelemetry/plugin-ioredis' }, - 'pg-pool': { enabled: true, path: '@opentelemetry/plugin-pg-pool' }, - express: { enabled: true, path: '@opentelemetry/plugin-express' }, - '@hapi/hapi': { enabled: true, path: '@opentelemetry/hapi-instrumentation' }, - koa: { enabled: true, path: '@opentelemetry/koa-instrumentation' }, - dns: { enabled: true, path: '@opentelemetry/plugin-dns' }, -}; diff --git a/packages/opentelemetry-node/src/index.ts b/packages/opentelemetry-node/src/index.ts index 092ae180c9..44e347c09e 100644 --- a/packages/opentelemetry-node/src/index.ts +++ b/packages/opentelemetry-node/src/index.ts @@ -15,5 +15,4 @@ */ export { NodeTracerConfig } from './config'; -export { Plugins } from './instrumentation/PluginLoader'; export * from './NodeTracerProvider'; diff --git a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts deleted file mode 100644 index 618cff0918..0000000000 --- a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Logger, TracerProvider } from '@opentelemetry/api'; -import { Plugin, PluginConfig } from '@opentelemetry/core'; -import { getEnv } from '@opentelemetry/core'; -import * as hook from 'require-in-the-middle'; -import * as utils from './utils'; - -// States for the Plugin Loader -export enum HookState { - UNINITIALIZED, - ENABLED, - DISABLED, -} - -/** - * Wildcard symbol. If ignore list is set to this, disable all plugins - */ -const DISABLE_ALL_PLUGINS = '*'; - -export interface Plugins { - [pluginName: string]: PluginConfig; -} - -/** - * Returns the Plugins object that meet the below conditions. - * Valid criteria: 1. It should be enabled. 2. Should have non-empty path. - */ -function filterPlugins(plugins: Plugins): Plugins { - const keys = Object.keys(plugins); - return keys.reduce((acc: Plugins, key: string) => { - if (plugins[key].enabled && plugins[key].path) acc[key] = plugins[key]; - return acc; - }, {}); -} - -/** - * The PluginLoader class can load instrumentation plugins that use a patch - * mechanism to enable automatic tracing for specific target modules. - */ -export class PluginLoader { - /** A list of loaded plugins. */ - private _plugins: Plugin[] = []; - /** - * A field that tracks whether the require-in-the-middle hook has been loaded - * for the first time, as well as whether the hook body is activated or not. - */ - private _hookState = HookState.UNINITIALIZED; - - /** Constructs a new PluginLoader instance. */ - constructor(readonly provider: TracerProvider, readonly logger: Logger) {} - - /** - * Loads a list of plugins. Each plugin module should implement the core - * {@link Plugin} interface and export an instance named as 'plugin'. This - * function will attach a hook to be called the first time the module is - * loaded. - * @param Plugins an object whose keys are plugin names and whose - * {@link PluginConfig} values indicate several configuration options. - */ - load(plugins: Plugins): PluginLoader { - if (this._hookState === HookState.UNINITIALIZED) { - const pluginsToLoad = filterPlugins(plugins); - const modulesToHook = Object.keys(pluginsToLoad); - const modulesToIgnore = getEnv().OTEL_NO_PATCH_MODULES; - // Do not hook require when no module is provided. In this case it is - // not necessary. With skipping this step we lower our footprint in - // customer applications and require-in-the-middle won't show up in CPU - // frames. - if (modulesToHook.length === 0) { - this._hookState = HookState.DISABLED; - return this; - } - - const requiredModulesToHook = modulesToHook.filter((name: string) => { - try { - const moduleResolvedFilename = require.resolve(name); - return moduleResolvedFilename in require.cache; - } catch { - return false; - } - }); - if (requiredModulesToHook.length > 0) { - this.logger.warn( - `Some modules (${requiredModulesToHook.join( - ', ' - )}) were already required when their respective plugin was loaded, some plugins might not work. Make sure the SDK is setup before you require in other modules.` - ); - } - - // Enable the require hook. - hook(modulesToHook, (exports, name, baseDir) => { - if (this._hookState !== HookState.ENABLED) return exports; - const config = pluginsToLoad[name]; - const modulePath = config.path!; - let version = null; - - if (!baseDir) { - // basedir is the directory where the module is located, - // or undefined for core modules. - // lets plugins restrict what they support for core modules (see plugin.supportedVersions) - version = process.versions.node; - } else { - // Get the module version. - version = utils.getPackageVersion(this.logger, baseDir); - } - - // Skip loading of all modules if '*' is provided - if (modulesToIgnore[0] === DISABLE_ALL_PLUGINS) { - this.logger.info( - `PluginLoader#load: skipped patching module ${name} because all plugins are disabled (${modulesToIgnore.join( - ',' - )})` - ); - return exports; - } - - if (modulesToIgnore.includes(name)) { - this.logger.info( - `PluginLoader#load: skipped patching module ${name} because it was on the ignore list (${modulesToIgnore.join( - ',' - )})` - ); - return exports; - } - - this.logger.info( - `PluginLoader#load: trying to load ${name}@${version}` - ); - - if (!version) return exports; - - this.logger.debug( - `PluginLoader#load: applying patch to ${name}@${version} using ${modulePath} module` - ); - - // Expecting a plugin from module; - try { - const plugin: Plugin = require(modulePath).plugin; - if (!utils.isSupportedVersion(version, plugin.supportedVersions)) { - this.logger.warn( - `PluginLoader#load: Plugin ${name} only supports module ${plugin.moduleName} with the versions: ${plugin.supportedVersions}` - ); - return exports; - } - if (plugin.moduleName !== name) { - this.logger.error( - `PluginLoader#load: Entry ${name} use a plugin that instruments ${plugin.moduleName}` - ); - return exports; - } - - this._plugins.push(plugin); - // Enable each supported plugin. - return plugin.enable(exports, this.provider, this.logger, config); - } catch (e) { - this.logger.error( - `PluginLoader#load: could not load plugin ${modulePath} of module ${name}. Error: ${e.message}` - ); - return exports; - } - }); - this._hookState = HookState.ENABLED; - } else if (this._hookState === HookState.DISABLED) { - this.logger.error( - 'PluginLoader#load: Currently cannot re-enable plugin loader.' - ); - } else { - this.logger.error('PluginLoader#load: Plugin loader already enabled.'); - } - return this; - } - - /** Unloads plugins. */ - unload(): PluginLoader { - if (this._hookState === HookState.ENABLED) { - for (const plugin of this._plugins) { - plugin.disable(); - } - this._plugins = []; - this._hookState = HookState.DISABLED; - } - return this; - } -} - -/** - * Adds a search path for plugin modules. Intended for testing purposes only. - * @param searchPath The path to add. - */ -export function searchPathForTest(searchPath: string) { - module.paths.push(searchPath); -} diff --git a/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts b/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts deleted file mode 100644 index 832cb09086..0000000000 --- a/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -declare module 'require-in-the-middle' { - namespace hook { - type Options = { - internals?: boolean; - }; - type OnRequireFn = (exports: T, name: string, basedir?: string) => T; - } - function hook( - modules: string[] | null, - options: hook.Options | null, - onRequire: hook.OnRequireFn - ): void; - function hook(modules: string[] | null, onRequire: hook.OnRequireFn): void; - function hook(onRequire: hook.OnRequireFn): void; - export = hook; -} diff --git a/packages/opentelemetry-node/src/instrumentation/utils.ts b/packages/opentelemetry-node/src/instrumentation/utils.ts deleted file mode 100644 index 238096cd06..0000000000 --- a/packages/opentelemetry-node/src/instrumentation/utils.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Logger } from '@opentelemetry/api'; -import * as path from 'path'; -import * as semver from 'semver'; - -/** - * Gets the package version. - * @param logger The logger to use. - * @param basedir The base directory. - */ -export function getPackageVersion( - logger: Logger, - basedir: string -): string | null { - const pjsonPath = path.join(basedir, 'package.json'); - try { - const version = require(pjsonPath).version; - // Attempt to parse a string as a semantic version, returning either a - // SemVer object or null. - if (!semver.parse(version)) { - logger.error( - `getPackageVersion: [${pjsonPath}|${version}] Version string could not be parsed.` - ); - return null; - } - return version; - } catch (e) { - logger.error( - `getPackageVersion: [${pjsonPath}] An error occurred while retrieving version string. ${e.message}` - ); - return null; - } -} - -/** - * Determines if a version is supported - * @param moduleVersion a version in [semver](https://semver.org/spec/v2.0.0.html) format. - * @param [supportedVersions] a list of supported versions ([semver](https://semver.org/spec/v2.0.0.html) format). - */ -export function isSupportedVersion( - moduleVersion: string, - supportedVersions?: string[] -) { - if (!Array.isArray(supportedVersions) || supportedVersions.length === 0) { - return true; - } - - return supportedVersions.some(supportedVersion => - semver.satisfies(moduleVersion, supportedVersion) - ); -} - -/** - * Adds a search path for plugin modules. Intended for testing purposes only. - * @param searchPath The path to add. - */ -export function searchPathForTest(searchPath: string) { - module.paths.push(searchPath); -} diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index 851091b0ac..fab7c8ee78 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -31,6 +31,7 @@ import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { Span } from '@opentelemetry/tracing'; import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources'; import * as assert from 'assert'; +import * as sinon from 'sinon'; import * as path from 'path'; import { ContextManager, ROOT_CONTEXT } from '@opentelemetry/context-base'; import { NodeTracerProvider } from '../src/NodeTracerProvider'; @@ -61,7 +62,6 @@ describe('NodeTracerProvider', () => { afterEach(() => { // clear require cache Object.keys(require.cache).forEach(key => delete require.cache[key]); - provider.stop(); contextManager.disable(); context.disable(); }); @@ -86,38 +86,18 @@ describe('NodeTracerProvider', () => { assert.ok(provider instanceof NodeTracerProvider); }); - it('should load a merge of user configured and default plugins and implictly enable non-default plugins', () => { - provider = new NodeTracerProvider({ - logger: new NoopLogger(), - plugins: { - 'simple-module': { - path: '@opentelemetry/plugin-simple-module', - }, - 'supported-module': { - path: '@opentelemetry/plugin-supported-module', - enhancedDatabaseReporting: false, - ignoreMethods: [], - ignoreUrls: [], - }, - 'random-module': { - enabled: false, - path: '@opentelemetry/random-module', - }, - http: { - path: '@opentelemetry/plugin-http-module', - }, - }, - }); - const plugins = provider['_pluginLoader']['_plugins']; - assert.strictEqual(plugins.length, 0); - require('simple-module'); - assert.strictEqual(plugins.length, 1); - require('supported-module'); - assert.strictEqual(plugins.length, 2); - require('random-module'); - assert.strictEqual(plugins.length, 2); - require('http'); - assert.strictEqual(plugins.length, 3); + it('should show warning when plugins are defined', () => { + const dummyPlugin1 = {}; + const spyWarn = sinon.spy(console, 'warn'); + + const plugins = [dummyPlugin1]; + const options = { plugins }; + provider = new NodeTracerProvider(options); + + assert.strictEqual( + spyWarn.args[0][0], + 'plugins options was removed, please use "registerInstrumentations" to load plugins' + ); }); }); @@ -264,52 +244,3 @@ describe('NodeTracerProvider', () => { }); }); }); - -describe('mergePlugins', () => { - const defaultPlugins = { - module1: { - enabled: true, - path: 'testpath', - }, - module2: { - enabled: true, - path: 'testpath2', - }, - module3: { - enabled: true, - path: 'testpath3', - }, - }; - - const userPlugins = { - module2: { - path: 'userpath', - }, - module3: { - enabled: false, - }, - nonDefaultModule: { - path: 'userpath2', - }, - }; - - const provider = new NodeTracerProvider(); - - const mergedPlugins = provider['_mergePlugins'](defaultPlugins, userPlugins); - - it('should merge user and default configs', () => { - assert.equal(mergedPlugins.module1.enabled, true); - assert.equal(mergedPlugins.module1.path, 'testpath'); - assert.equal(mergedPlugins.module2.enabled, true); - assert.equal(mergedPlugins.module2.path, 'userpath'); - assert.equal(mergedPlugins.module3.enabled, false); - assert.equal(mergedPlugins.nonDefaultModule.enabled, true); - assert.equal(mergedPlugins.nonDefaultModule.path, 'userpath2'); - }); - - it('should should not mangle default config', () => { - assert.equal(defaultPlugins.module2.path, 'testpath2'); - assert.equal(defaultPlugins.module3.enabled, true); - assert.equal(defaultPlugins.module3.path, 'testpath3'); - }); -}); diff --git a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts deleted file mode 100644 index 3efef3f0f9..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { NoopTracerProvider, NoopLogger } from '@opentelemetry/api'; -import * as assert from 'assert'; -import * as path from 'path'; -import { - HookState, - PluginLoader, - Plugins, - searchPathForTest, -} from '../../src/instrumentation/PluginLoader'; - -const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules'); -/* eslint-disable node/no-extraneous-require */ -const simplePlugins: Plugins = { - 'simple-module': { - enabled: true, - path: '@opentelemetry/plugin-simple-module', - ignoreMethods: [], - ignoreUrls: [], - }, -}; - -const httpPlugins: Plugins = { - http: { - enabled: true, - path: '@opentelemetry/plugin-http-module', - ignoreMethods: [], - ignoreUrls: [], - }, -}; - -const disablePlugins: Plugins = { - 'simple-module': { - enabled: false, - path: '@opentelemetry/plugin-simple-module', - }, - nonexistent: { - enabled: false, - path: '@opentelemetry/plugin-nonexistent-module', - }, -}; - -const nonexistentPlugins: Plugins = { - nonexistent: { - enabled: true, - path: '@opentelemetry/plugin-nonexistent-module', - }, -}; - -const missingPathPlugins: Plugins = { - 'simple-module': { - enabled: true, - }, - nonexistent: { - enabled: true, - }, -}; - -const supportedVersionPlugins: Plugins = { - 'supported-module': { - enabled: true, - path: '@opentelemetry/plugin-supported-module', - }, -}; - -const notSupportedVersionPlugins: Plugins = { - 'notsupported-module': { - enabled: true, - path: 'notsupported-module', - }, -}; - -const alreadyRequiredPlugins: Plugins = { - 'already-require-module': { - enabled: true, - path: '@opentelemetry/plugin-supported-module', - }, -}; - -const differentNamePlugins: Plugins = { - 'random-module': { - enabled: true, - path: '@opentelemetry/plugin-http-module', - }, -}; - -describe('PluginLoader', () => { - const provider = new NoopTracerProvider(); - const logger = new NoopLogger(); - - before(() => { - module.paths.push(INSTALLED_PLUGINS_PATH); - searchPathForTest(INSTALLED_PLUGINS_PATH); - }); - - afterEach(() => { - // clear require cache - Object.keys(require.cache).forEach(key => delete require.cache[key]); - }); - - describe('.state()', () => { - it('returns UNINITIALIZED when first called', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_hookState'], HookState.UNINITIALIZED); - }); - - it('transitions from UNINITIALIZED to ENABLED', () => { - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load(simplePlugins); - assert.strictEqual(pluginLoader['_hookState'], HookState.ENABLED); - pluginLoader.unload(); - }); - - it('transitions from ENABLED to DISABLED', () => { - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load(simplePlugins).unload(); - assert.strictEqual(pluginLoader['_hookState'], HookState.DISABLED); - }); - }); - - describe('.load()', () => { - afterEach(() => { - delete process.env['OTEL_NO_PATCH_MODULES']; - }); - - it('sanity check', () => { - // Ensure that module fixtures contain values that we expect. - const simpleModule = require('simple-module'); - const simpleModule001 = require('supported-module'); - const simpleModule100 = require('notsupported-module'); - - assert.strictEqual(simpleModule.name(), 'simple-module'); - assert.strictEqual(simpleModule001.name(), 'supported-module'); - assert.strictEqual(simpleModule100.name(), 'notsupported-module'); - - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule001.value(), 0); - assert.strictEqual(simpleModule100.value(), 0); - - assert.throws(() => require('nonexistent-module')); - }); - - it('should not load a plugin on the ignore list environment variable', () => { - // Set ignore list env var - process.env['OTEL_NO_PATCH_MODULES'] = 'simple-module'; - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load({ ...simplePlugins, ...supportedVersionPlugins }); - - assert.strictEqual(pluginLoader['_plugins'].length, 0); - - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - - const supportedModule = require('supported-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(supportedModule.value(), 1); - assert.strictEqual(supportedModule.name(), 'patched-supported-module'); - - pluginLoader.unload(); - }); - - it('should not load plugins on the ignore list environment variable', () => { - // Set ignore list env var - process.env['OTEL_NO_PATCH_MODULES'] = 'simple-module,http'; - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load({ - ...simplePlugins, - ...supportedVersionPlugins, - ...httpPlugins, - }); - - assert.strictEqual(pluginLoader['_plugins'].length, 0); - - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - - const httpModule = require('http'); - assert.ok(httpModule); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - - const supportedModule = require('supported-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(supportedModule.value(), 1); - assert.strictEqual(supportedModule.name(), 'patched-supported-module'); - - pluginLoader.unload(); - }); - - it('should not load any plugins if ignore list environment variable is set to "*"', () => { - // Set ignore list env var - process.env['OTEL_NO_PATCH_MODULES'] = '*'; - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load({ - ...simplePlugins, - ...supportedVersionPlugins, - ...httpPlugins, - }); - - assert.strictEqual(pluginLoader['_plugins'].length, 0); - - const simpleModule = require('simple-module'); - const httpModule = require('http'); - const supportedModule = require('supported-module'); - - assert.strictEqual( - pluginLoader['_plugins'].length, - 0, - 'No plugins were loaded' - ); - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - assert.ok(httpModule); - assert.strictEqual(supportedModule.value(), 0); - assert.strictEqual(supportedModule.name(), 'supported-module'); - - pluginLoader.unload(); - }); - - it('should load a plugin and patch the target modules', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(simplePlugins); - // The hook is only called the first time the module is loaded. - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(simpleModule.value(), 1); - assert.strictEqual(simpleModule.name(), 'patched-simple-module'); - pluginLoader.unload(); - }); - - it('should load a plugin and patch the core module', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(httpPlugins); - // The hook is only called the first time the module is loaded. - const httpModule = require('http'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(httpModule.get(), 'patched'); - pluginLoader.unload(); - }); - // @TODO: simplify this test once we can load module with custom path - it('should not load the plugin when supported versions does not match', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(notSupportedVersionPlugins); - // The hook is only called the first time the module is loaded. - require('notsupported-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.unload(); - }); - // @TODO: simplify this test once we can load module with custom path - it('should load a plugin and patch the target modules when supported versions match', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(supportedVersionPlugins); - // The hook is only called the first time the module is loaded. - const simpleModule = require('supported-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(simpleModule.value(), 1); - assert.strictEqual(simpleModule.name(), 'patched-supported-module'); - pluginLoader.unload(); - }); - - it('should not load a plugin when value is false', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(disablePlugins); - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - pluginLoader.unload(); - }); - - it('should not load a plugin when value is true but path is missing', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(missingPathPlugins); - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - assert.strictEqual(simpleModule.value(), 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - pluginLoader.unload(); - }); - - it('should not load a non existing plugin', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(nonexistentPlugins); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.unload(); - }); - - it("doesn't patch modules for which plugins aren't specified", () => { - const pluginLoader = new PluginLoader(provider, logger); - pluginLoader.load({}); - assert.strictEqual(require('simple-module').value(), 0); - pluginLoader.unload(); - }); - - it('should warn when module was already loaded', callback => { - const verifyWarnLogger = { - error: logger.error, - info: logger.info, - debug: logger.debug, - warn: (message: string, ...args: unknown[]) => { - assert(message.match(/were already required when/)); - assert(message.match(/(already-require-module)/)); - return callback(); - }, - }; - require('already-require-module'); - const pluginLoader = new PluginLoader(provider, verifyWarnLogger); - pluginLoader.load(alreadyRequiredPlugins); - pluginLoader.unload(); - }); - - it('should not load a plugin that patches a different module that the one configured', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(differentNamePlugins); - require('random-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.unload(); - }); - }); - - describe('.unload()', () => { - it('should unload the plugins and unpatch the target module when unloads', () => { - const pluginLoader = new PluginLoader(provider, logger); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - pluginLoader.load(simplePlugins); - // The hook is only called the first time the module is loaded. - const simpleModule = require('simple-module'); - assert.strictEqual(pluginLoader['_plugins'].length, 1); - assert.strictEqual(simpleModule.value(), 1); - assert.strictEqual(simpleModule.name(), 'patched-simple-module'); - pluginLoader.unload(); - assert.strictEqual(pluginLoader['_plugins'].length, 0); - assert.strictEqual(simpleModule.name(), 'simple-module'); - assert.strictEqual(simpleModule.value(), 0); - }); - }); -}); diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/http-module.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/http-module.js deleted file mode 100644 index 2c46ac30ee..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/http-module.js +++ /dev/null @@ -1,22 +0,0 @@ -Object.defineProperty(exports, "__esModule", { value: true }); -const core_1 = require("@opentelemetry/core"); -const shimmer = require("shimmer"); - -class HttpModulePlugin extends core_1.BasePlugin { - constructor() { - super(); - this.moduleName = 'http'; - } - - patch() { - shimmer.wrap(this._moduleExports, 'get', orig => () => 'patched'); - return this._moduleExports; - } - - unpatch() { - shimmer.unwrap(this._moduleExports, 'get'); - } -} -exports.HttpModulePlugin = HttpModulePlugin; -const plugin = new HttpModulePlugin(); -exports.plugin = plugin; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/index.js deleted file mode 100644 index 4847af1405..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} -Object.defineProperty(exports, "__esModule", { value: true }); -__export(require("./http-module")); diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/package.json deleted file mode 100644 index bb40eab67d..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-http-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@opentelemetry/plugin-http-module", - "version": "0.0.1" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/index.js deleted file mode 100644 index 1b22b5ce90..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} -Object.defineProperty(exports, "__esModule", { value: true }); -__export(require("./simple-module")); diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/package.json deleted file mode 100644 index 4db9e49b1d..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@opentelemetry/plugin-notsupported-module", - "version": "1.0.0" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/simple-module.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/simple-module.js deleted file mode 100644 index 92bb7d4e80..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-notsupported-module/simple-module.js +++ /dev/null @@ -1,25 +0,0 @@ -Object.defineProperty(exports, "__esModule", { value: true }); -const core_1 = require("@opentelemetry/core"); -const shimmer = require("shimmer"); - -class SimpleModulePlugin extends core_1.BasePlugin { - constructor() { - super(); - this.moduleName = 'notsupported-module'; - } - - patch() { - shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply()); - shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1); - return this._moduleExports; - } - - unpatch() { - shimmer.unwrap(this._moduleExports, 'name'); - shimmer.unwrap(this._moduleExports, 'value'); - } -} -exports.SimpleModulePlugin = SimpleModulePlugin; -const plugin = new SimpleModulePlugin(); -plugin.supportedVersions = ['1.0.0']; -exports.plugin = plugin; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/index.js deleted file mode 100644 index 1b22b5ce90..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} -Object.defineProperty(exports, "__esModule", { value: true }); -__export(require("./simple-module")); diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/package.json deleted file mode 100644 index 59d87df350..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@opentelemetry/plugin-simple-module", - "version": "0.0.1" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/simple-module.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/simple-module.js deleted file mode 100644 index 67e8f838d4..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-simple-module/simple-module.js +++ /dev/null @@ -1,24 +0,0 @@ -Object.defineProperty(exports, "__esModule", { value: true }); -const core_1 = require("@opentelemetry/core"); -const shimmer = require("shimmer"); - -class SimpleModulePlugin extends core_1.BasePlugin { - constructor() { - super(); - this.moduleName = 'simple-module'; - } - - patch() { - shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply()); - shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1); - return this._moduleExports; - } - - unpatch() { - shimmer.unwrap(this._moduleExports, 'name'); - shimmer.unwrap(this._moduleExports, 'value'); - } -} -exports.SimpleModulePlugin = SimpleModulePlugin; -const plugin = new SimpleModulePlugin(); -exports.plugin = plugin; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/index.js deleted file mode 100644 index 1b22b5ce90..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} -Object.defineProperty(exports, "__esModule", { value: true }); -__export(require("./simple-module")); diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/package.json deleted file mode 100644 index ca18bafa63..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@opentelemetry/plugin-supported-module", - "version": "0.0.1" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/simple-module.js b/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/simple-module.js deleted file mode 100644 index 6395bd261a..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/@opentelemetry/plugin-supported-module/simple-module.js +++ /dev/null @@ -1,25 +0,0 @@ -Object.defineProperty(exports, "__esModule", { value: true }); -const core_1 = require("@opentelemetry/core"); -const shimmer = require("shimmer"); - -class SimpleModulePlugin extends core_1.BasePlugin { - constructor() { - super(); - this.moduleName = 'supported-module'; - } - - patch() { - shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply()); - shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1); - return this._moduleExports; - } - - unpatch() { - shimmer.unwrap(this._moduleExports, 'name'); - shimmer.unwrap(this._moduleExports, 'value'); - } -} -exports.SimpleModulePlugin = SimpleModulePlugin; -const plugin = new SimpleModulePlugin(); -plugin.supportedVersions = ['^0.0.1']; -exports.plugin = plugin; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/index.js deleted file mode 100644 index 18c0f69a3b..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - name: () => 'already-module', - value: () => 0, -}; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/package.json deleted file mode 100644 index 7ae0ab8f09..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/already-require-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "already-module", - "version": "0.1.0" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/index.js deleted file mode 100644 index 4fe98dae33..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - name: () => 'notsupported-module', - value: () => 0, -}; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/package.json deleted file mode 100644 index 9494b2866e..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/notsupported-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "notsupported-module", - "version": "0.0.1" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/index.js deleted file mode 100644 index 35a4110c28..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - name: () => 'random-module', - value: () => 0, -}; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/package.json deleted file mode 100644 index a5c840081b..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/random-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "random-module", - "version": "0.1.0" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/index.js deleted file mode 100644 index 8ec2e77ffd..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - name: () => 'simple-module', - value: () => 0, -}; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/package.json deleted file mode 100644 index 2eba36a5bd..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/simple-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "simple-module", - "version": "0.1.0" -} diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/index.js b/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/index.js deleted file mode 100644 index 090d0db5fb..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - name: () => 'supported-module', - value: () => 0, -}; diff --git a/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/package.json b/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/package.json deleted file mode 100644 index ffd520afda..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/node_modules/supported-module/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "supported-module", - "version": "0.0.1" -} diff --git a/packages/opentelemetry-node/test/instrumentation/utils.test.ts b/packages/opentelemetry-node/test/instrumentation/utils.test.ts deleted file mode 100644 index 06ccdd12e0..0000000000 --- a/packages/opentelemetry-node/test/instrumentation/utils.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { NoopLogger } from '@opentelemetry/api'; -import * as assert from 'assert'; -import * as path from 'path'; -import * as utils from '../../src/instrumentation/utils'; - -const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules'); -const TEST_MODULES: Array<{ name: string; version: string | null }> = [ - { - name: 'simple-module', - version: '0.1.0', - }, - { - name: 'nonexistent-module', - version: null, - }, - { - name: 'http', - version: null, - }, -]; - -describe('Instrumentation#utils', () => { - const logger = new NoopLogger(); - - before(() => { - utils.searchPathForTest(INSTALLED_PLUGINS_PATH); - }); - - describe('getPackageVersion', () => { - TEST_MODULES.forEach(testCase => { - it(`should return ${testCase.version} for ${testCase.name}`, () => { - assert.strictEqual( - utils.getPackageVersion(logger, testCase.name), - testCase.version - ); - }); - }); - }); - describe('isSupportedVersion', () => { - const version = '1.0.1'; - - it('should return true when supportedVersions is not defined', () => { - assert.strictEqual(utils.isSupportedVersion('1.0.0', undefined), true); - }); - - [ - ['1.X'], - [version], - ['1.X.X', '3.X.X'], - ['^1.0.0'], - ['~1.0.0', '^0.1.0'], - ['*'], - ['>1.0.0'], - [], - ].forEach(supportedVersion => { - it(`should return true when version is equal to ${version} and supportedVersions is equal to ${supportedVersion}`, () => { - assert.strictEqual( - utils.isSupportedVersion(version, supportedVersion), - true - ); - }); - }); - - [['0.X'], ['0.1.0'], ['0.X.X'], ['^0.1.0'], ['1.0.0'], ['<1.0.0']].forEach( - supportedVersion => { - it(`should return false when version is equal to ${version} and supportedVersions is equal to ${supportedVersion}`, () => { - assert.strictEqual( - utils.isSupportedVersion(version, supportedVersion), - false - ); - }); - } - ); - - it("should return false when version is equal to null and supportedVersions is equal to '*'", () => { - assert.strictEqual(utils.isSupportedVersion(null as any, ['*']), false); - }); - }); -}); diff --git a/packages/opentelemetry-sdk-node/package.json b/packages/opentelemetry-sdk-node/package.json index 1dc3f7f2d0..417953ed1e 100644 --- a/packages/opentelemetry-sdk-node/package.json +++ b/packages/opentelemetry-sdk-node/package.json @@ -44,6 +44,7 @@ "@opentelemetry/api-metrics": "^0.16.0", "@opentelemetry/context-base": "^0.16.0", "@opentelemetry/core": "^0.16.0", + "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/metrics": "^0.16.0", "@opentelemetry/node": "^0.16.0", "@opentelemetry/resource-detector-aws": "^0.16.0", diff --git a/packages/opentelemetry-sdk-node/src/sdk.ts b/packages/opentelemetry-sdk-node/src/sdk.ts index 3290993f31..11fb7a5b77 100644 --- a/packages/opentelemetry-sdk-node/src/sdk.ts +++ b/packages/opentelemetry-sdk-node/src/sdk.ts @@ -18,6 +18,10 @@ import { TextMapPropagator } from '@opentelemetry/api'; import { metrics } from '@opentelemetry/api-metrics'; import { ContextManager } from '@opentelemetry/context-base'; import { MeterConfig, MeterProvider } from '@opentelemetry/metrics'; +import { + InstrumentationOption, + registerInstrumentations, +} from '@opentelemetry/instrumentation'; import { NodeTracerConfig, NodeTracerProvider } from '@opentelemetry/node'; import { awsEc2Detector } from '@opentelemetry/resource-detector-aws'; import { gcpDetector } from '@opentelemetry/resource-detector-gcp'; @@ -39,6 +43,7 @@ export class NodeSDK { contextManager?: ContextManager; textMapPropagator?: TextMapPropagator; }; + private _instrumentations: InstrumentationOption[]; private _meterProviderConfig?: MeterConfig; private _resource: Resource; @@ -65,9 +70,6 @@ export class NodeSDK { if (configuration.logger) { tracerProviderConfig.logger = configuration.logger; } - if (configuration.plugins) { - tracerProviderConfig.plugins = configuration.plugins; - } if (configuration.sampler) { tracerProviderConfig.sampler = configuration.sampler; } @@ -108,8 +110,16 @@ export class NodeSDK { this.configureMeterProvider(meterConfig); } - } + let instrumentations: InstrumentationOption[] = []; + if (configuration.instrumentations) { + instrumentations = configuration.instrumentations; + } else if (configuration.plugins) { + console.error('plugins option is deprecated'); + instrumentations = configuration.plugins; + } + this._instrumentations = instrumentations; + } /** Set configurations required to register a NodeTracerProvider */ public configureTracerProvider( tracerConfig: NodeTracerConfig, @@ -178,6 +188,12 @@ export class NodeSDK { metrics.setGlobalMeterProvider(meterProvider); } + + registerInstrumentations({ + instrumentations: this._instrumentations, + tracerProvider: this._tracerProvider, + meterProvider: this._meterProvider, + }); } public shutdown(): Promise { diff --git a/packages/opentelemetry-sdk-node/src/types.ts b/packages/opentelemetry-sdk-node/src/types.ts index 43a9274698..d3da15274b 100644 --- a/packages/opentelemetry-sdk-node/src/types.ts +++ b/packages/opentelemetry-sdk-node/src/types.ts @@ -15,7 +15,8 @@ */ import type { ContextManager } from '@opentelemetry/context-base'; -import type { api, core, metrics, node, resources, tracing } from '.'; +import type { api, core, metrics, resources, tracing } from '.'; +import { InstrumentationOption } from '@opentelemetry/instrumentation'; export interface NodeSDKConfiguration { autoDetectResources: boolean; @@ -27,7 +28,9 @@ export interface NodeSDKConfiguration { metricProcessor: metrics.Processor; metricExporter: metrics.MetricExporter; metricInterval: number; - plugins: node.Plugins; + /* Deprecated */ + plugins: InstrumentationOption[]; + instrumentations: InstrumentationOption[]; resource: resources.Resource; sampler: api.Sampler; spanProcessor: tracing.SpanProcessor; diff --git a/packages/opentelemetry-sdk-node/test/sdk.test.ts b/packages/opentelemetry-sdk-node/test/sdk.test.ts index c5fbbdc724..06e397d25d 100644 --- a/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -31,7 +31,7 @@ import { NoopContextManager } from '@opentelemetry/context-base'; import { CompositePropagator } from '@opentelemetry/core'; import { ConsoleMetricExporter, MeterProvider } from '@opentelemetry/metrics'; import { NodeTracerProvider } from '@opentelemetry/node'; -import * as NodeConfig from '@opentelemetry/node/build/src/config'; +import * as NodeConfig from '@opentelemetry/instrumentation/build/src/platform/node/old/autoLoader'; import { awsEc2Detector } from '@opentelemetry/resource-detector-aws'; import { resetIsAvailableCache } from '@opentelemetry/resource-detector-gcp'; import { Resource } from '@opentelemetry/resources'; diff --git a/packages/opentelemetry-sdk-node/tsconfig.json b/packages/opentelemetry-sdk-node/tsconfig.json index 1656d30753..e3291a2cb0 100644 --- a/packages/opentelemetry-sdk-node/tsconfig.json +++ b/packages/opentelemetry-sdk-node/tsconfig.json @@ -24,6 +24,9 @@ { "path": "../opentelemetry-core" }, + { + "path": "../opentelemetry-instrumentation" + }, { "path": "../opentelemetry-metrics" }, diff --git a/packages/opentelemetry-web/README.md b/packages/opentelemetry-web/README.md index b15e78190b..733696c8b8 100644 --- a/packages/opentelemetry-web/README.md +++ b/packages/opentelemetry-web/README.md @@ -16,7 +16,7 @@ This package exposes a class `WebTracerProvider` that will be able to automatica See the example how to use it. -OpenTelemetry comes with a growing number of instrumentation plugins for well know modules (see [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins)) and an API to create custom plugins (see [the plugin developer guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/plugin-guide.md)). +OpenTelemetry comes with a growing number of instrumentations for well know modules (see [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins)) and an API to create custom instrumentations (see [the instrumentation developer guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/instrumentation-guide.md)). Web Tracer currently supports one plugin for document load. Unlike Node Tracer (`NodeTracerProvider`), the plugins needs to be initialised and passed in configuration. @@ -37,27 +37,22 @@ import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing import { WebTracerProvider } from '@opentelemetry/web'; import { DocumentLoad } from '@opentelemetry/plugin-document-load'; import { ZoneContextManager } from '@opentelemetry/context-zone'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; -// Minimum required setup - supports only synchronous operations -const provider = new WebTracerProvider({ - plugins: [ - new DocumentLoad() - ] -}); - +const provider = new WebTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.register(); -const providerWithZone = new WebTracerProvider({ - plugins: [ - new DocumentLoad() - ] +provider.register({ + // Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional + contextManager: new ZoneContextManager(), }); -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -// Changing default contextManager to use ZoneContextManager - supports asynchronous operations -providerWithZone.register({ - contextManager: new ZoneContextManager(), +// Registering instrumentations / plugins +registerInstrumentations({ + instrumentations: [ + new DocumentLoad(), + ], + tracerProvider: provider, }); ``` diff --git a/packages/opentelemetry-web/package.json b/packages/opentelemetry-web/package.json index 54dd6d8323..34e256d721 100644 --- a/packages/opentelemetry-web/package.json +++ b/packages/opentelemetry-web/package.json @@ -77,7 +77,6 @@ "@opentelemetry/api": "^0.16.0", "@opentelemetry/context-base": "^0.16.0", "@opentelemetry/core": "^0.16.0", - "@opentelemetry/instrumentation": "^0.16.0", "@opentelemetry/semantic-conventions": "^0.16.0", "@opentelemetry/tracing": "^0.16.0" } diff --git a/packages/opentelemetry-web/src/WebTracerProvider.ts b/packages/opentelemetry-web/src/WebTracerProvider.ts index 9d6fbd455c..405935e78e 100644 --- a/packages/opentelemetry-web/src/WebTracerProvider.ts +++ b/packages/opentelemetry-web/src/WebTracerProvider.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { BasePlugin } from '@opentelemetry/core'; -import { InstrumentationBase } from '@opentelemetry/instrumentation'; import { BasicTracerProvider, SDKRegistrationConfig, @@ -30,7 +28,7 @@ export interface WebTracerConfig extends TracerConfig { /** * plugins to be used with tracer, they will be enabled automatically */ - plugins?: (BasePlugin | InstrumentationBase)[]; + plugins?: unknown[]; } /** @@ -42,21 +40,14 @@ export class WebTracerProvider extends BasicTracerProvider { * @param config Web Tracer config */ constructor(config: WebTracerConfig = {}) { - if (typeof config.plugins === 'undefined') { - config.plugins = []; + if (typeof config.plugins !== 'undefined') { + console.warn( + 'plugins option was removed, please use' + + ' "registerInstrumentations" to load plugins' + ); } super(config); - for (const plugin of config.plugins) { - const instrumentation = (plugin as unknown) as InstrumentationBase; - if (typeof instrumentation.setTracerProvider === 'function') { - instrumentation.setTracerProvider(this); - instrumentation.enable(); - } else { - plugin.enable([], this, this.logger); - } - } - if ((config as SDKRegistrationConfig).contextManager) { throw ( 'contextManager should be defined in register method not in' + diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index 7cf43c2767..10b1f5e274 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -17,8 +17,6 @@ import { context, NoopLogger, getSpan, setSpan } from '@opentelemetry/api'; import { ContextManager } from '@opentelemetry/context-base'; import { ZoneContextManager } from '@opentelemetry/context-zone'; -import { BasePlugin } from '@opentelemetry/core'; -import { InstrumentationBase } from '@opentelemetry/instrumentation'; import { B3Propagator } from '@opentelemetry/propagator-b3'; import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources'; import { Span, Tracer } from '@opentelemetry/tracing'; @@ -27,25 +25,6 @@ import * as sinon from 'sinon'; import { WebTracerConfig } from '../src'; import { WebTracerProvider } from '../src/WebTracerProvider'; -class DummyPlugin extends BasePlugin { - constructor() { - super('dummy'); - } - moduleName = 'dummy'; - - patch() {} - unpatch() {} -} - -class DummyInstrumentation extends InstrumentationBase { - constructor() { - super('dummy', '1'); - } - enable() {} - disable() {} - init() {} -} - describe('WebTracerProvider', () => { describe('constructor', () => { let defaultOptions: WebTracerConfig; @@ -69,24 +48,19 @@ describe('WebTracerProvider', () => { assert.ok(tracer instanceof Tracer); }); - it('should enable all plugins', () => { - const dummyPlugin1 = new DummyPlugin(); - const dummyPlugin2 = new DummyPlugin(); - const dummyPlugin3 = new DummyInstrumentation(); - const spyEnable1 = sinon.spy(dummyPlugin1, 'enable'); - const spyEnable2 = sinon.spy(dummyPlugin2, 'enable'); - const spyEnable3 = sinon.spy(dummyPlugin3, 'enable'); - const spySetTracerProvider = sinon.spy(dummyPlugin3, 'setTracerProvider'); + it('should show warning when plugins are defined', () => { + const dummyPlugin1 = {}; + const spyWarn = sinon.spy(window.console, 'warn'); - const plugins = [dummyPlugin1, dummyPlugin2, dummyPlugin3]; + const plugins = [dummyPlugin1]; const options = { plugins }; new WebTracerProvider(options); - assert.ok(spyEnable1.calledOnce === true); - assert.ok(spyEnable2.calledOnce === true); - assert.ok(spyEnable3.calledOnce === true); - assert.ok(spySetTracerProvider.calledOnce === true); + assert.strictEqual( + spyWarn.args[0][0], + 'plugins option was removed, please use "registerInstrumentations" to load plugins' + ); }); it('should work without default context manager', () => { diff --git a/packages/opentelemetry-web/tsconfig.json b/packages/opentelemetry-web/tsconfig.json index 950d91905b..72e685708c 100644 --- a/packages/opentelemetry-web/tsconfig.json +++ b/packages/opentelemetry-web/tsconfig.json @@ -22,9 +22,6 @@ { "path": "../opentelemetry-core" }, - { - "path": "../opentelemetry-instrumentation" - }, { "path": "../opentelemetry-propagator-b3" },