From 18c6aa4f19b899a9c6041b307cf58bac359b7609 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 9 Jan 2020 11:29:38 -0500 Subject: [PATCH] Named Tracers / Tracer Registry (#582) * feat: spike of named tracer registry * chore: mysql/mongo tracer registry support * fix: lint * chore: add getTracer back * chore: change default tracer name to empty string * fix: lint * chore: update examples for registry * chore(tracer-registry): make name required * chore: lint * chore: update examples for required tracer name * chore: remove unused tracer delegate * chore: remove references to basic tracer * chore: remove references to NodeTracer * chore: update xhr for tracer registry * chore: update tracer names to match package names * chore: add version script to all packages * chore: update plugins to use version script * chore: add jsdoc to noop tracer registry * chore: update ioredis for tracer registry * chore: update pg pool for tracer registry * fix: lint * chore: fix tests * chore: lint * chore: lint Co-authored-by: Mayur Kale --- .gitignore | 1 + benchmark/tracer.js | 18 +-- examples/basic-tracer-node/index.js | 15 +- examples/basic-tracer-node/multi_exporter.js | 19 +-- examples/dns/client.js | 2 +- examples/dns/setup.js | 10 +- examples/grpc/client.js | 2 +- examples/grpc/server.js | 2 +- examples/grpc/setup.js | 10 +- .../grpc_dynamic_codegen/capitalize_client.js | 2 +- .../grpc_dynamic_codegen/capitalize_server.js | 2 +- examples/grpc_dynamic_codegen/setup.js | 10 +- examples/http/client.js | 2 +- examples/http/server.js | 2 +- examples/http/setup.js | 10 +- examples/https/client.js | 4 +- examples/https/server.js | 2 +- examples/https/setup.js | 10 +- examples/mysql/client.js | 2 +- examples/mysql/server.js | 2 +- examples/mysql/setup.js | 12 +- examples/opentracing-shim/shim.js | 8 +- examples/redis/client.js | 2 +- examples/redis/server.js | 2 +- examples/redis/setup.js | 10 +- .../examples/document-load/index.js | 39 ++--- packages/opentelemetry-core/src/index.ts | 2 +- .../src/trace/NoopTracer.ts | 2 + .../src/trace/NoopTracerRegistry.ts | 28 ++++ .../src/trace/TracerDelegate.ts | 101 ------------ .../src/trace/globaltracer-utils.ts | 26 +++- .../src/trace/instrumentation/BasePlugin.ts | 13 +- .../test/trace/BasePlugin.test.ts | 11 +- .../test/trace/TracerDelegate.test.ts | 117 -------------- .../test/trace/globaltracer-utils.test.ts | 26 ++-- .../README.md | 8 +- .../test/transform.test.ts | 6 +- packages/opentelemetry-node/README.md | 32 ++-- .../{NodeTracer.ts => NodeTracerRegistry.ts} | 4 +- packages/opentelemetry-node/src/config.ts | 4 +- packages/opentelemetry-node/src/index.ts | 2 +- .../src/instrumentation/PluginLoader.ts | 11 +- .../test/NodeTracer.test.ts | 146 +++++++++++------- .../test/instrumentation/PluginLoader.test.ts | 30 ++-- packages/opentelemetry-plugin-dns/README.md | 6 +- packages/opentelemetry-plugin-dns/src/dns.ts | 23 +-- .../test/functionals/dns-disable.test.ts | 9 +- .../test/functionals/dns-enable.test.ts | 8 +- .../test/functionals/utils.test.ts | 10 +- .../test/integrations/dns-lookup.test.ts | 10 +- .../integrations/dnspromise-lookup.test.ts | 10 +- .../src/documentLoad.ts | 5 +- .../test/documentLoad.test.ts | 32 ++-- packages/opentelemetry-plugin-grpc/README.md | 8 +- .../opentelemetry-plugin-grpc/src/grpc.ts | 26 ++-- .../test/grpc.test.ts | 56 +++---- packages/opentelemetry-plugin-http/README.md | 8 +- .../opentelemetry-plugin-http/src/http.ts | 21 +-- .../test/functionals/http-disable.test.ts | 29 ++-- .../test/functionals/http-enable.test.ts | 24 +-- .../test/functionals/http-package.test.ts | 8 +- .../test/functionals/utils.test.ts | 6 +- .../test/integrations/http-enable.test.ts | 8 +- packages/opentelemetry-plugin-https/README.md | 8 +- .../test/functionals/https-disable.test.ts | 17 +- .../test/functionals/https-enable.test.ts | 13 +- .../test/functionals/https-package.test.ts | 26 ++-- .../test/integrations/https-enable.test.ts | 13 +- .../test/utils/assertSpan.ts | 8 +- .../src/ioredis.ts | 3 +- .../test/ioredis.test.ts | 65 ++++---- .../opentelemetry-plugin-mongodb/README.md | 8 +- .../src/mongodb.ts | 17 +- .../test/mongodb.test.ts | 46 +++--- .../tsconfig.json | 3 +- .../opentelemetry-plugin-mysql/src/mysql.ts | 8 +- .../test/mysql.test.ts | 104 ++++++------- .../src/pg-pool.ts | 3 +- .../test/pg-pool.test.ts | 30 ++-- .../opentelemetry-plugin-pg/src/pg.ts | 9 +- .../opentelemetry-plugin-pg/test/pg.test.ts | 9 +- packages/opentelemetry-plugin-redis/README.md | 8 +- .../opentelemetry-plugin-redis/src/redis.ts | 3 +- .../test/redis.test.ts | 9 +- .../src/xhr.ts | 7 +- .../test/xhr.test.ts | 22 ++- .../test/Shim.test.ts | 8 +- packages/opentelemetry-tracing/README.md | 17 +- .../src/BasicTracerRegistry.ts | 63 ++++++++ packages/opentelemetry-tracing/src/Span.ts | 6 +- .../src/{BasicTracer.ts => Tracer.ts} | 26 ++-- packages/opentelemetry-tracing/src/index.ts | 3 +- packages/opentelemetry-tracing/src/types.ts | 4 +- packages/opentelemetry-tracing/src/utility.ts | 6 +- ...er.test.ts => BasicTracerRegistry.test.ts} | 112 +++++++------- .../test/MultiSpanProcessor.test.ts | 4 +- .../opentelemetry-tracing/test/Span.test.ts | 6 +- .../test/export/BatchSpanProcessor.test.ts | 10 +- .../test/export/ConsoleSpanExporter.test.ts | 10 +- .../test/export/InMemorySpanExporter.test.ts | 28 ++-- .../test/export/SimpleSpanProcessor.test.ts | 18 ++- packages/opentelemetry-types/src/index.ts | 1 + .../src/trace/instrumentation/Plugin.ts | 6 +- .../src/trace/tracer_registry.ts | 31 ++++ .../{WebTracer.ts => WebTracerRegistry.ts} | 6 +- packages/opentelemetry-web/src/index.ts | 2 +- .../opentelemetry-web/test/WebTracer.test.ts | 29 ++-- 107 files changed, 975 insertions(+), 936 deletions(-) create mode 100644 packages/opentelemetry-core/src/trace/NoopTracerRegistry.ts delete mode 100644 packages/opentelemetry-core/src/trace/TracerDelegate.ts delete mode 100644 packages/opentelemetry-core/test/trace/TracerDelegate.test.ts rename packages/opentelemetry-node/src/{NodeTracer.ts => NodeTracerRegistry.ts} (92%) create mode 100644 packages/opentelemetry-tracing/src/BasicTracerRegistry.ts rename packages/opentelemetry-tracing/src/{BasicTracer.ts => Tracer.ts} (86%) rename packages/opentelemetry-tracing/test/{BasicTracer.test.ts => BasicTracerRegistry.test.ts} (80%) create mode 100644 packages/opentelemetry-types/src/trace/tracer_registry.ts rename packages/opentelemetry-web/src/{WebTracer.ts => WebTracerRegistry.ts} (88%) diff --git a/.gitignore b/.gitignore index f9d0089925..9900542847 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ docs #lerna .changelog +package.json.lerna_backup # OS generated files .DS_Store diff --git a/benchmark/tracer.js b/benchmark/tracer.js index 2dda2a8b68..83700b0171 100644 --- a/benchmark/tracer.js +++ b/benchmark/tracer.js @@ -2,26 +2,26 @@ const benchmark = require('./benchmark'); const opentelemetry = require('@opentelemetry/core'); -const { BasicTracer, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing'); -const { NodeTracer } = require('@opentelemetry/node'); +const { BasicTracerRegistry, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const exporter = new InMemorySpanExporter(); const logger = new opentelemetry.NoopLogger(); const setups = [ { - name: 'BasicTracer', - tracer: new BasicTracer({ logger }) + name: 'BasicTracerRegistry', + registry: new BasicTracerRegistry({ logger }) }, { - name: 'NodeTracer', - tracer: new NodeTracer({ logger }) + name: 'NodeTracerRegistry', + registry: new NodeTracerRegistry({ logger }) } ]; for (const setup of setups) { console.log(`Beginning ${setup.name} Benchmark...`); - const tracer = setup.tracer; + const tracer = setup.registry.getTracer("benchmark"); const suite = benchmark() .add('#startSpan', function () { const span = tracer.startSpan('op'); @@ -55,7 +55,7 @@ for (const setup of setups) { .add('#startSpan with SimpleSpanProcessor', function () { const simpleSpanProcessor = new SimpleSpanProcessor(exporter); - tracer.addSpanProcessor(simpleSpanProcessor); + registry.addSpanProcessor(simpleSpanProcessor); const span = tracer.startSpan('op'); span.end(); @@ -64,7 +64,7 @@ for (const setup of setups) { .add('#startSpan with BatchSpanProcessor', function () { const batchSpanProcessor = new BatchSpanProcessor(exporter); - tracer.addSpanProcessor(batchSpanProcessor); + registry.addSpanProcessor(batchSpanProcessor); const span = tracer.startSpan('op'); span.end(); batchSpanProcessor.shutdown(); diff --git a/examples/basic-tracer-node/index.js b/examples/basic-tracer-node/index.js index 61bbe33b54..086d1fe158 100644 --- a/examples/basic-tracer-node/index.js +++ b/examples/basic-tracer-node/index.js @@ -1,5 +1,5 @@ const opentelemetry = require('@opentelemetry/core'); -const { BasicTracer, SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { BasicTracerRegistry, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { CollectorExporter } = require('@opentelemetry/exporter-collector'); @@ -20,16 +20,17 @@ if (EXPORTER.toLowerCase().startsWith('z')) { exporter = new CollectorExporter(options); } -const tracer = new BasicTracer(); +const registry = new BasicTracerRegistry(); // Configure span processor to send spans to the provided exporter -tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); +registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); -// Initialize the OpenTelemetry APIs to use the BasicTracer bindings -opentelemetry.initGlobalTracer(tracer); +// Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings +opentelemetry.initGlobalTracerRegistry(registry); +const tracer = opentelemetry.getTracer('example-basic-tracer-node') // Create a span. A span must be closed. -const span = opentelemetry.getTracer().startSpan('main'); +const span = tracer.startSpan('main'); for (let i = 0; i < 10; i++) { doWork(span); } @@ -42,7 +43,7 @@ exporter.shutdown(); function doWork(parent) { // Start another span. In this example, the main method already started a // span, so that'll be the parent span, and this will be a child span. - const span = opentelemetry.getTracer().startSpan('doWork', { + const span = tracer.startSpan('doWork', { parent: parent }); diff --git a/examples/basic-tracer-node/multi_exporter.js b/examples/basic-tracer-node/multi_exporter.js index 6c12a24c57..2d7723397e 100644 --- a/examples/basic-tracer-node/multi_exporter.js +++ b/examples/basic-tracer-node/multi_exporter.js @@ -1,10 +1,10 @@ const opentelemetry = require('@opentelemetry/core'); -const { BasicTracer, BatchSpanProcessor, SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { BasicTracerRegistry, BatchSpanProcessor, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { CollectorExporter } = require('@opentelemetry/exporter-collector'); -const tracer = new BasicTracer(); +const registry = new BasicTracerRegistry(); const zipkinExporter = new ZipkinExporter({serviceName: 'basic-service'}); const jaegerExporter = new JaegerExporter({ @@ -14,21 +14,22 @@ const collectorExporter = new CollectorExporter({serviceName: 'basic-service'}); // It is recommended to use this BatchSpanProcessor for better performance // and optimization, especially in production. -tracer.addSpanProcessor(new BatchSpanProcessor(zipkinExporter, { +registry.addSpanProcessor(new BatchSpanProcessor(zipkinExporter, { bufferSize: 10 // This is added for example, default size is 100. })); // It is recommended to use SimpleSpanProcessor in case of Jaeger exporter as // it's internal client already handles the spans with batching logic. -tracer.addSpanProcessor(new SimpleSpanProcessor(jaegerExporter)); +registry.addSpanProcessor(new SimpleSpanProcessor(jaegerExporter)); -tracer.addSpanProcessor(new SimpleSpanProcessor(collectorExporter)); +registry.addSpanProcessor(new SimpleSpanProcessor(collectorExporter)); -// Initialize the OpenTelemetry APIs to use the BasicTracer bindings -opentelemetry.initGlobalTracer(tracer); +// Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings +opentelemetry.initGlobalTracerRegistry(registry); +const tracer = opentelemetry.getTracer('default'); // Create a span. A span must be closed. -const span = opentelemetry.getTracer().startSpan('main'); +const span = tracer.startSpan('main'); for (let i = 0; i < 10; i++) { doWork(span); } @@ -43,7 +44,7 @@ collectorExporter.shutdown(); function doWork(parent) { // Start another span. In this example, the main method already started a // span, so that'll be the parent span, and this will be a child span. - const span = opentelemetry.getTracer().startSpan('doWork', { + const span = tracer.startSpan('doWork', { parent: parent }); diff --git a/examples/dns/client.js b/examples/dns/client.js index 83399387ab..317b5b9e46 100644 --- a/examples/dns/client.js +++ b/examples/dns/client.js @@ -10,7 +10,7 @@ const config = require('./setup'); config.setupTracerAndExporters('dns-client-service'); const dns = require('dns').promises; -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-dns'); /** A function which makes a dns lookup and handles response. */ function makeLookup() { diff --git a/examples/dns/setup.js b/examples/dns/setup.js index e7e40d199e..f5ef407f2a 100644 --- a/examples/dns/setup.js +++ b/examples/dns/setup.js @@ -1,14 +1,14 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const EXPORTER = process.env.EXPORTER || ''; function setupTracerAndExporters(service) { - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({       plugins: {           dns: {             enabled: true, @@ -30,10 +30,10 @@ function setupTracerAndExporters(service) { }); } - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/grpc/client.js b/examples/grpc/client.js index 585f61873c..4bc65bc976 100644 --- a/examples/grpc/client.js +++ b/examples/grpc/client.js @@ -14,7 +14,7 @@ const grpc = require('grpc'); const messages = require('./helloworld_pb'); const services = require('./helloworld_grpc_pb'); const PORT = 50051; -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-grpc-client'); /** A function which makes requests and handles response. */ function main() { diff --git a/examples/grpc/server.js b/examples/grpc/server.js index b1e3c407f6..2a411ba40b 100644 --- a/examples/grpc/server.js +++ b/examples/grpc/server.js @@ -10,7 +10,7 @@ const config = require('./setup'); config.setupTracerAndExporters('grpc-server-service'); const grpc = require('grpc'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-grpc-server'); const messages = require('./helloworld_pb'); const services = require('./helloworld_grpc_pb'); diff --git a/examples/grpc/setup.js b/examples/grpc/setup.js index 162884ffcb..7a7fc3eafe 100644 --- a/examples/grpc/setup.js +++ b/examples/grpc/setup.js @@ -1,14 +1,14 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const EXPORTER = process.env.EXPORTER || ''; function setupTracerAndExporters(service) { - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ plugins: { grpc: { enabled: true, @@ -29,10 +29,10 @@ function setupTracerAndExporters(service) { }); } - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/grpc_dynamic_codegen/capitalize_client.js b/examples/grpc_dynamic_codegen/capitalize_client.js index 0b7b360f0e..a994307854 100644 --- a/examples/grpc_dynamic_codegen/capitalize_client.js +++ b/examples/grpc_dynamic_codegen/capitalize_client.js @@ -13,7 +13,7 @@ const path = require('path'); const grpc = require('grpc'); const protoLoader = require('@grpc/proto-loader'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-grpc-capitalize-client'); const PROTO_PATH = path.join(__dirname, 'protos/defs.proto'); const PROTO_OPTIONS = { keepCase: true, enums: String, defaults: true, oneofs: true }; diff --git a/examples/grpc_dynamic_codegen/capitalize_server.js b/examples/grpc_dynamic_codegen/capitalize_server.js index c18731d4c7..79dcd3c0fe 100644 --- a/examples/grpc_dynamic_codegen/capitalize_server.js +++ b/examples/grpc_dynamic_codegen/capitalize_server.js @@ -19,7 +19,7 @@ const PROTO_OPTIONS = { keepCase: true, enums: String, defaults: true, oneofs: t const definition = protoLoader.loadSync(PROTO_PATH, PROTO_OPTIONS); const rpcProto = grpc.loadPackageDefinition(definition).rpc; -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-grpc-capitalize-server'); /** Implements the Capitalize RPC method. */ function capitalize(call, callback) { diff --git a/examples/grpc_dynamic_codegen/setup.js b/examples/grpc_dynamic_codegen/setup.js index f738c610fa..4fd8b0a8b6 100644 --- a/examples/grpc_dynamic_codegen/setup.js +++ b/examples/grpc_dynamic_codegen/setup.js @@ -1,14 +1,14 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const EXPORTER = process.env.EXPORTER || ''; function setupTracerAndExporters(service) { - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ plugins: { grpc: { enabled: true, @@ -31,10 +31,10 @@ function setupTracerAndExporters(service) { // It is recommended to use this `BatchSpanProcessor` for better performance // and optimization, especially in production. - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/http/client.js b/examples/http/client.js index aa812785a1..8b299b98ff 100644 --- a/examples/http/client.js +++ b/examples/http/client.js @@ -10,7 +10,7 @@ const config = require('./setup'); config.setupTracerAndExporters('http-client-service'); const http = require('http'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-http-client'); /** A function which makes requests and handles response. */ function makeRequest() { diff --git a/examples/http/server.js b/examples/http/server.js index 322a144a65..d3c0046bf9 100644 --- a/examples/http/server.js +++ b/examples/http/server.js @@ -9,7 +9,7 @@ const config = require('./setup'); config.setupTracerAndExporters('http-server-service'); const http = require('http'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-http-server'); /** Starts a HTTP server that receives requests on sample server port. */ function startServer (port) { diff --git a/examples/http/setup.js b/examples/http/setup.js index abe667f064..770cdd5dfd 100644 --- a/examples/http/setup.js +++ b/examples/http/setup.js @@ -1,14 +1,14 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const EXPORTER = process.env.EXPORTER || ''; function setupTracerAndExporters(service) { - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); let exporter; if (EXPORTER.toLowerCase().startsWith('z')) { @@ -21,10 +21,10 @@ function setupTracerAndExporters(service) { }); } - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/https/client.js b/examples/https/client.js index aef9966d31..40ebc94d3f 100644 --- a/examples/https/client.js +++ b/examples/https/client.js @@ -9,7 +9,7 @@ const config = require('./setup'); config.setupTracerAndExporters('https-client-service'); const https = require('https'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-https-client'); /** A function which makes requests and handles response. */ function makeRequest() { @@ -31,7 +31,7 @@ function makeRequest() { }); }); }); - + // The process must live for at least the interval past any traces that // must be exported, or some risk being lost if they are recorded after the // last export. diff --git a/examples/https/server.js b/examples/https/server.js index 1d6d208860..7280c8f61f 100644 --- a/examples/https/server.js +++ b/examples/https/server.js @@ -10,7 +10,7 @@ const config = require('./setup'); config.setupTracerAndExporters('https-server-service'); const https = require('https'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-https-server'); /** Starts a HTTPs server that receives requests on sample server port. */ function startServer (port) { diff --git a/examples/https/setup.js b/examples/https/setup.js index d4433c20bd..ef426a90b5 100644 --- a/examples/https/setup.js +++ b/examples/https/setup.js @@ -1,7 +1,7 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); @@ -9,7 +9,7 @@ const EXPORTER = process.env.EXPORTER || ''; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; function setupTracerAndExporters(service) { let exporter; - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); if (EXPORTER.toLowerCase().startsWith('z')) { exporter = new ZipkinExporter({ @@ -21,10 +21,10 @@ function setupTracerAndExporters(service) { }); } - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/mysql/client.js b/examples/mysql/client.js index 8455511268..e080ab994a 100644 --- a/examples/mysql/client.js +++ b/examples/mysql/client.js @@ -10,7 +10,7 @@ const config = require('./setup'); config.setupTracerAndExporters('http-client-service'); const http = require('http'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-mysql-http-client'); /** A function which makes requests and handles response. */ function makeRequest() { diff --git a/examples/mysql/server.js b/examples/mysql/server.js index 0dc6c10e9c..1ba4eb7258 100644 --- a/examples/mysql/server.js +++ b/examples/mysql/server.js @@ -11,7 +11,7 @@ config.setupTracerAndExporters('http-mysql-server-service'); const mysql = require('mysql'); const http = require('http'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-mysql-http-server'); const pool = mysql.createPool({ host : 'localhost', diff --git a/examples/mysql/setup.js b/examples/mysql/setup.js index a5f5303c57..e3f9ce3f41 100644 --- a/examples/mysql/setup.js +++ b/examples/mysql/setup.js @@ -1,13 +1,13 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); function setupTracerAndExporters(service) { - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ plugins: { mysql: { enabled: true, @@ -20,15 +20,15 @@ function setupTracerAndExporters(service) { } }); - tracer.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({ + registry.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({ serviceName: service, }))); - tracer.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({ + registry.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({ serviceName: service, }))); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/opentracing-shim/shim.js b/examples/opentracing-shim/shim.js index 8579eb73a4..8efb1c2a8b 100644 --- a/examples/opentracing-shim/shim.js +++ b/examples/opentracing-shim/shim.js @@ -1,17 +1,17 @@ "use strict"; -const { NodeTracer } = require("@opentelemetry/node"); +const { NodeTracerRegistry } = require("@opentelemetry/node"); const { SimpleSpanProcessor } = require("@opentelemetry/tracing"); const { JaegerExporter } = require("@opentelemetry/exporter-jaeger"); const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); const { TracerShim } = require("@opentelemetry/shim-opentracing"); function shim(serviceName) { - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); - tracer.addSpanProcessor(new SimpleSpanProcessor(getExporter(serviceName))); + registry.addSpanProcessor(new SimpleSpanProcessor(getExporter(serviceName))); - return new TracerShim(tracer); + return new TracerShim(registry.getTracer("opentracing-shim")); } function getExporter(serviceName) { diff --git a/examples/redis/client.js b/examples/redis/client.js index 8215c8e575..191effe612 100644 --- a/examples/redis/client.js +++ b/examples/redis/client.js @@ -4,7 +4,7 @@ const opentelemetry = require('@opentelemetry/core'); const types = require('@opentelemetry/types'); const config = require('./setup'); config.setupTracerAndExporters('redis-client-service'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-redis-client'); const axios = require('axios').default; function makeRequest() { diff --git a/examples/redis/server.js b/examples/redis/server.js index 535df1c014..33744b2f74 100644 --- a/examples/redis/server.js +++ b/examples/redis/server.js @@ -4,7 +4,7 @@ const opentelemetry = require('@opentelemetry/core'); const config = require('./setup'); config.setupTracerAndExporters('redis-server-service'); -const tracer = opentelemetry.getTracer(); +const tracer = opentelemetry.getTracer('example-redis-server'); // Require in rest of modules const express = require('express'); diff --git a/examples/redis/setup.js b/examples/redis/setup.js index abe667f064..770cdd5dfd 100644 --- a/examples/redis/setup.js +++ b/examples/redis/setup.js @@ -1,14 +1,14 @@ 'use strict'; const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const EXPORTER = process.env.EXPORTER || ''; function setupTracerAndExporters(service) { - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); let exporter; if (EXPORTER.toLowerCase().startsWith('z')) { @@ -21,10 +21,10 @@ function setupTracerAndExporters(service) { }); } - tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the BasicTracer bindings - opentelemetry.initGlobalTracer(tracer); + // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings + opentelemetry.initGlobalTracerRegistry(registry); } exports.setupTracerAndExporters = setupTracerAndExporters; diff --git a/examples/tracer-web/examples/document-load/index.js b/examples/tracer-web/examples/document-load/index.js index 63e07e8054..bd42b14797 100644 --- a/examples/tracer-web/examples/document-load/index.js +++ b/examples/tracer-web/examples/document-load/index.js @@ -1,26 +1,27 @@ import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; -import { WebTracer } from '@opentelemetry/web'; +import { WebTracerRegistry } from '@opentelemetry/web'; import { DocumentLoad } from '@opentelemetry/plugin-document-load'; import { ZoneScopeManager } from '@opentelemetry/scope-zone'; import { CollectorExporter } from '@opentelemetry/exporter-collector' -const webTracer = new WebTracer({ +const registry = new WebTracerRegistry({ plugins: [ new DocumentLoad() ] }); -webTracer.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +registry.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -const webTracerWithZone = new WebTracer({ +const registryWithZone = new WebTracerRegistry({ scopeManager: new ZoneScopeManager(), plugins: [ new DocumentLoad() ] }); -webTracerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -webTracerWithZone.addSpanProcessor(new SimpleSpanProcessor(new CollectorExporter())); +registryWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +registryWithZone.addSpanProcessor(new SimpleSpanProcessor(new CollectorExporter())); -console.log('Current span is window', webTracerWithZone.getCurrentSpan() === window); +const tracerWithZone = registryWithZone.getTracer('example-tracer-web'); +console.log('Current span is window', tracerWithZone.getCurrentSpan() === window); // example of keeping track of scope between async operations const prepareClickEvent = () => { @@ -28,33 +29,33 @@ const prepareClickEvent = () => { const url2 = 'https://raw.githubusercontent.com/open-telemetry/opentelemetry-js/master/packages/opentelemetry-web/package.json'; const element = document.getElementById('button1'); - let mainSpan = webTracerWithZone.startSpan('main-span'); - webTracerWithZone.bind(element, mainSpan); + let mainSpan = tracerWithZone.startSpan('main-span'); + tracerWithZone.bind(element, mainSpan); const onClick = () => { - const span1 = webTracerWithZone.startSpan(`files-series-info-1`, { - parent: webTracerWithZone.getCurrentSpan() + const span1 = tracerWithZone.startSpan(`files-series-info-1`, { + parent: tracerWithZone.getCurrentSpan() }); - const span2 = webTracerWithZone.startSpan(`files-series-info-2`, { - parent: webTracerWithZone.getCurrentSpan() + const span2 = tracerWithZone.startSpan(`files-series-info-2`, { + parent: tracerWithZone.getCurrentSpan() }); - webTracerWithZone.withSpan(span1, () => { + tracerWithZone.withSpan(span1, () => { getData(url1).then((data) => { - console.log('current span is span1', webTracerWithZone.getCurrentSpan() === span1); + console.log('current span is span1', tracerWithZone.getCurrentSpan() === span1); console.log('info from package.json', data.description, data.version); - webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); + tracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); span1.end(); }); }); - webTracerWithZone.withSpan(span2, () => { + tracerWithZone.withSpan(span2, () => { getData(url2).then((data) => { setTimeout(() => { - console.log('current span is span2', webTracerWithZone.getCurrentSpan() === span2); + console.log('current span is span2', tracerWithZone.getCurrentSpan() === span2); console.log('info from package.json', data.description, data.version); - webTracerWithZone.getCurrentSpan().addEvent('fetching-span2-completed'); + tracerWithZone.getCurrentSpan().addEvent('fetching-span2-completed'); span2.end(); }, 100); }); diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index 8d0d7f19d8..582101ab1e 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -27,10 +27,10 @@ export * from './trace/globaltracer-utils'; export * from './trace/instrumentation/BasePlugin'; export * from './trace/NoopSpan'; export * from './trace/NoopTracer'; +export * from './trace/NoopTracerRegistry'; export * from './trace/NoRecordingSpan'; export * from './trace/sampler/ProbabilitySampler'; export * from './trace/spancontext-utils'; -export * from './trace/TracerDelegate'; export * from './trace/TraceState'; export * from './metrics/NoopMeter'; export * from './utils/url'; diff --git a/packages/opentelemetry-core/src/trace/NoopTracer.ts b/packages/opentelemetry-core/src/trace/NoopTracer.ts index ea36a96ecf..bd569977fa 100644 --- a/packages/opentelemetry-core/src/trace/NoopTracer.ts +++ b/packages/opentelemetry-core/src/trace/NoopTracer.ts @@ -59,3 +59,5 @@ export class NoopTracer implements Tracer { return NOOP_HTTP_TEXT_FORMAT; } } + +export const noopTracer = new NoopTracer(); diff --git a/packages/opentelemetry-core/src/trace/NoopTracerRegistry.ts b/packages/opentelemetry-core/src/trace/NoopTracerRegistry.ts new file mode 100644 index 0000000000..701dd9d3bf --- /dev/null +++ b/packages/opentelemetry-core/src/trace/NoopTracerRegistry.ts @@ -0,0 +1,28 @@ +/*! + * Copyright 2019, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as types from '@opentelemetry/types'; +import { noopTracer } from './NoopTracer'; + +/** + * An implementation of the {@link TracerRegistry} which returns an impotent Tracer + * for all calls to `getTracer` + */ +export class NoopTracerRegistry implements types.TracerRegistry { + getTracer(_name?: string, _version?: string): types.Tracer { + return noopTracer; + } +} diff --git a/packages/opentelemetry-core/src/trace/TracerDelegate.ts b/packages/opentelemetry-core/src/trace/TracerDelegate.ts deleted file mode 100644 index 529862f98f..0000000000 --- a/packages/opentelemetry-core/src/trace/TracerDelegate.ts +++ /dev/null @@ -1,101 +0,0 @@ -/*! - * Copyright 2019, OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as types from '@opentelemetry/types'; -import { NoopTracer } from './NoopTracer'; - -// Acts a bridge to the global tracer that can be safely called before the -// global tracer is initialized. The purpose of the delegation is to avoid the -// sometimes nearly intractable initialization order problems that can arise in -// applications with a complex set of dependencies. Also allows for the tracer -// to be changed/disabled during runtime without needing to change reference -// to the global tracer -export class TracerDelegate implements types.Tracer { - private _currentTracer: types.Tracer; - private readonly _tracer: types.Tracer | null; - private readonly _fallbackTracer: types.Tracer; - - // Wrap a tracer with a TracerDelegate. Provided tracer becomes the default - // fallback tracer for when a global tracer has not been initialized - constructor(tracer?: types.Tracer, fallbackTracer?: types.Tracer) { - this._tracer = tracer || null; - this._fallbackTracer = fallbackTracer || new NoopTracer(); - this._currentTracer = this._tracer || this._fallbackTracer; // equivalent to this.start() - } - - // Begin using the user provided tracer. Stop always falling back to fallback tracer - start(): void { - this._currentTracer = this._tracer || this._fallbackTracer; - } - - // Stop the delegate from using the provided tracer. Begin to use the fallback tracer - stop(): void { - this._currentTracer = this._fallbackTracer; - } - - // -- Tracer interface implementation below -- // - - getCurrentSpan(): types.Span | undefined { - return this._currentTracer.getCurrentSpan.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ); - } - - bind(target: T, span?: types.Span): T { - return (this._currentTracer.bind.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ) as unknown) as T; - } - - startSpan(name: string, options?: types.SpanOptions): types.Span { - return this._currentTracer.startSpan.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ); - } - - withSpan ReturnType>( - span: types.Span, - fn: T - ): ReturnType { - return this._currentTracer.withSpan.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ); - } - - getBinaryFormat(): types.BinaryFormat { - return this._currentTracer.getBinaryFormat.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ); - } - - getHttpTextFormat(): types.HttpTextFormat { - return this._currentTracer.getHttpTextFormat.apply( - this._currentTracer, - // tslint:disable-next-line:no-any - arguments as any - ); - } -} diff --git a/packages/opentelemetry-core/src/trace/globaltracer-utils.ts b/packages/opentelemetry-core/src/trace/globaltracer-utils.ts index 9f16402e4d..f61180dc8f 100644 --- a/packages/opentelemetry-core/src/trace/globaltracer-utils.ts +++ b/packages/opentelemetry-core/src/trace/globaltracer-utils.ts @@ -15,21 +15,31 @@ */ import * as types from '@opentelemetry/types'; -import { TracerDelegate } from './TracerDelegate'; +import { NoopTracerRegistry } from './NoopTracerRegistry'; -let globalTracerDelegate = new TracerDelegate(); +let globalTracerRegistry: types.TracerRegistry = new NoopTracerRegistry(); /** * Set the current global tracer. Returns the initialized global tracer */ -export function initGlobalTracer(tracer: types.Tracer): types.Tracer { - return (globalTracerDelegate = new TracerDelegate(tracer)); +export function initGlobalTracerRegistry( + tracerRegistry: types.TracerRegistry +): types.TracerRegistry { + return (globalTracerRegistry = tracerRegistry); } /** - * Returns the global tracer + * Returns the global tracer registry. */ -export function getTracer(): types.Tracer { - // Return the global tracer delegate - return globalTracerDelegate; +export function getTracerRegistry(): types.TracerRegistry { + // Return the global tracer registry + return globalTracerRegistry; +} + +/** + * Returns a tracer from the global tracer registry. + */ +export function getTracer(name: string, version?: string): types.Tracer { + // Return the global tracer registry + return globalTracerRegistry.getTracer(name, version); } diff --git a/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts b/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts index 5a58aa6962..04ccc60b26 100644 --- a/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts +++ b/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts @@ -21,6 +21,7 @@ import { PluginConfig, PluginInternalFiles, PluginInternalFilesVersion, + TracerRegistry, } from '@opentelemetry/types'; import * as semver from 'semver'; import * as path from 'path'; @@ -39,14 +40,22 @@ export abstract class BasePlugin implements Plugin { protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports protected _config!: PluginConfig; + constructor( + protected readonly _tracerName: string, + protected readonly _tracerVersion?: string + ) {} + enable( moduleExports: T, - tracer: Tracer, + tracerRegistry: TracerRegistry, logger: Logger, config?: PluginConfig ): T { this._moduleExports = moduleExports; - this._tracer = tracer; + this._tracer = tracerRegistry.getTracer( + this._tracerName, + this._tracerVersion + ); this._logger = logger; this._internalFilesExports = this._loadInternalFilesExports(); if (config) this._config = config; diff --git a/packages/opentelemetry-core/test/trace/BasePlugin.test.ts b/packages/opentelemetry-core/test/trace/BasePlugin.test.ts index 6a67fdcc5a..2841903009 100644 --- a/packages/opentelemetry-core/test/trace/BasePlugin.test.ts +++ b/packages/opentelemetry-core/test/trace/BasePlugin.test.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { BasePlugin, NoopTracer, NoopLogger } from '../../src'; import * as assert from 'assert'; import * as path from 'path'; +import { BasePlugin, NoopLogger } from '../../src'; +import { NoopTracerRegistry } from '../../src/trace/NoopTracerRegistry'; import * as types from './fixtures/test-package/foo/bar/internal'; -const tracer = new NoopTracer(); +const registry = new NoopTracerRegistry(); const logger = new NoopLogger(); describe('BasePlugin', () => { @@ -28,7 +29,7 @@ describe('BasePlugin', () => { const testPackage = require('./fixtures/test-package'); const plugin = new TestPlugin(); assert.doesNotThrow(() => { - plugin.enable(testPackage, tracer, logger); + plugin.enable(testPackage, registry, logger); }); // @TODO: https://github.com/open-telemetry/opentelemetry-js/issues/285 @@ -61,6 +62,10 @@ class TestPlugin extends BasePlugin<{ [key: string]: Function }> { readonly version = '0.1.0'; readonly _basedir = basedir; + constructor() { + super('test-package.opentelemetry'); + } + protected readonly _internalFilesList = { '0.1.0': { internal: 'foo/bar/internal.js', diff --git a/packages/opentelemetry-core/test/trace/TracerDelegate.test.ts b/packages/opentelemetry-core/test/trace/TracerDelegate.test.ts deleted file mode 100644 index cc8772f263..0000000000 --- a/packages/opentelemetry-core/test/trace/TracerDelegate.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -/*! - * Copyright 2019, OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as assert from 'assert'; -import * as types from '@opentelemetry/types'; -import { TracerDelegate } from '../../src/trace/TracerDelegate'; -import { NoopTracer, NoopSpan } from '../../src'; -import { TraceFlags } from '@opentelemetry/types'; - -describe('TracerDelegate', () => { - const functions = [ - 'getCurrentSpan', - 'startSpan', - 'withSpan', - 'bind', - 'getBinaryFormat', - 'getHttpTextFormat', - ]; - const spanContext = { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.UNSAMPLED, - }; - - describe('constructor', () => { - it('should not crash with default constructor', () => { - functions.forEach(fn => { - const tracer = new TracerDelegate(); - try { - ((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function - assert.ok(true, fn); - } catch (err) { - if (err.message !== 'Method not implemented.') { - assert.ok(true, fn); - } - } - }); - }); - - it('should allow fallback tracer to be set', () => { - const dummyTracer = new DummyTracer(); - const tracerDelegate = new TracerDelegate(dummyTracer); - - tracerDelegate.startSpan('foo'); - assert.deepStrictEqual(dummyTracer.spyCounter, 1); - }); - - it('should use user provided tracer if provided', () => { - const dummyTracer = new DummyTracer(); - const tracerDelegate = new TracerDelegate(dummyTracer); - - tracerDelegate.startSpan('foo'); - assert.deepStrictEqual(dummyTracer.spyCounter, 1); - }); - }); - - describe('.start/.stop()', () => { - it('should use the fallback tracer when stop is called', () => { - const dummyTracerUser = new DummyTracer(); - const dummyTracerFallback = new DummyTracer(); - const tracerDelegate = new TracerDelegate( - dummyTracerUser, - dummyTracerFallback - ); - - tracerDelegate.stop(); - tracerDelegate.startSpan('fallback'); - assert.deepStrictEqual(dummyTracerUser.spyCounter, 0); - assert.deepStrictEqual(dummyTracerFallback.spyCounter, 1); - }); - - it('should use the user tracer when start is called', () => { - const dummyTracerUser = new DummyTracer(); - const dummyTracerFallback = new DummyTracer(); - const tracerDelegate = new TracerDelegate( - dummyTracerUser, - dummyTracerFallback - ); - - tracerDelegate.stop(); - tracerDelegate.startSpan('fallback'); - assert.deepStrictEqual(dummyTracerUser.spyCounter, 0); - assert.deepStrictEqual(dummyTracerFallback.spyCounter, 1); - - tracerDelegate.start(); - tracerDelegate.startSpan('user'); - assert.deepStrictEqual(dummyTracerUser.spyCounter, 1); - assert.deepStrictEqual( - dummyTracerFallback.spyCounter, - 1, - 'Only user tracer counter is incremented' - ); - }); - }); - - class DummyTracer extends NoopTracer { - spyCounter = 0; - - startSpan(name: string, options?: types.SpanOptions | undefined) { - this.spyCounter = this.spyCounter + 1; - return new NoopSpan(spanContext); - } - } -}); diff --git a/packages/opentelemetry-core/test/trace/globaltracer-utils.test.ts b/packages/opentelemetry-core/test/trace/globaltracer-utils.test.ts index 9d15b0d12f..4fc5ae0c05 100644 --- a/packages/opentelemetry-core/test/trace/globaltracer-utils.test.ts +++ b/packages/opentelemetry-core/test/trace/globaltracer-utils.test.ts @@ -17,11 +17,12 @@ import * as assert from 'assert'; import * as types from '@opentelemetry/types'; import { - getTracer, - initGlobalTracer, + getTracerRegistry, + initGlobalTracerRegistry, } from '../../src/trace/globaltracer-utils'; import { NoopTracer, NoopSpan } from '../../src'; import { TraceFlags } from '@opentelemetry/types'; +import { NoopTracerRegistry } from '../../src/trace/NoopTracerRegistry'; describe('globaltracer-utils', () => { const functions = [ @@ -32,13 +33,13 @@ describe('globaltracer-utils', () => { 'getHttpTextFormat', ]; - it('should expose a tracer via getTracer', () => { - const tracer = getTracer(); + it('should expose a tracer registry via getTracerRegistry', () => { + const tracer = getTracerRegistry(); assert.ok(tracer); assert.strictEqual(typeof tracer, 'object'); }); - describe('GlobalTracer', () => { + describe('GlobalTracerRegistry', () => { const spanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', spanId: '6e0c63257de34c92', @@ -47,12 +48,12 @@ describe('globaltracer-utils', () => { const dummySpan = new NoopSpan(spanContext); afterEach(() => { - initGlobalTracer(new NoopTracer()); + initGlobalTracerRegistry(new NoopTracerRegistry()); }); it('should not crash', () => { functions.forEach(fn => { - const tracer = getTracer(); + const tracer = getTracerRegistry(); try { ((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function assert.ok(true, fn); @@ -64,8 +65,9 @@ describe('globaltracer-utils', () => { }); }); - it('should use the global tracer', () => { - const tracer = initGlobalTracer(new TestTracer()); + it('should use the global tracer registry', () => { + initGlobalTracerRegistry(new TestTracerRegistry()); + const tracer = getTracerRegistry().getTracer('name'); const span = tracer.startSpan('test'); assert.deepStrictEqual(span, dummySpan); }); @@ -78,5 +80,11 @@ describe('globaltracer-utils', () => { return dummySpan; } } + + class TestTracerRegistry extends NoopTracerRegistry { + getTracer(_name: string, version?: string) { + return new TestTracer(); + } + } }); }); diff --git a/packages/opentelemetry-exporter-collector/README.md b/packages/opentelemetry-exporter-collector/README.md index 5e1c13f8e4..867b344692 100644 --- a/packages/opentelemetry-exporter-collector/README.md +++ b/packages/opentelemetry-exporter-collector/README.md @@ -35,18 +35,18 @@ opentelemetry.initGlobalTracer(tracer); ## Usage in Node ```js const opentelemetry = require('@opentelemetry/core'); -const { BasicTracer, SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { BasicTracerRegistry, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const collectorOptions = { url: '' // url is optional and can be omitted - default is http://localhost:55678/v1/trace }; -const tracer = new BasicTracer(); +const registry = new BasicTracerRegistry(); const exporter = new CollectorExporter(collectorOptions); -tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); +registry.addSpanProcessor(new SimpleSpanProcessor(exporter)); -opentelemetry.initGlobalTracer(tracer); +opentelemetry.initGlobalTracerRegistry(registry); ``` diff --git a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts index a7c0399d7e..641803902f 100644 --- a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts @@ -16,7 +16,7 @@ import * as assert from 'assert'; import * as types from '@opentelemetry/types'; -import { Span, BasicTracer } from '@opentelemetry/tracing'; +import { Span, BasicTracerRegistry } from '@opentelemetry/tracing'; import { NoopLogger, hrTimeToMicroseconds, @@ -32,9 +32,9 @@ import { import * as zipkinTypes from '../src/types'; const logger = new NoopLogger(); -const tracer = new BasicTracer({ +const tracer = new BasicTracerRegistry({ logger, -}); +}).getTracer('default'); const parentId = '5c1c63257de34c67'; const spanContext: types.SpanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', diff --git a/packages/opentelemetry-node/README.md b/packages/opentelemetry-node/README.md index 8a24c5b0d7..8e6c195c32 100644 --- a/packages/opentelemetry-node/README.md +++ b/packages/opentelemetry-node/README.md @@ -11,14 +11,14 @@ For manual instrumentation see the [@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing) package. ## How does automated instrumentation work? -This package exposes a `NodeTracer` that will automatically hook into the module loader of Node.js. +This package exposes a `NodeTracerRegistry` that will automatically hook into the module loader of Node.js. -For this to work, please make sure that `NodeTracer` is initialized before any other module of your application, (like `http` or `express`) is loaded. +For this to work, please make sure that `NodeTracerRegistry` 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/master/doc/plugin-guide.md)). -Whenever a module is loaded `NodeTracer` will check if a matching instrumentation plugin has been installed. +Whenever a module is loaded `NodeTracerRegistry` will check if a matching instrumentation plugin has been installed. > **Please note:** This module does *not* bundle any plugins. They need to be installed separately. @@ -34,7 +34,7 @@ This instrumentation code will automatically 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, `NodeTracer` exposes the same API as [@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing), allowing creating custom spans if needed. +Additionally to automated instrumentation, `NodeTracerRegistry` exposes the same API as [@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing), allowing creating custom spans if needed. ## Installation @@ -50,14 +50,14 @@ npm install --save @opentelemetry/plugin-https ## Usage -The following code will configure the `NodeTracer` to instrument `http` using `@opentelemetry/plugin-http`. +The following code will configure the `NodeTracerRegistry` to instrument `http` using `@opentelemetry/plugin-http`. ```js const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -// Create and configure NodeTracer -const tracer = new NodeTracer({ +// Create and configure NodeTracerRegistry +const registry = new NodeTracerRegistry({ plugins: { http: { enabled: true, @@ -68,25 +68,25 @@ const tracer = new NodeTracer({ } }); -// Initialize the tracer -opentelemetry.initGlobalTracer(tracer); +// Initialize the registry +opentelemetry.initGlobalTracerRegistry(registry); // Your application code - http will automatically be instrumented if // @opentelemetry/plugin-http is present const http = require('http'); ``` -To enable instrumentation for all [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins), create an instance of `NodeTracer` without providing any plugin configuration to the constructor. +To enable instrumentation for all [supported modules](https://github.com/open-telemetry/opentelemetry-js#plugins), create an instance of `NodeTracerRegistry` without providing any plugin configuration to the constructor. ```js const opentelemetry = require('@opentelemetry/core'); -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -// Create and initialize NodeTracer -const tracer = new NodeTracer(); +// Create and initialize NodeTracerRegistry +const registry = new NodeTracerRegistry(); -// Initialize the tracer -opentelemetry.initGlobalTracer(tracer); +// Initialize the registry +opentelemetry.initGlobalTracerRegistry(registry); // Your application code // ... diff --git a/packages/opentelemetry-node/src/NodeTracer.ts b/packages/opentelemetry-node/src/NodeTracerRegistry.ts similarity index 92% rename from packages/opentelemetry-node/src/NodeTracer.ts rename to packages/opentelemetry-node/src/NodeTracerRegistry.ts index 86591fd0ac..d2aac35236 100644 --- a/packages/opentelemetry-node/src/NodeTracer.ts +++ b/packages/opentelemetry-node/src/NodeTracerRegistry.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BasicTracer } from '@opentelemetry/tracing'; +import { BasicTracerRegistry } from '@opentelemetry/tracing'; import { AsyncHooksScopeManager } from '@opentelemetry/scope-async-hooks'; import { PluginLoader } from './instrumentation/PluginLoader'; import { NodeTracerConfig, DEFAULT_INSTRUMENTATION_PLUGINS } from './config'; @@ -22,7 +22,7 @@ import { NodeTracerConfig, DEFAULT_INSTRUMENTATION_PLUGINS } from './config'; /** * This class represents a node tracer with `async_hooks` module. */ -export class NodeTracer extends BasicTracer { +export class NodeTracerRegistry extends BasicTracerRegistry { private readonly _pluginLoader: PluginLoader; /** diff --git a/packages/opentelemetry-node/src/config.ts b/packages/opentelemetry-node/src/config.ts index 042c0c90eb..3d93b5bba5 100644 --- a/packages/opentelemetry-node/src/config.ts +++ b/packages/opentelemetry-node/src/config.ts @@ -15,12 +15,12 @@ */ import { Plugins } from './instrumentation/PluginLoader'; -import { BasicTracerConfig } from '@opentelemetry/tracing'; +import { TracerConfig } from '@opentelemetry/tracing'; /** * NodeTracerConfig provides an interface for configuring a Node Tracer. */ -export interface NodeTracerConfig extends BasicTracerConfig { +export interface NodeTracerConfig extends TracerConfig { /** Plugins options. */ plugins?: Plugins; } diff --git a/packages/opentelemetry-node/src/index.ts b/packages/opentelemetry-node/src/index.ts index 6517aafec9..2ba218e18d 100644 --- a/packages/opentelemetry-node/src/index.ts +++ b/packages/opentelemetry-node/src/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './NodeTracer'; +export * from './NodeTracerRegistry'; diff --git a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts index 3eb8881e6f..99d2abf487 100644 --- a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts +++ b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { Logger, Plugin, Tracer, PluginConfig } from '@opentelemetry/types'; +import { + Logger, + Plugin, + PluginConfig, + TracerRegistry, +} from '@opentelemetry/types'; import * as hook from 'require-in-the-middle'; import * as utils from './utils'; @@ -55,7 +60,7 @@ export class PluginLoader { private _hookState = HookState.UNINITIALIZED; /** Constructs a new PluginLoader instance. */ - constructor(readonly tracer: Tracer, readonly logger: Logger) {} + constructor(readonly registry: TracerRegistry, readonly logger: Logger) {} /** * Loads a list of plugins. Each plugin module should implement the core @@ -115,7 +120,7 @@ export class PluginLoader { this._plugins.push(plugin); // Enable each supported plugin. - return plugin.enable(exports, this.tracer, this.logger, config); + return plugin.enable(exports, this.registry, this.logger, config); } catch (e) { this.logger.error( `PluginLoader#load: could not load plugin ${modulePath} of module ${name}. Error: ${e.message}` diff --git a/packages/opentelemetry-node/test/NodeTracer.test.ts b/packages/opentelemetry-node/test/NodeTracer.test.ts index e9cbbeea47..757be77348 100644 --- a/packages/opentelemetry-node/test/NodeTracer.test.ts +++ b/packages/opentelemetry-node/test/NodeTracer.test.ts @@ -23,7 +23,7 @@ import { NoopLogger, NoRecordingSpan, } from '@opentelemetry/core'; -import { NodeTracer } from '../src/NodeTracer'; +import { NodeTracerRegistry } from '../src/NodeTracerRegistry'; import { TraceFlags } from '@opentelemetry/types'; import { Span } from '@opentelemetry/tracing'; import * as path from 'path'; @@ -39,8 +39,8 @@ const INSTALLED_PLUGINS_PATH = path.join( 'node_modules' ); -describe('NodeTracer', () => { - let tracer: NodeTracer; +describe('NodeTracerRegistry', () => { + let registry: NodeTracerRegistry; before(() => { module.paths.push(INSTALLED_PLUGINS_PATH); }); @@ -48,45 +48,45 @@ describe('NodeTracer', () => { afterEach(() => { // clear require cache Object.keys(require.cache).forEach(key => delete require.cache[key]); - tracer.stop(); + registry.stop(); }); describe('constructor', () => { it('should construct an instance with required only options', () => { - tracer = new NodeTracer(); - assert.ok(tracer instanceof NodeTracer); + registry = new NodeTracerRegistry(); + assert.ok(registry instanceof NodeTracerRegistry); }); it('should construct an instance with binary format', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ binaryFormat: new BinaryTraceContext(), }); - assert.ok(tracer instanceof NodeTracer); + assert.ok(registry instanceof NodeTracerRegistry); }); it('should construct an instance with http text format', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ httpTextFormat: new HttpTraceContext(), }); - assert.ok(tracer instanceof NodeTracer); + assert.ok(registry instanceof NodeTracerRegistry); }); it('should construct an instance with logger', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ logger: new NoopLogger(), }); - assert.ok(tracer instanceof NodeTracer); + assert.ok(registry instanceof NodeTracerRegistry); }); it('should construct an instance with sampler', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ sampler: ALWAYS_SAMPLER, }); - assert.ok(tracer instanceof NodeTracer); + assert.ok(registry instanceof NodeTracerRegistry); }); it('should load user configured plugins', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ logger: new NoopLogger(), plugins: { 'simple-module': { @@ -102,7 +102,7 @@ describe('NodeTracer', () => { }, }, }); - const pluginLoader = tracer['_pluginLoader']; + const pluginLoader = registry['_pluginLoader']; assert.strictEqual(pluginLoader['_plugins'].length, 0); require('simple-module'); assert.strictEqual(pluginLoader['_plugins'].length, 1); @@ -111,39 +111,39 @@ describe('NodeTracer', () => { }); it('should construct an instance with default attributes', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ defaultAttributes: { region: 'eu-west', asg: 'my-asg', }, }); - assert.ok(tracer instanceof NodeTracer); + assert.ok(registry instanceof NodeTracerRegistry); }); }); describe('.startSpan()', () => { it('should start a span with name only', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ logger: new NoopLogger(), }); - const span = tracer.startSpan('my-span'); + const span = registry.getTracer('default').startSpan('my-span'); assert.ok(span); }); it('should start a span with name and options', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ logger: new NoopLogger(), }); - const span = tracer.startSpan('my-span', {}); + const span = registry.getTracer('default').startSpan('my-span', {}); assert.ok(span); }); it('should return a default span with no sampling', () => { - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ sampler: NEVER_SAMPLER, logger: new NoopLogger(), }); - const span = tracer.startSpan('my-span'); + const span = registry.getTracer('default').startSpan('my-span'); assert.ok(span instanceof NoRecordingSpan); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); assert.strictEqual(span.isRecording(), false); @@ -156,11 +156,11 @@ describe('NodeTracer', () => { const defaultAttributes = { foo: 'bar', }; - tracer = new NodeTracer({ + registry = new NodeTracerRegistry({ defaultAttributes, }); - const span = tracer.startSpan('my-span') as Span; + const span = registry.getTracer('default').startSpan('my-span') as Span; assert.ok(span instanceof Span); assert.deepStrictEqual(span.attributes, defaultAttributes); }); @@ -168,32 +168,48 @@ describe('NodeTracer', () => { describe('.getCurrentSpan()', () => { it('should return undefined with AsyncHooksScopeManager when no span started', () => { - tracer = new NodeTracer({}); - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + registry = new NodeTracerRegistry({}); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + undefined + ); }); }); describe('.withSpan()', () => { it('should run scope with AsyncHooksScopeManager scope manager', done => { - tracer = new NodeTracer({}); - const span = tracer.startSpan('my-span'); - tracer.withSpan(span, () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), span); + registry = new NodeTracerRegistry({}); + const span = registry.getTracer('default').startSpan('my-span'); + registry.getTracer('default').withSpan(span, () => { + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + span + ); return done(); }); - // @todo: below check is not running. - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + undefined + ); }); it('should run scope with AsyncHooksScopeManager scope manager with multiple spans', done => { - tracer = new NodeTracer({}); - const span = tracer.startSpan('my-span'); - tracer.withSpan(span, () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), span); - - const span1 = tracer.startSpan('my-span1', { parent: span }); - tracer.withSpan(span1, () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), span1); + registry = new NodeTracerRegistry({}); + const span = registry.getTracer('default').startSpan('my-span'); + registry.getTracer('default').withSpan(span, () => { + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + span + ); + + const span1 = registry + .getTracer('default') + .startSpan('my-span1', { parent: span }); + registry.getTracer('default').withSpan(span1, () => { + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + span1 + ); assert.deepStrictEqual( span1.context().traceId, span.context().traceId @@ -203,48 +219,66 @@ describe('NodeTracer', () => { }); // when span ended. // @todo: below check is not running. - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + undefined + ); }); it('should find correct scope with promises', done => { - tracer = new NodeTracer({}); - const span = tracer.startSpan('my-span'); - tracer.withSpan(span, async () => { + registry = new NodeTracerRegistry({}); + const span = registry.getTracer('default').startSpan('my-span'); + registry.getTracer('default').withSpan(span, async () => { for (let i = 0; i < 3; i++) { await sleep(5).then(() => { - assert.deepStrictEqual(tracer.getCurrentSpan(), span); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + span + ); }); } return done(); }); - assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + undefined + ); }); }); describe('.bind()', () => { it('should bind scope with AsyncHooksScopeManager scope manager', done => { - const tracer = new NodeTracer({}); - const span = tracer.startSpan('my-span'); + const registry = new NodeTracerRegistry({}); + const span = registry.getTracer('default').startSpan('my-span'); const fn = () => { - assert.deepStrictEqual(tracer.getCurrentSpan(), span); + assert.deepStrictEqual( + registry.getTracer('default').getCurrentSpan(), + span + ); return done(); }; - const patchedFn = tracer.bind(fn, span); + const patchedFn = registry.getTracer('default').bind(fn, span); return patchedFn(); }); }); describe('.getBinaryFormat()', () => { it('should get default binary formatter', () => { - tracer = new NodeTracer({}); - assert.ok(tracer.getBinaryFormat() instanceof BinaryTraceContext); + registry = new NodeTracerRegistry({}); + assert.ok( + registry.getTracer('default').getBinaryFormat() instanceof + BinaryTraceContext + ); }); }); describe('.getHttpTextFormat()', () => { it('should get default HTTP text formatter', () => { - tracer = new NodeTracer({}); - assert.ok(tracer.getHttpTextFormat() instanceof HttpTraceContext); + registry = new NodeTracerRegistry({}); + assert.ok( + registry.getTracer('default').getHttpTextFormat() instanceof + HttpTraceContext + ); }); }); }); diff --git a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts index af6ca193e7..93440eb294 100644 --- a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts +++ b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import { NoopLogger, NoopTracer } from '@opentelemetry/core'; +import { NoopLogger, NoopTracerRegistry } from '@opentelemetry/core'; import * as assert from 'assert'; import * as path from 'path'; import { HookState, PluginLoader, - searchPathForTest, Plugins, + searchPathForTest, } from '../../src/instrumentation/PluginLoader'; const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules'); @@ -86,7 +86,7 @@ const notSupportedVersionPlugins: Plugins = { }; describe('PluginLoader', () => { - const tracer = new NoopTracer(); + const registry = new NoopTracerRegistry(); const logger = new NoopLogger(); before(() => { @@ -101,19 +101,19 @@ describe('PluginLoader', () => { describe('.state()', () => { it('returns UNINITIALIZED when first called', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_hookState'], HookState.UNINITIALIZED); }); it('transitions from UNINITIALIZED to ENABLED', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); pluginLoader.load(simplePlugins); assert.strictEqual(pluginLoader['_hookState'], HookState.ENABLED); pluginLoader.unload(); }); it('transitions from ENABLED to DISABLED', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); pluginLoader.load(simplePlugins).unload(); assert.strictEqual(pluginLoader['_hookState'], HookState.DISABLED); }); @@ -138,7 +138,7 @@ describe('PluginLoader', () => { }); it('should load a plugin and patch the target modules', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(simplePlugins); // The hook is only called the first time the module is loaded. @@ -150,7 +150,7 @@ describe('PluginLoader', () => { }); it('should load a plugin and patch the core module', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(httpPlugins); // The hook is only called the first time the module is loaded. @@ -161,7 +161,7 @@ describe('PluginLoader', () => { }); // @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(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(notSupportedVersionPlugins); // The hook is only called the first time the module is loaded. @@ -171,7 +171,7 @@ describe('PluginLoader', () => { }); // @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(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(supportedVersionPlugins); // The hook is only called the first time the module is loaded. @@ -183,7 +183,7 @@ describe('PluginLoader', () => { }); it('should not load a plugin when value is false', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(disablePlugins); const simpleModule = require('simple-module'); @@ -194,7 +194,7 @@ describe('PluginLoader', () => { }); it('should not load a plugin when value is true but path is missing', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(missingPathPlugins); const simpleModule = require('simple-module'); @@ -205,7 +205,7 @@ describe('PluginLoader', () => { }); it('should not load a non existing plugin', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(nonexistentPlugins); assert.strictEqual(pluginLoader['_plugins'].length, 0); @@ -213,7 +213,7 @@ describe('PluginLoader', () => { }); it(`doesn't patch modules for which plugins aren't specified`, () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); pluginLoader.load({}); assert.strictEqual(require('simple-module').value(), 0); pluginLoader.unload(); @@ -222,7 +222,7 @@ describe('PluginLoader', () => { describe('.unload()', () => { it('should unload the plugins and unpatch the target module when unloads', () => { - const pluginLoader = new PluginLoader(tracer, logger); + const pluginLoader = new PluginLoader(registry, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); pluginLoader.load(simplePlugins); // The hook is only called the first time the module is loaded. diff --git a/packages/opentelemetry-plugin-dns/README.md b/packages/opentelemetry-plugin-dns/README.md index 50bf77fd7c..3cac446759 100644 --- a/packages/opentelemetry-plugin-dns/README.md +++ b/packages/opentelemetry-plugin-dns/README.md @@ -18,9 +18,9 @@ npm install --save @opentelemetry/plugin-dns ## Usage ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { dns: { enabled: true, @@ -37,7 +37,7 @@ const tracer = new NodeTracer({ If you use Zipkin, you must use `ignoreHostnames` in order to not trace those calls. If the server is local. You can set : ``` -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { dns: { enabled: true, diff --git a/packages/opentelemetry-plugin-dns/src/dns.ts b/packages/opentelemetry-plugin-dns/src/dns.ts index 11eac18399..f7c3eb651b 100644 --- a/packages/opentelemetry-plugin-dns/src/dns.ts +++ b/packages/opentelemetry-plugin-dns/src/dns.ts @@ -14,22 +14,23 @@ * limitations under the License. */ -import * as shimmer from 'shimmer'; -import * as semver from 'semver'; -import * as utils from './utils'; import { BasePlugin } from '@opentelemetry/core'; -import { SpanOptions, SpanKind, Span } from '@opentelemetry/types'; +import { Span, SpanKind, SpanOptions } from '@opentelemetry/types'; +import { LookupAddress } from 'dns'; +import * as semver from 'semver'; +import * as shimmer from 'shimmer'; +import { AddressFamily } from './enums/AddressFamily'; +import { AttributeNames } from './enums/AttributeNames'; import { Dns, - LookupPromiseSignature, + DnsPluginConfig, + LookupCallbackSignature, LookupFunction, LookupFunctionSignature, - LookupCallbackSignature, - DnsPluginConfig, + LookupPromiseSignature, } from './types'; -import { AttributeNames } from './enums/AttributeNames'; -import { AddressFamily } from './enums/AddressFamily'; -import { LookupAddress } from 'dns'; +import * as utils from './utils'; +import { VERSION } from './version'; /** * Dns instrumentation plugin for Opentelemetry @@ -39,7 +40,7 @@ export class DnsPlugin extends BasePlugin { protected _config!: DnsPluginConfig; constructor(readonly moduleName: string, readonly version: string) { - super(); + super('@opentelemetry/plugin-dns', VERSION); // For now component is equal to moduleName but it can change in the future. this.component = this.moduleName; this._config = {}; diff --git a/packages/opentelemetry-plugin-dns/test/functionals/dns-disable.test.ts b/packages/opentelemetry-plugin-dns/test/functionals/dns-disable.test.ts index c3bd111b53..8fcfb36f4d 100644 --- a/packages/opentelemetry-plugin-dns/test/functionals/dns-disable.test.ts +++ b/packages/opentelemetry-plugin-dns/test/functionals/dns-disable.test.ts @@ -20,19 +20,20 @@ import { } from '@opentelemetry/tracing'; import * as assert from 'assert'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin } from '../../src/dns'; import * as sinon from 'sinon'; import * as dns from 'dns'; const memoryExporter = new InMemorySpanExporter(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ logger }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const registry = new NodeTracerRegistry({ logger }); +const tracer = registry.getTracer('default'); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); describe('DnsPlugin', () => { before(() => { - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, tracer.logger); assert.strictEqual(dns.lookup.__wrapped, true); }); diff --git a/packages/opentelemetry-plugin-dns/test/functionals/dns-enable.test.ts b/packages/opentelemetry-plugin-dns/test/functionals/dns-enable.test.ts index be6fde2d93..cb59bcb133 100644 --- a/packages/opentelemetry-plugin-dns/test/functionals/dns-enable.test.ts +++ b/packages/opentelemetry-plugin-dns/test/functionals/dns-enable.test.ts @@ -20,18 +20,18 @@ import { } from '@opentelemetry/tracing'; import * as assert from 'assert'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin, DnsPlugin } from '../../src/dns'; import * as dns from 'dns'; const memoryExporter = new InMemorySpanExporter(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ logger }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const registry = new NodeTracerRegistry({ logger }); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); describe('DnsPlugin', () => { before(() => { - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, registry.logger); }); after(() => { diff --git a/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts index 8bda076750..4be83dbed2 100644 --- a/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-dns/test/functionals/utils.test.ts @@ -14,14 +14,14 @@ * limitations under the License. */ +import { NoopLogger } from '@opentelemetry/core'; +import { BasicTracerRegistry, Span } from '@opentelemetry/tracing'; +import { CanonicalCode, SpanKind } from '@opentelemetry/types'; import * as assert from 'assert'; import * as sinon from 'sinon'; -import { CanonicalCode, SpanKind } from '@opentelemetry/types'; +import { AttributeNames } from '../../src/enums/AttributeNames'; import { IgnoreMatcher } from '../../src/types'; import * as utils from '../../src/utils'; -import { Span, BasicTracer } from '@opentelemetry/tracing'; -import { NoopLogger } from '@opentelemetry/core'; -import { AttributeNames } from '../../src/enums/AttributeNames'; describe('Utility', () => { describe('parseResponseStatus()', () => { @@ -162,7 +162,7 @@ describe('Utility', () => { it('should have error attributes', () => { const errorMessage = 'test error'; const span = new Span( - new BasicTracer(), + new BasicTracerRegistry().getTracer('default'), 'test', { spanId: '', traceId: '' }, SpanKind.INTERNAL diff --git a/packages/opentelemetry-plugin-dns/test/integrations/dns-lookup.test.ts b/packages/opentelemetry-plugin-dns/test/integrations/dns-lookup.test.ts index 05ba0effb4..088a6ea93d 100644 --- a/packages/opentelemetry-plugin-dns/test/integrations/dns-lookup.test.ts +++ b/packages/opentelemetry-plugin-dns/test/integrations/dns-lookup.test.ts @@ -20,7 +20,7 @@ import { } from '@opentelemetry/tracing'; import * as assert from 'assert'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin } from '../../src/dns'; import * as dns from 'dns'; import * as utils from '../utils/utils'; @@ -29,14 +29,14 @@ import { CanonicalCode } from '@opentelemetry/types'; const memoryExporter = new InMemorySpanExporter(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ logger }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const registry = new NodeTracerRegistry({ logger }); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); describe('dns.lookup()', () => { before(function(done) { // mandatory if (process.env.CI) { - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, registry.logger); done(); return; } @@ -48,7 +48,7 @@ describe('dns.lookup()', () => { } done(); }); - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, registry.logger); }); afterEach(() => { diff --git a/packages/opentelemetry-plugin-dns/test/integrations/dnspromise-lookup.test.ts b/packages/opentelemetry-plugin-dns/test/integrations/dnspromise-lookup.test.ts index aec20fa398..ec9e49ae51 100644 --- a/packages/opentelemetry-plugin-dns/test/integrations/dnspromise-lookup.test.ts +++ b/packages/opentelemetry-plugin-dns/test/integrations/dnspromise-lookup.test.ts @@ -20,7 +20,7 @@ import { } from '@opentelemetry/tracing'; import * as assert from 'assert'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin } from '../../src/dns'; import * as dns from 'dns'; import * as utils from '../utils/utils'; @@ -30,8 +30,8 @@ import { CanonicalCode } from '@opentelemetry/types'; const memoryExporter = new InMemorySpanExporter(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ logger }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const registry = new NodeTracerRegistry({ logger }); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); describe('dns.promises.lookup()', () => { before(function(done) { @@ -42,7 +42,7 @@ describe('dns.promises.lookup()', () => { // if node version is supported, it's mandatory for CI if (process.env.CI) { - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, registry.logger); done(); return; } @@ -54,7 +54,7 @@ describe('dns.promises.lookup()', () => { } done(); }); - plugin.enable(dns, tracer, tracer.logger); + plugin.enable(dns, registry, registry.logger); }); afterEach(() => { diff --git a/packages/opentelemetry-plugin-document-load/src/documentLoad.ts b/packages/opentelemetry-plugin-document-load/src/documentLoad.ts index 208b7d151b..2d14055cd8 100644 --- a/packages/opentelemetry-plugin-document-load/src/documentLoad.ts +++ b/packages/opentelemetry-plugin-document-load/src/documentLoad.ts @@ -21,7 +21,6 @@ import { TRACE_PARENT_HEADER, } from '@opentelemetry/core'; import { PluginConfig, Span, SpanOptions } from '@opentelemetry/types'; -import { AttributeNames } from './enums/AttributeNames'; import { addSpanNetworkEvent, hasKey, @@ -29,6 +28,8 @@ import { PerformanceLegacy, PerformanceTimingNames as PTN, } from '@opentelemetry/web'; +import { AttributeNames } from './enums/AttributeNames'; +import { VERSION } from './version'; /** * This class represents a document load plugin @@ -44,7 +45,7 @@ export class DocumentLoad extends BasePlugin { * @param config */ constructor(config: PluginConfig = {}) { - super(); + super('@opentelemetry/plugin-document-load', VERSION); this._onDocumentLoaded = this._onDocumentLoaded.bind(this); this._config = config; } diff --git a/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts b/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts index c125ae8402..6ae19c3846 100644 --- a/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts +++ b/packages/opentelemetry-plugin-document-load/test/documentLoad.test.ts @@ -18,18 +18,16 @@ * Can't use Sinon Fake Time here as then cannot stub the performance getEntriesByType with desired metrics */ -import * as assert from 'assert'; -import * as sinon from 'sinon'; - import { ConsoleLogger, TRACE_PARENT_HEADER } from '@opentelemetry/core'; import { - BasicTracer, + BasicTracerRegistry, ReadableSpan, SimpleSpanProcessor, SpanExporter, } from '@opentelemetry/tracing'; import { Logger, PluginConfig, TimedEvent } from '@opentelemetry/types'; - +import * as assert from 'assert'; +import * as sinon from 'sinon'; import { ExportResult } from '../../opentelemetry-base/build/src'; import { DocumentLoad } from '../src'; import { PerformanceTimingNames as PTN } from '@opentelemetry/web'; @@ -193,7 +191,7 @@ function ensureNetworkEventsExists(events: TimedEvent[]) { describe('DocumentLoad Plugin', () => { let plugin: DocumentLoad; let moduleExports: any; - let tracer: BasicTracer; + let registry: BasicTracerRegistry; let logger: Logger; let config: PluginConfig; let spanProcessor: SimpleSpanProcessor; @@ -205,13 +203,13 @@ describe('DocumentLoad Plugin', () => { value: 'complete', }); moduleExports = {}; - tracer = new BasicTracer(); + registry = new BasicTracerRegistry(); logger = new ConsoleLogger(); config = {}; plugin = new DocumentLoad(); dummyExporter = new DummyExporter(); spanProcessor = new SimpleSpanProcessor(dummyExporter); - tracer.addSpanProcessor(spanProcessor); + registry.addSpanProcessor(spanProcessor); }); afterEach(() => { @@ -239,7 +237,7 @@ describe('DocumentLoad Plugin', () => { spyEntries.restore(); }); it('should start collecting the performance immediately', done => { - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { assert.strictEqual(window.document.readyState, 'complete'); assert.strictEqual(spyEntries.callCount, 2); @@ -266,7 +264,7 @@ describe('DocumentLoad Plugin', () => { it('should collect performance after document load event', done => { const spy = sinon.spy(window, 'addEventListener'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); const args = spy.args[0]; const name = args[0]; assert.strictEqual(name, 'load'); @@ -301,7 +299,7 @@ describe('DocumentLoad Plugin', () => { it('should export correct span with events', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; @@ -358,7 +356,7 @@ describe('DocumentLoad Plugin', () => { it('should create a root span with server context traceId', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; const fetchSpan = spyOnEnd.args[1][0][0] as ReadableSpan; @@ -394,7 +392,7 @@ describe('DocumentLoad Plugin', () => { it('should create span for each of the resource', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan; const spanResource2 = spyOnEnd.args[2][0][0] as ReadableSpan; @@ -432,7 +430,7 @@ describe('DocumentLoad Plugin', () => { it('should create span for each of the resource', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan; @@ -473,7 +471,7 @@ describe('DocumentLoad Plugin', () => { it('should still export rootSpan and fetchSpan', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; @@ -505,7 +503,7 @@ describe('DocumentLoad Plugin', () => { it('should export correct span with events', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; const fetchSpan = spyOnEnd.args[1][0][0] as ReadableSpan; @@ -553,7 +551,7 @@ describe('DocumentLoad Plugin', () => { it('should not create any span', done => { const spyOnEnd = sinon.spy(dummyExporter, 'export'); - plugin.enable(moduleExports, tracer, logger, config); + plugin.enable(moduleExports, registry, logger, config); setTimeout(() => { assert.ok(spyOnEnd.callCount === 0); done(); diff --git a/packages/opentelemetry-plugin-grpc/README.md b/packages/opentelemetry-plugin-grpc/README.md index d421029dbd..e728f8e694 100644 --- a/packages/opentelemetry-plugin-grpc/README.md +++ b/packages/opentelemetry-plugin-grpc/README.md @@ -22,9 +22,9 @@ OpenTelemetry gRPC Instrumentation allows the user to automatically collect trac To load a specific plugin (**gRPC** in this case), specify it in the Node Tracer's configuration. ```javascript -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { grpc: { enabled: true, @@ -37,9 +37,9 @@ const tracer = new NodeTracer({ To load all the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. ```javascript -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer(); +const registry = new NodeTracerRegistry(); ``` See [examples/grpc](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/grpc) for a short example. diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index 2fba28743e..901eba22fe 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -16,33 +16,33 @@ import { BasePlugin } from '@opentelemetry/core'; import { + CanonicalCode, + Span, + SpanContext, SpanKind, SpanOptions, - Span, Status, - CanonicalCode, - SpanContext, } from '@opentelemetry/types'; +import * as events from 'events'; +import * as grpcTypes from 'grpc'; +import * as path from 'path'; +import * as shimmer from 'shimmer'; import { AttributeNames } from './enums/AttributeNames'; import { grpc, - ModuleExportsMapping, - GrpcPluginOptions, - ServerCallWithMeta, - SendUnaryDataCallback, GrpcClientFunc, GrpcInternalClientTypes, + GrpcPluginOptions, + ModuleExportsMapping, + SendUnaryDataCallback, + ServerCallWithMeta, } from './types'; import { findIndex, _grpcStatusCodeToCanonicalCode, _grpcStatusCodeToSpanStatus, } from './utils'; - -import * as events from 'events'; -import * as grpcTypes from 'grpc'; -import * as shimmer from 'shimmer'; -import * as path from 'path'; +import { VERSION } from './version'; /** The metadata key under which span context is stored as a binary value. */ export const GRPC_TRACE_KEY = 'grpc-trace-bin'; @@ -56,7 +56,7 @@ export class GrpcPlugin extends BasePlugin { protected _config!: GrpcPluginOptions; constructor(readonly moduleName: string, readonly version: string) { - super(); + super('@opentelemetry/plugin-grpc', VERSION); this._config = {}; } diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index a6d4f35450..3f778496ea 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -14,22 +14,20 @@ * limitations under the License. */ -import { NoopLogger, NoopTracer } from '@opentelemetry/core'; +import { NoopLogger, NoopTracerRegistry } from '@opentelemetry/core'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; -import { SpanKind, Tracer } from '@opentelemetry/types'; -import { NodeTracer } from '@opentelemetry/node'; - -import { assertSpan, assertPropagation } from './utils/assertionUtils'; -import { GrpcPlugin, plugin } from '../src'; -import { SendUnaryDataCallback } from '../src/types'; - +import { SpanKind } from '@opentelemetry/types'; import * as assert from 'assert'; -import * as semver from 'semver'; import * as grpc from 'grpc'; +import * as semver from 'semver'; import * as sinon from 'sinon'; +import { GrpcPlugin, plugin } from '../src'; +import { SendUnaryDataCallback } from '../src/types'; +import { assertPropagation, assertSpan } from './utils/assertionUtils'; const PROTO_PATH = __dirname + '/fixtures/grpc-test.proto'; const memoryExporter = new InMemorySpanExporter(); @@ -318,7 +316,7 @@ describe('GrpcPlugin', () => { }); it('should patch client constructor makeClientConstructor() and makeGenericClientConstructor()', () => { - plugin.enable(grpc, new NoopTracer(), new NoopLogger()); + plugin.enable(grpc, new NoopTracerRegistry(), new NoopLogger()); (plugin['_moduleExports'] as any).makeGenericClientConstructor({}); assert.strictEqual(clientPatchStub.callCount, 1); }); @@ -370,7 +368,7 @@ describe('GrpcPlugin', () => { const runTest = ( method: typeof methodList[0], - tracer: Tracer, + registry: NodeTracerRegistry, checkSpans = true ) => { it(`should ${ @@ -410,9 +408,11 @@ describe('GrpcPlugin', () => { const expectEmpty = memoryExporter.getFinishedSpans(); assert.strictEqual(expectEmpty.length, 0); - const span = tracer.startSpan('TestSpan', { kind: SpanKind.PRODUCER }); - return tracer.withSpan(span, async () => { - const rootSpan = tracer.getCurrentSpan(); + const span = registry + .getTracer('default') + .startSpan('TestSpan', { kind: SpanKind.PRODUCER }); + return registry.getTracer('default').withSpan(span, async () => { + const rootSpan = registry.getTracer('default').getCurrentSpan(); if (!rootSpan) { assert.ok(false); return; // return so typechecking passes for rootSpan.end() @@ -465,7 +465,7 @@ describe('GrpcPlugin', () => { method: typeof methodList[0], key: string, errorCode: number, - tracer: Tracer + registry: NodeTracerRegistry ) => { it(`should raise an error for client/server rootSpans: method=${method.methodName}, status=${key}`, async () => { const expectEmpty = memoryExporter.getFinishedSpans(); @@ -503,9 +503,11 @@ describe('GrpcPlugin', () => { const expectEmpty = memoryExporter.getFinishedSpans(); assert.strictEqual(expectEmpty.length, 0); - const span = tracer.startSpan('TestSpan', { kind: SpanKind.PRODUCER }); - return tracer.withSpan(span, async () => { - const rootSpan = tracer.getCurrentSpan(); + const span = registry + .getTracer('default') + .startSpan('TestSpan', { kind: SpanKind.PRODUCER }); + return registry.getTracer('default').withSpan(span, async () => { + const rootSpan = registry.getTracer('default').getCurrentSpan(); if (!rootSpan) { assert.ok(false); return; // return so typechecking passes for rootSpan.end() @@ -552,8 +554,8 @@ describe('GrpcPlugin', () => { describe('enable()', () => { const logger = new NoopLogger(); - const tracer = new NodeTracer({ logger }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const registry = new NodeTracerRegistry({ logger }); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); @@ -562,7 +564,7 @@ describe('GrpcPlugin', () => { const config = { // TODO: add plugin options here once supported }; - plugin.enable(grpc, tracer, logger, config); + plugin.enable(grpc, registry, logger, config); const proto = grpc.load(PROTO_PATH).pkg_test; server = startServer(grpc, proto); @@ -579,7 +581,7 @@ describe('GrpcPlugin', () => { methodList.forEach(method => { describe(`Test automatic tracing for grpc remote method ${method.description}`, () => { - runTest(method, tracer); + runTest(method, registry); }); }); @@ -589,7 +591,7 @@ describe('GrpcPlugin', () => { // tslint:disable-next-line:no-any const errorCode = Number(grpc.status[statusKey as any]); if (errorCode > grpc.status.OK) { - runErrorTest(method, statusKey, errorCode, tracer); + runErrorTest(method, statusKey, errorCode, registry); } }); }); @@ -598,14 +600,14 @@ describe('GrpcPlugin', () => { describe('disable()', () => { const logger = new NoopLogger(); - const tracer = new NodeTracer({ logger }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const registry = new NodeTracerRegistry({ logger }); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); before(() => { - plugin.enable(grpc, tracer, logger); + plugin.enable(grpc, registry, logger); plugin.disable(); const proto = grpc.load(PROTO_PATH).pkg_test; @@ -622,7 +624,7 @@ describe('GrpcPlugin', () => { methodList.map(method => { describe(`Test automatic tracing for grpc remote method ${method.description}`, () => { - runTest(method, tracer, false); + runTest(method, registry, false); }); }); }); diff --git a/packages/opentelemetry-plugin-http/README.md b/packages/opentelemetry-plugin-http/README.md index c1e84e55a8..69d196b5cd 100644 --- a/packages/opentelemetry-plugin-http/README.md +++ b/packages/opentelemetry-plugin-http/README.md @@ -22,9 +22,9 @@ OpenTelemetry HTTP Instrumentation allows the user to automatically collect trac To load a specific plugin (HTTP in this case), specify it in the Node Tracer's configuration. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { http: { enabled: true, @@ -38,9 +38,9 @@ const tracer = new NodeTracer({ To load all the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer(); +const registry = new NodeTracerRegistry(); ``` See [examples/http](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/http) for a short example. diff --git a/packages/opentelemetry-plugin-http/src/http.ts b/packages/opentelemetry-plugin-http/src/http.ts index feeab5a26e..f45fb6ac56 100644 --- a/packages/opentelemetry-plugin-http/src/http.ts +++ b/packages/opentelemetry-plugin-http/src/http.ts @@ -16,10 +16,10 @@ import { BasePlugin, isValid } from '@opentelemetry/core'; import { + CanonicalCode, Span, SpanKind, SpanOptions, - CanonicalCode, Status, } from '@opentelemetry/types'; import { @@ -29,22 +29,23 @@ import { RequestOptions, ServerResponse, } from 'http'; +import { Socket } from 'net'; import * as semver from 'semver'; import * as shimmer from 'shimmer'; import * as url from 'url'; +import { AttributeNames } from './enums/AttributeNames'; +import { Format } from './enums/Format'; import { - HttpPluginConfig, - Http, + Err, Func, - ResponseEndArgs, - ParsedRequestOptions, + Http, + HttpPluginConfig, HttpRequestArgs, - Err, + ParsedRequestOptions, + ResponseEndArgs, } from './types'; -import { Format } from './enums/Format'; -import { AttributeNames } from './enums/AttributeNames'; import * as utils from './utils'; -import { Socket } from 'net'; +import { VERSION } from './version'; /** * Http instrumentation plugin for Opentelemetry @@ -56,7 +57,7 @@ export class HttpPlugin extends BasePlugin { private readonly _spanNotEnded: WeakSet; constructor(readonly moduleName: string, readonly version: string) { - super(); + super(`@opentelemetry/plugin-${moduleName}`, VERSION); // For now component is equal to moduleName but it can change in the future. this.component = this.moduleName; this._spanNotEnded = new WeakSet(); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts index 4aba514d61..b9b13276b9 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts @@ -20,10 +20,12 @@ import * as nock from 'nock'; import * as sinon from 'sinon'; import { plugin } from '../../src/http'; -import { NodeTracer } from '@opentelemetry/node'; -import { NoopLogger } from '@opentelemetry/core'; +import { + NoopLogger, + NoopTracerRegistry, + noopTracer, +} from '@opentelemetry/core'; import { AddressInfo } from 'net'; -import { DummyPropagation } from '../utils/DummyPropagation'; import { httpRequest } from '../utils/httpRequest'; describe('HttpPlugin', () => { @@ -31,17 +33,13 @@ describe('HttpPlugin', () => { let serverPort = 0; describe('disable()', () => { - const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ - logger, - httpTextFormat, - }); + const registry = new NoopTracerRegistry(); before(() => { nock.cleanAll(); nock.enableNetConnect(); - plugin.enable(http, tracer, tracer.logger); + plugin.enable(http, registry, logger); // Ensure that http module is patched. assert.strictEqual(http.Server.prototype.emit.__wrapped, true); server = http.createServer((request, response) => { @@ -55,8 +53,8 @@ describe('HttpPlugin', () => { }); beforeEach(() => { - tracer.startSpan = sinon.spy(); - tracer.withSpan = sinon.spy(); + noopTracer.startSpan = sinon.spy(); + noopTracer.withSpan = sinon.spy(); }); afterEach(() => { @@ -67,7 +65,7 @@ describe('HttpPlugin', () => { server.close(); }); describe('unpatch()', () => { - it('should not call tracer methods for creating span', async () => { + it('should not call registry methods for creating span', async () => { plugin.disable(); const testPath = '/incoming/unpatch/'; @@ -75,12 +73,15 @@ describe('HttpPlugin', () => { await httpRequest.get(options).then(result => { assert.strictEqual( - (tracer.startSpan as sinon.SinonSpy).called, + (noopTracer.startSpan as sinon.SinonSpy).called, false ); assert.strictEqual(http.Server.prototype.emit.__wrapped, undefined); - assert.strictEqual((tracer.withSpan as sinon.SinonSpy).called, false); + assert.strictEqual( + (noopTracer.withSpan as sinon.SinonSpy).called, + false + ); }); }); }); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index fcc49dc30d..4efaa6920d 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -19,7 +19,7 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { CanonicalCode, Span as ISpan, SpanKind } from '@opentelemetry/types'; import * as assert from 'assert'; import * as http from 'http'; @@ -45,11 +45,11 @@ const serverName = 'my.server.name'; const memoryExporter = new InMemorySpanExporter(); const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); function doNock( hostname: string, @@ -109,7 +109,7 @@ describe('HttpPlugin', () => { plugin.component, process.versions.node ); - pluginWithBadOptions.enable(http, tracer, tracer.logger, config); + pluginWithBadOptions.enable(http, registry, registry.logger, config); server = http.createServer((request, response) => { response.end('Test Server Response'); }); @@ -187,7 +187,7 @@ describe('HttpPlugin', () => { applyCustomAttributesOnSpan: customAttributeFunction, serverName, }; - plugin.enable(http, tracer, tracer.logger, config); + plugin.enable(http, registry, registry.logger, config); server = http.createServer((request, response) => { response.end('Test Server Response'); }); @@ -208,7 +208,7 @@ describe('HttpPlugin', () => { const httpNotPatched = new HttpPlugin( plugin.component, process.versions.node - ).enable({} as Http, tracer, tracer.logger, {}); + ).enable({} as Http, registry, registry.logger, {}); assert.strictEqual(Object.keys(httpNotPatched).length, 0); }); @@ -323,8 +323,8 @@ describe('HttpPlugin', () => { const testPath = '/outgoing/rootSpan/childs/1'; doNock(hostname, testPath, 200, 'Ok'); const name = 'TestRootSpan'; - const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + const span = registry.getTracer('default').startSpan(name); + return registry.getTracer('default').withSpan(span, async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -366,8 +366,8 @@ describe('HttpPlugin', () => { httpErrorCodes[i].toString() ); const name = 'TestRootSpan'; - const span = tracer.startSpan(name); - return tracer.withSpan(span, async () => { + const span = registry.getTracer('default').startSpan(name); + return registry.getTracer('default').withSpan(span, async () => { const result = await httpRequest.get( `${protocol}://${hostname}${testPath}` ); @@ -405,8 +405,8 @@ describe('HttpPlugin', () => { const num = 5; doNock(hostname, testPath, 200, 'Ok', num); const name = 'TestRootSpan'; - const span = tracer.startSpan(name); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('default').startSpan(name); + await registry.getTracer('default').withSpan(span, async () => { for (let i = 0; i < num; i++) { await httpRequest.get(`${protocol}://${hostname}${testPath}`); const spans = memoryExporter.getFinishedSpans(); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts index 4976e88a33..cf9e68c619 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -28,7 +28,7 @@ import * as superagent from 'superagent'; import * as got from 'got'; import * as request from 'request-promise-native'; import * as path from 'path'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -45,11 +45,11 @@ describe('Packages', () => { const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); @@ -58,7 +58,7 @@ describe('Packages', () => { const config: HttpPluginConfig = { applyCustomAttributesOnSpan: customAttributeFunction, }; - plugin.enable(http, tracer, tracer.logger, config); + plugin.enable(http, registry, registry.logger, config); }); after(() => { diff --git a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts index 138cccac81..32372c8cbe 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts @@ -22,7 +22,7 @@ import { NoopScopeManager } from '@opentelemetry/scope-base'; import { IgnoreMatcher } from '../../src/types'; import * as utils from '../../src/utils'; import * as http from 'http'; -import { Span, BasicTracer } from '@opentelemetry/tracing'; +import { Span, BasicTracerRegistry } from '@opentelemetry/tracing'; import { AttributeNames } from '../../src'; import { NoopLogger } from '@opentelemetry/core'; @@ -248,9 +248,9 @@ describe('Utility', () => { const errorMessage = 'test error'; for (const obj of [undefined, { statusCode: 400 }]) { const span = new Span( - new BasicTracer({ + new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), - }), + }).getTracer('default'), 'test', { spanId: '', traceId: '' }, SpanKind.INTERNAL diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index 086546db2d..0793aa99ed 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -24,7 +24,7 @@ import { DummyPropagation } from '../utils/DummyPropagation'; import { httpRequest } from '../utils/httpRequest'; import * as url from 'url'; import * as utils from '../utils/utils'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -60,11 +60,11 @@ describe('HttpPlugin Integration tests', () => { const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); @@ -83,7 +83,7 @@ describe('HttpPlugin Integration tests', () => { try { plugin.disable(); } catch (e) {} - plugin.enable(http, tracer, tracer.logger, config); + plugin.enable(http, registry, registry.logger, config); }); after(() => { diff --git a/packages/opentelemetry-plugin-https/README.md b/packages/opentelemetry-plugin-https/README.md index c8aff10265..a47a71a6ca 100644 --- a/packages/opentelemetry-plugin-https/README.md +++ b/packages/opentelemetry-plugin-https/README.md @@ -22,9 +22,9 @@ OpenTelemetry HTTPS Instrumentation allows the user to automatically collect tra To load a specific plugin (HTTPS in this case), specify it in the Node Tracer's configuration. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { https: { enabled: true, @@ -38,9 +38,9 @@ const tracer = new NodeTracer({ To load all the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer(); +const registry = new NodeTracerRegistry(); ``` See [examples/https](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/https) for a short example. diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts index cc5f6edcaa..826fc5d72c 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts @@ -14,19 +14,19 @@ * limitations under the License. */ +import { NoopLogger } from '@opentelemetry/core'; +import { Http } from '@opentelemetry/plugin-http'; import * as assert from 'assert'; import * as fs from 'fs'; import * as https from 'https'; +import { AddressInfo } from 'net'; import * as nock from 'nock'; import * as sinon from 'sinon'; - import { plugin } from '../../src/https'; -import { NodeTracer } from '@opentelemetry/node'; -import { NoopLogger } from '@opentelemetry/core'; -import { Http } from '@opentelemetry/plugin-http'; -import { AddressInfo } from 'net'; import { DummyPropagation } from '../utils/DummyPropagation'; import { httpsRequest } from '../utils/httpsRequest'; +import { NodeTracerRegistry } from '@opentelemetry/node'; +import * as types from '@opentelemetry/types'; describe('HttpsPlugin', () => { let server: https.Server; @@ -35,15 +35,18 @@ describe('HttpsPlugin', () => { describe('disable()', () => { const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); + // const tracer = registry.getTracer('test-https') + let tracer: types.Tracer; before(() => { nock.cleanAll(); nock.enableNetConnect(); - plugin.enable((https as unknown) as Http, tracer, tracer.logger); + plugin.enable((https as unknown) as Http, registry, registry.logger); + tracer = plugin['_tracer']; // Ensure that https module is patched. assert.strictEqual(https.Server.prototype.emit.__wrapped, true); server = https.createServer( diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts index c87f3635ca..477b2b906c 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -19,7 +19,7 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { Http, HttpPluginConfig, @@ -50,11 +50,12 @@ const pathname = '/test'; const memoryExporter = new InMemorySpanExporter(); const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); -tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const tracer = registry.getTracer('test-https'); +registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); function doNock( hostname: string, @@ -113,7 +114,7 @@ describe('HttpsPlugin', () => { pluginWithBadOptions = new HttpsPlugin(process.versions.node); pluginWithBadOptions.enable( (https as unknown) as Http, - tracer, + registry, tracer.logger, config ); @@ -202,7 +203,7 @@ describe('HttpsPlugin', () => { }; plugin.enable( (https as unknown) as Http, - tracer, + registry, tracer.logger, config ); @@ -231,7 +232,7 @@ describe('HttpsPlugin', () => { it(`should not patch if it's not a ${protocol} module`, () => { const httpsNotPatched = new HttpsPlugin(process.versions.node).enable( {} as Http, - tracer, + registry, tracer.logger, {} ); diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts index 811a3e32c5..63769e16f8 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { SpanKind } from '@opentelemetry/types'; +import { SpanKind, Span } from '@opentelemetry/types'; import * as assert from 'assert'; import * as https from 'https'; import * as http from 'http'; @@ -29,37 +29,35 @@ import * as superagent from 'superagent'; import * as got from 'got'; import * as request from 'request-promise-native'; import * as path from 'path'; -import { NodeTracer } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; - -import { Http, HttpPluginConfig } from '@opentelemetry/plugin-http'; -import { customAttributeFunction } from './https-enable.test'; +import { Http } from '@opentelemetry/plugin-http'; +import { NodeTracerRegistry } from '@opentelemetry/node'; const memoryExporter = new InMemorySpanExporter(); -const protocol = 'https'; + +export const customAttributeFunction = (span: Span): void => { + span.setAttribute('span kind', SpanKind.CLIENT); +}; describe('Packages', () => { describe('get', () => { const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); before(() => { - const config: HttpPluginConfig = { - applyCustomAttributesOnSpan: customAttributeFunction, - }; - plugin.enable((https as unknown) as Http, tracer, tracer.logger, config); + plugin.enable((https as unknown) as Http, registry, registry.logger); }); after(() => { @@ -95,8 +93,8 @@ describe('Packages', () => { // https://github.com/nock/nock/pull/1551 // https://github.com/sindresorhus/got/commit/bf1aa5492ae2bc78cbbec6b7d764906fb156e6c2#diff-707a4781d57c42085155dcb27edb9ccbR258 // TODO: check if this is still the case when new version - `${protocol}://www.google.com` - : `${protocol}://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8` + 'https://www.google.com' + : `https://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8` ); const result = await httpPackage.get(urlparsed.href!); if (!resHeaders) { diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index 7d3dd7b659..39002c8af6 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -30,7 +30,7 @@ import { DummyPropagation } from '../utils/DummyPropagation'; import { httpsRequest } from '../utils/httpsRequest'; import * as url from 'url'; import * as utils from '../utils/utils'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -65,11 +65,11 @@ describe('HttpsPlugin Integration tests', () => { const httpTextFormat = new DummyPropagation(); const logger = new NoopLogger(); - const tracer = new NodeTracer({ + const registry = new NodeTracerRegistry({ logger, httpTextFormat, }); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); @@ -88,7 +88,12 @@ describe('HttpsPlugin Integration tests', () => { try { plugin.disable(); } catch (e) {} - plugin.enable((https as unknown) as Http, tracer, tracer.logger, config); + plugin.enable( + (https as unknown) as Http, + registry, + registry.logger, + config + ); }); after(() => { diff --git a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts index ceba19daea..71167b4e6d 100644 --- a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SpanKind, Status } from '@opentelemetry/types'; +import { SpanKind } from '@opentelemetry/types'; import { hrTimeToNanoseconds } from '@opentelemetry/core'; import * as assert from 'assert'; import * as http from 'http'; @@ -36,7 +36,6 @@ export const assertSpan = ( pathname: string; reqHeaders?: http.OutgoingHttpHeaders; path?: string | null; - forceStatus?: Status; serverName?: string; component: string; } @@ -68,13 +67,12 @@ export const assertSpan = ( span.attributes[AttributeNames.HTTP_STATUS_CODE], validations.httpStatusCode ); - + assert.ok(span.endTime); assert.strictEqual(span.links.length, 0); assert.strictEqual(span.events.length, 0); - assert.deepStrictEqual( span.status, - validations.forceStatus || parseResponseStatus(validations.httpStatusCode) + parseResponseStatus(validations.httpStatusCode) ); assert.ok(span.endTime, 'must be finished'); diff --git a/packages/opentelemetry-plugin-ioredis/src/ioredis.ts b/packages/opentelemetry-plugin-ioredis/src/ioredis.ts index 4fedf82c53..428e174057 100644 --- a/packages/opentelemetry-plugin-ioredis/src/ioredis.ts +++ b/packages/opentelemetry-plugin-ioredis/src/ioredis.ts @@ -18,6 +18,7 @@ import { BasePlugin } from '@opentelemetry/core'; import * as ioredisTypes from 'ioredis'; import * as shimmer from 'shimmer'; import { traceConnection, traceSendCommand } from './utils'; +import { VERSION } from './version'; export class IORedisPlugin extends BasePlugin { static readonly COMPONENT = 'ioredis'; @@ -25,7 +26,7 @@ export class IORedisPlugin extends BasePlugin { readonly supportedVersions = ['^2.0.0']; constructor(readonly moduleName: string) { - super(); + super('@opentelemetry/plugin-ioredis', VERSION); } protected patch(): typeof ioredisTypes { diff --git a/packages/opentelemetry-plugin-ioredis/test/ioredis.test.ts b/packages/opentelemetry-plugin-ioredis/test/ioredis.test.ts index ba68af4dd4..3f99e22216 100644 --- a/packages/opentelemetry-plugin-ioredis/test/ioredis.test.ts +++ b/packages/opentelemetry-plugin-ioredis/test/ioredis.test.ts @@ -19,7 +19,7 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin, IORedisPlugin } from '../src'; import * as ioredisTypes from 'ioredis'; import { NoopLogger } from '@opentelemetry/core'; @@ -49,7 +49,7 @@ const okStatus: Status = { }; describe('ioredis', () => { - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); let ioredis: typeof ioredisTypes; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; @@ -68,8 +68,8 @@ describe('ioredis', () => { } ioredis = require('ioredis'); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); - plugin.enable(ioredis, tracer, new NoopLogger()); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + plugin.enable(ioredis, registry, new NoopLogger()); }); after(() => { @@ -84,7 +84,7 @@ describe('ioredis', () => { describe('#createClient()', () => { it('should propagate the current span to event handlers', done => { - const span = tracer.startSpan('test span'); + const span = registry.getTracer('ioredis-test').startSpan('test span'); let client: ioredisTypes.Redis; const attributes = { ...DEFAULT_ATTRIBUTES, @@ -93,7 +93,10 @@ describe('ioredis', () => { const readyHandler = () => { const endedSpans = memoryExporter.getFinishedSpans(); - assert.strictEqual(tracer.getCurrentSpan(), span); + assert.strictEqual( + registry.getTracer('ioredis-test').getCurrentSpan(), + span + ); assert.strictEqual(endedSpans.length, 2); assert.strictEqual(endedSpans[0].name, `connect`); assert.strictEqual(endedSpans[1].name, `info`); @@ -119,7 +122,7 @@ describe('ioredis', () => { client.quit(done); }; - tracer.withSpan(span, () => { + registry.getTracer('ioredis-test').withSpan(span, () => { client = new ioredis(URL); client.on('ready', readyHandler); client.on('error', errorHandler); @@ -183,8 +186,10 @@ describe('ioredis', () => { ' ' )}`, }; - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry + .getTracer('ioredis-test') + .startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { command.method((err, _result) => { assert.ifError(err); assert.strictEqual(memoryExporter.getFinishedSpans().length, 1); @@ -211,8 +216,8 @@ describe('ioredis', () => { ...DEFAULT_ATTRIBUTES, [AttributeNames.DB_STATEMENT]: 'hset hash random random', }; - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + await registry.getTracer('ioredis-test').withSpan(span, async () => { try { await client.hset('hash', 'random', 'random'); assert.strictEqual(memoryExporter.getFinishedSpans().length, 1); @@ -239,8 +244,8 @@ describe('ioredis', () => { ...DEFAULT_ATTRIBUTES, [AttributeNames.DB_STATEMENT]: 'scan 0', }; - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { const stream = client.scanStream(); stream .on('data', resultKeys => { @@ -275,8 +280,8 @@ describe('ioredis', () => { }); it('should create a child span for pubsub', async () => { - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + await registry.getTracer('ioredis-test').withSpan(span, async () => { try { const pub = new ioredis(URL); const sub = new ioredis(URL); @@ -334,8 +339,8 @@ describe('ioredis', () => { [AttributeNames.DB_STATEMENT]: 'eval return {KEYS[1],ARGV[1]} 1 test', }; - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { // This will define a command echo: client.defineCommand('echo', { numberOfKeys: 1, @@ -372,8 +377,8 @@ describe('ioredis', () => { [AttributeNames.DB_STATEMENT]: 'multi', }; - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { client .multi() .set('foo', 'bar') @@ -408,8 +413,8 @@ describe('ioredis', () => { [AttributeNames.DB_STATEMENT]: 'set foo bar', }; - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { const pipeline = client.pipeline(); pipeline.set('foo', 'bar'); pipeline.del('cc'); @@ -441,8 +446,8 @@ describe('ioredis', () => { ...DEFAULT_ATTRIBUTES, [AttributeNames.DB_STATEMENT]: 'get test', }; - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + await registry.getTracer('ioredis-test').withSpan(span, async () => { try { const value = await client.get('test'); assert.strictEqual(value, 'data'); @@ -470,8 +475,8 @@ describe('ioredis', () => { ...DEFAULT_ATTRIBUTES, [AttributeNames.DB_STATEMENT]: 'del test', }; - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + await registry.getTracer('ioredis-test').withSpan(span, async () => { try { const result = await client.del('test'); assert.strictEqual(result, 1); @@ -502,8 +507,10 @@ describe('ioredis', () => { IOREDIS_CALLBACK_OPERATIONS.forEach(operation => { it(`should not create a child span for cb style ${operation.description}`, done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry + .getTracer('ioredis-test') + .startSpan('test span'); + registry.getTracer('ioredis-test').withSpan(span, () => { operation.method((err, _) => { assert.ifError(err); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); @@ -518,8 +525,8 @@ describe('ioredis', () => { }); it('should not create a child span for hset promise upon error', async () => { - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('ioredis-test').startSpan('test span'); + await registry.getTracer('ioredis-test').withSpan(span, async () => { try { await client.hset('hash', 'random', 'random'); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); diff --git a/packages/opentelemetry-plugin-mongodb/README.md b/packages/opentelemetry-plugin-mongodb/README.md index dd6697c39e..e9489b0701 100644 --- a/packages/opentelemetry-plugin-mongodb/README.md +++ b/packages/opentelemetry-plugin-mongodb/README.md @@ -23,9 +23,9 @@ OpenTelemetry Mongodb Instrumentation allows the user to automatically collect t To load a specific plugin (mongodb in this case), specify it in the Node Tracer's configuration. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { mongodb: { enabled: true, @@ -38,9 +38,9 @@ const tracer = new NodeTracer({ To load all the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer(); +const registry = new NodeTracerRegistry(); ``` See [examples/mongodb](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/mongodb) for a short example. diff --git a/packages/opentelemetry-plugin-mongodb/src/mongodb.ts b/packages/opentelemetry-plugin-mongodb/src/mongodb.ts index 8d76981177..ebcab73699 100644 --- a/packages/opentelemetry-plugin-mongodb/src/mongodb.ts +++ b/packages/opentelemetry-plugin-mongodb/src/mongodb.ts @@ -18,16 +18,17 @@ /* tslint:disable:deprecation */ import { BasePlugin } from '@opentelemetry/core'; -import { Span, SpanKind, CanonicalCode } from '@opentelemetry/types'; +import { CanonicalCode, Span, SpanKind } from '@opentelemetry/types'; +import * as mongodb from 'mongodb'; +import * as shimmer from 'shimmer'; import { + AttributeNames, Func, + MongodbCommandType, MongoInternalCommand, MongoInternalTopology, - AttributeNames, - MongodbCommandType, } from './types'; -import * as mongodb from 'mongodb'; -import * as shimmer from 'shimmer'; +import { VERSION } from './version'; /** MongoDBCore instrumentation plugin for OpenTelemetry */ export class MongoDBPlugin extends BasePlugin { @@ -40,7 +41,7 @@ export class MongoDBPlugin extends BasePlugin { readonly supportedVersions = ['>=2 <4']; constructor(readonly moduleName: string) { - super(); + super('@opentelemetry/plugin-mongodb-core', VERSION); } /** @@ -106,7 +107,7 @@ export class MongoDBPlugin extends BasePlugin { const resultHandler = typeof options === 'function' ? options : callback; if ( - currentSpan === undefined || + !currentSpan || typeof resultHandler !== 'function' || typeof commands !== 'object' ) { @@ -210,7 +211,7 @@ export class MongoDBPlugin extends BasePlugin { ): mongodb.Cursor { const currentSpan = plugin._tracer.getCurrentSpan(); const resultHandler = args[0]; - if (currentSpan === undefined || typeof resultHandler !== 'function') { + if (!currentSpan || typeof resultHandler !== 'function') { return original.apply(this, args); } const span = plugin._tracer.startSpan(`mongodb.query`, { diff --git a/packages/opentelemetry-plugin-mongodb/test/mongodb.test.ts b/packages/opentelemetry-plugin-mongodb/test/mongodb.test.ts index ce7df375b7..23e3b9d14d 100644 --- a/packages/opentelemetry-plugin-mongodb/test/mongodb.test.ts +++ b/packages/opentelemetry-plugin-mongodb/test/mongodb.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import * as assert from 'assert'; import * as mongodb from 'mongodb'; import { plugin } from '../src'; @@ -65,8 +65,12 @@ function accessCollection( function assertSpans( spans: ReadableSpan[], expectedName: string, - expectedKind: SpanKind + expectedKind: SpanKind, + log = false ) { + if (log) { + console.log(spans); + } assert.strictEqual(spans.length, 2); spans.forEach(span => { assert(span.endTime instanceof Array); @@ -75,10 +79,7 @@ function assertSpans( const [mongoSpan] = spans; assert.strictEqual(mongoSpan.name, expectedName); assert.strictEqual(mongoSpan.kind, expectedKind); - assert.strictEqual( - mongoSpan.attributes[AttributeNames.COMPONENT], - 'mongodb' - ); + assert.strictEqual(mongoSpan.attributes[AttributeNames.COMPONENT], 'mongodb'); assert.strictEqual( mongoSpan.attributes[AttributeNames.PEER_HOSTNAME], process.env.MONGODB_HOST || 'localhost' @@ -104,12 +105,13 @@ describe('MongoDBPlugin', () => { let client: mongodb.MongoClient; let collection: mongodb.Collection; const logger = new NoopLogger(); - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); const memoryExporter = new InMemorySpanExporter(); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const spanProcessor = new SimpleSpanProcessor(memoryExporter); + registry.addSpanProcessor(spanProcessor); before(done => { - plugin.enable(mongodb, tracer, logger); + plugin.enable(mongodb, registry, logger); accessCollection(URL, DB_NAME, COLLECTION_NAME) .then(result => { client = result.client; @@ -155,8 +157,8 @@ describe('MongoDBPlugin', () => { it('should create a child span for insert', done => { const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; - const span = tracer.startSpan(`insertRootSpan`); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan(`insertRootSpan`); + registry.getTracer('default').withSpan(span, () => { collection.insertMany(insertData, (err, result) => { span.end(); assert.ifError(err); @@ -171,8 +173,8 @@ describe('MongoDBPlugin', () => { }); it('should create a child span for update', done => { - const span = tracer.startSpan('updateRootSpan'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('updateRootSpan'); + registry.getTracer('default').withSpan(span, () => { collection.updateOne({ a: 2 }, { $set: { b: 1 } }, (err, result) => { span.end(); assert.ifError(err); @@ -187,8 +189,8 @@ describe('MongoDBPlugin', () => { }); it('should create a child span for remove', done => { - const span = tracer.startSpan('removeRootSpan'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('removeRootSpan'); + registry.getTracer('default').withSpan(span, () => { collection.deleteOne({ a: 3 }, (err, result) => { span.end(); assert.ifError(err); @@ -206,8 +208,8 @@ describe('MongoDBPlugin', () => { /** Should intercept cursor */ describe('Instrumenting cursor operations', () => { it('should create a child span for find', done => { - const span = tracer.startSpan('findRootSpan'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('findRootSpan'); + registry.getTracer('default').withSpan(span, () => { collection.find({}).toArray((err, result) => { span.end(); assert.ifError(err); @@ -225,8 +227,8 @@ describe('MongoDBPlugin', () => { /** Should intercept command */ describe('Instrumenting command operations', () => { it('should create a child span for create index', done => { - const span = tracer.startSpan('indexRootSpan'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('indexRootSpan'); + registry.getTracer('default').withSpan(span, () => { collection.createIndex({ a: 1 }, (err, result) => { span.end(); assert.ifError(err); @@ -252,7 +254,7 @@ describe('MongoDBPlugin', () => { it('should not create a child span for query', done => { const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; - const span = tracer.startSpan('insertRootSpan'); + const span = registry.getTracer('default').startSpan('insertRootSpan'); collection.insertMany(insertData, (err, result) => { span.end(); assert.ifError(err); @@ -262,7 +264,7 @@ describe('MongoDBPlugin', () => { }); it('should not create a child span for cursor', done => { - const span = tracer.startSpan('findRootSpan'); + const span = registry.getTracer('default').startSpan('findRootSpan'); collection.find({}).toArray((err, result) => { span.end(); assert.ifError(err); @@ -272,7 +274,7 @@ describe('MongoDBPlugin', () => { }); it('should not create a child span for command', done => { - const span = tracer.startSpan('indexRootSpan'); + const span = registry.getTracer('default').startSpan('indexRootSpan'); collection.createIndex({ a: 1 }, (err, result) => { span.end(); assert.ifError(err); diff --git a/packages/opentelemetry-plugin-mongodb/tsconfig.json b/packages/opentelemetry-plugin-mongodb/tsconfig.json index 3e83278f6c..a2042cd68b 100644 --- a/packages/opentelemetry-plugin-mongodb/tsconfig.json +++ b/packages/opentelemetry-plugin-mongodb/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "build" }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "test/**/*.ts" ] } diff --git a/packages/opentelemetry-plugin-mysql/src/mysql.ts b/packages/opentelemetry-plugin-mysql/src/mysql.ts index 3255a57c2b..9fcd6e64b6 100644 --- a/packages/opentelemetry-plugin-mysql/src/mysql.ts +++ b/packages/opentelemetry-plugin-mysql/src/mysql.ts @@ -20,9 +20,9 @@ import * as mysqlTypes from 'mysql'; import * as shimmer from 'shimmer'; import { AttributeNames } from './enums'; import { getConnectionAttributes, getSpanName } from './utils'; +import { VERSION } from './version'; export class MysqlPlugin extends BasePlugin { - readonly moduleName = 'mysql'; readonly supportedVersions = ['2.*']; static readonly COMPONENT = 'mysql'; @@ -36,6 +36,10 @@ export class MysqlPlugin extends BasePlugin { private _enabled = false; + constructor(readonly moduleName: string) { + super('@opentelemetry/plugin-mysql', VERSION); + } + protected patch(): typeof mysqlTypes { this._enabled = true; shimmer.wrap( @@ -283,4 +287,4 @@ export class MysqlPlugin extends BasePlugin { } } -export const plugin = new MysqlPlugin(); +export const plugin = new MysqlPlugin(MysqlPlugin.COMPONENT); diff --git a/packages/opentelemetry-plugin-mysql/test/mysql.test.ts b/packages/opentelemetry-plugin-mysql/test/mysql.test.ts index cd207a7216..d422981e7b 100644 --- a/packages/opentelemetry-plugin-mysql/test/mysql.test.ts +++ b/packages/opentelemetry-plugin-mysql/test/mysql.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -38,7 +38,7 @@ describe('mysql@2.x', () => { let connection: mysql.Connection; let pool: mysql.Pool; let poolCluster: mysql.PoolCluster; - const tracer = new NodeTracer({ plugins: {} }); + const registry = new NodeTracerRegistry({ plugins: {} }); const logger = new NoopLogger(); const testMysql = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available const testMysqlLocally = process.env.RUN_MYSQL_TESTS_LOCAL; // For local: spins up local mysql db via docker @@ -52,7 +52,7 @@ describe('mysql@2.x', () => { this.test!.parent!.pending = true; this.skip(); } - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); if (testMysqlLocally) { testUtils.startDocker('mysql'); // wait 15 seconds for docker container to start @@ -71,7 +71,7 @@ describe('mysql@2.x', () => { }); beforeEach(function() { - plugin.enable(mysql, tracer, logger); + plugin.enable(mysql, registry, logger); connection = mysql.createConnection({ port, user, @@ -118,8 +118,8 @@ describe('mysql@2.x', () => { describe('#Connection', () => { it('should intercept connection.query(text: string)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; const query = connection.query(statement); let rows = 0; @@ -140,8 +140,8 @@ describe('mysql@2.x', () => { }); it('should intercept connection.query(text: string, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; connection.query(statement, (err, res) => { assert.ifError(err); @@ -156,8 +156,8 @@ describe('mysql@2.x', () => { }); it('should intercept connection.query(text: options, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; connection.query({ sql: statement, values: [1] }, (err, res) => { assert.ifError(err); @@ -172,8 +172,8 @@ describe('mysql@2.x', () => { }); it('should intercept connection.query(text: options, values: [], callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // but does not match the typings @@ -190,8 +190,8 @@ describe('mysql@2.x', () => { }); it('should intercept connection.query(text: string, values: [], callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; connection.query(statement, [1], (err, res) => { assert.ifError(err); @@ -206,8 +206,8 @@ describe('mysql@2.x', () => { }); it('should intercept connection.query(text: string, value: any, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; connection.query(statement, 1, (err, res) => { assert.ifError(err); @@ -222,8 +222,8 @@ describe('mysql@2.x', () => { }); it('should attach error messages to spans', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; connection.query(statement, (err, res) => { assert.ok(err); @@ -238,8 +238,8 @@ describe('mysql@2.x', () => { describe('#Pool', () => { it('should intercept pool.query(text: string)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; const query = pool.query(statement); let rows = 0; @@ -260,8 +260,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.getConnection().query(text: string)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; pool.getConnection((err, conn) => { const query = conn.query(statement); @@ -284,8 +284,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.query(text: string, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; pool.query(statement, (err, res) => { assert.ifError(err); @@ -300,8 +300,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.getConnection().query(text: string, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; pool.getConnection((err, conn) => { conn.query(statement, (err, res) => { @@ -318,8 +318,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.query(text: options, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; pool.query({ sql: statement, values: [1] }, (err, res) => { assert.ifError(err); @@ -334,8 +334,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.query(text: options, values: [], callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // but does not match the typings @@ -352,8 +352,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.query(text: string, values: [], callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; pool.query(statement, [1], (err, res) => { assert.ifError(err); @@ -368,8 +368,8 @@ describe('mysql@2.x', () => { }); it('should intercept pool.query(text: string, value: any, callback)', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; pool.query(statement, 1, (err, res) => { assert.ifError(err); @@ -384,8 +384,8 @@ describe('mysql@2.x', () => { }); it('should attach error messages to spans', done => { - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; pool.query(statement, (err, res) => { assert.ok(err); @@ -402,8 +402,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: string)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; const query = poolClusterConnection.query(statement); let rows = 0; @@ -427,8 +427,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: string, callback)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+1 as solution'; poolClusterConnection.query(statement, (err, res) => { assert.ifError(err); @@ -446,8 +446,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: options, callback)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; poolClusterConnection.query( { sql: statement, values: [1] }, @@ -468,8 +468,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: options, values: [], callback)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1+? as solution'; // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // but does not match the typings @@ -489,8 +489,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: string, values: [], callback)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; poolClusterConnection.query(statement, [1], (err, res) => { assert.ifError(err); @@ -508,8 +508,8 @@ describe('mysql@2.x', () => { it('should intercept poolClusterConnection.query(text: string, value: any, callback)', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; poolClusterConnection.query(statement, 1, (err, res) => { assert.ifError(err); @@ -527,8 +527,8 @@ describe('mysql@2.x', () => { it('should attach error messages to spans', done => { poolCluster.getConnection((err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT ? as solution'; poolClusterConnection.query(statement, (err, res) => { assert.ok(err); @@ -544,8 +544,8 @@ describe('mysql@2.x', () => { it('should get connection by name', done => { poolCluster.getConnection('name', (err, poolClusterConnection) => { assert.ifError(err); - const span = tracer.startSpan('test span'); - tracer.withSpan(span, () => { + const span = registry.getTracer('default').startSpan('test span'); + registry.getTracer('default').withSpan(span, () => { const statement = 'SELECT 1 as solution'; poolClusterConnection.query(statement, (err, res) => { assert.ifError(err); diff --git a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/src/pg-pool.ts b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/src/pg-pool.ts index be335c1203..0584e29f83 100644 --- a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/src/pg-pool.ts +++ b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/src/pg-pool.ts @@ -25,6 +25,7 @@ import { PgPoolExtended, } from './types'; import * as utils from './utils'; +import { VERSION } from './version'; export class PostgresPoolPlugin extends BasePlugin { protected _config: PostgresPoolPluginOptions; @@ -35,7 +36,7 @@ export class PostgresPoolPlugin extends BasePlugin { readonly supportedVersions = ['2.*']; constructor(readonly moduleName: string) { - super(); + super('@opentelemetry/plugin-pg-pool', VERSION); this._config = {}; } diff --git a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/test/pg-pool.test.ts b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/test/pg-pool.test.ts index 28ad86113a..f2f3ebb862 100644 --- a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/test/pg-pool.test.ts +++ b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg-pool/test/pg-pool.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -92,7 +92,7 @@ const runCallbackTest = ( describe('pg-pool@2.x', () => { let pool: pgPool; - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); const logger = new NoopLogger(); const testPostgres = process.env.TEST_POSTGRES; // For CI: assumes local postgres db is already available const testPostgresLocally = process.env.TEST_POSTGRES_LOCAL; // For local: spins up local postgres db via docker @@ -106,7 +106,7 @@ describe('pg-pool@2.x', () => { this.skip(); } pool = new pgPool(CONFIG); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); if (testPostgresLocally) { testUtils.startDocker('postgres'); } @@ -123,8 +123,8 @@ describe('pg-pool@2.x', () => { }); beforeEach(function() { - plugin.enable(pgPool, tracer, logger); - pgPlugin.enable(pg, tracer, logger); + plugin.enable(pgPool, registry, logger); + pgPlugin.enable(pg, registry, logger); }); afterEach(() => { @@ -152,8 +152,8 @@ describe('pg-pool@2.x', () => { [AttributeNames.DB_STATEMENT]: 'SELECT NOW()', }; const events: TimedEvent[] = []; - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('test-pg-pool').startSpan('test span'); + await registry.getTracer('test-pg-pool').withSpan(span, async () => { const client = await pool.connect(); runCallbackTest(span, pgPoolattributes, events, okStatus, 1, 0); assert.ok(client, 'pool.connect() returns a promise'); @@ -178,8 +178,10 @@ describe('pg-pool@2.x', () => { [AttributeNames.DB_STATEMENT]: 'SELECT NOW()', }; const events: TimedEvent[] = []; - const parentSpan = tracer.startSpan('test span'); - tracer.withSpan(parentSpan, () => { + const parentSpan = registry + .getTracer('test-pg-pool') + .startSpan('test span'); + registry.getTracer('test-pg-pool').withSpan(parentSpan, () => { const resNoPromise = pool.connect((err, client, release) => { if (err) { return done(err); @@ -212,8 +214,8 @@ describe('pg-pool@2.x', () => { [AttributeNames.DB_STATEMENT]: 'SELECT NOW()', }; const events: TimedEvent[] = []; - const span = tracer.startSpan('test span'); - await tracer.withSpan(span, async () => { + const span = registry.getTracer('test-pg-pool').startSpan('test span'); + await registry.getTracer('test-pg-pool').withSpan(span, async () => { try { const result = await pool.query('SELECT NOW()'); runCallbackTest(span, pgPoolattributes, events, okStatus, 2, 0); @@ -235,8 +237,10 @@ describe('pg-pool@2.x', () => { [AttributeNames.DB_STATEMENT]: 'SELECT NOW()', }; const events: TimedEvent[] = []; - const parentSpan = tracer.startSpan('test span'); - tracer.withSpan(parentSpan, () => { + const parentSpan = registry + .getTracer('test-pg-pool') + .startSpan('test span'); + registry.getTracer('test-pg-pool').withSpan(parentSpan, () => { const resNoPromise = pool.query('SELECT NOW()', (err, result) => { if (err) { return done(err); diff --git a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/src/pg.ts b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/src/pg.ts index a6841ae33a..02902df2db 100644 --- a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/src/pg.ts +++ b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/src/pg.ts @@ -16,15 +16,16 @@ import { BasePlugin } from '@opentelemetry/core'; import { CanonicalCode, Span } from '@opentelemetry/types'; +import * as pgTypes from 'pg'; +import * as shimmer from 'shimmer'; import { - PostgresPluginOptions, PgClientExtended, PgPluginQueryConfig, PostgresCallback, + PostgresPluginOptions, } from './types'; -import * as pgTypes from 'pg'; -import * as shimmer from 'shimmer'; import * as utils from './utils'; +import { VERSION } from './version'; export class PostgresPlugin extends BasePlugin { protected _config: PostgresPluginOptions; @@ -37,7 +38,7 @@ export class PostgresPlugin extends BasePlugin { readonly supportedVersions = ['7.*']; constructor(readonly moduleName: string) { - super(); + super('@opentelemetry/plugin-pg', VERSION); this._config = {}; } diff --git a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/test/pg.test.ts b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/test/pg.test.ts index c508f5840f..03834e2534 100644 --- a/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/test/pg.test.ts +++ b/packages/opentelemetry-plugin-postgres/opentelemetry-plugin-pg/test/pg.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -81,7 +81,8 @@ const runCallbackTest = ( describe('pg@7.x', () => { let client: pg.Client; - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); + const tracer = registry.getTracer('external'); const logger = new NoopLogger(); const testPostgres = process.env.RUN_POSTGRES_TESTS; // For CI: assumes local postgres db is already available const testPostgresLocally = process.env.RUN_POSTGRES_TESTS_LOCAL; // For local: spins up local postgres db via docker @@ -94,7 +95,7 @@ describe('pg@7.x', () => { this.test!.parent!.pending = true; this.skip(); } - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); if (testPostgresLocally) { testUtils.startDocker('postgres'); } @@ -115,7 +116,7 @@ describe('pg@7.x', () => { }); beforeEach(function() { - plugin.enable(pg, tracer, logger); + plugin.enable(pg, registry, logger); }); afterEach(() => { diff --git a/packages/opentelemetry-plugin-redis/README.md b/packages/opentelemetry-plugin-redis/README.md index 25f5f62f3f..5751420c8e 100644 --- a/packages/opentelemetry-plugin-redis/README.md +++ b/packages/opentelemetry-plugin-redis/README.md @@ -24,9 +24,9 @@ OpenTelemetry Redis Instrumentation allows the user to automatically collect tra To load a specific plugin (**redis** in this case), specify it in the Node Tracer's configuration ```js -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer({ +const registry = new NodeTracerRegistry({ plugins: { redis: { enabled: true, @@ -39,9 +39,9 @@ const tracer = new NodeTracer({ To load all the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. ```javascript -const { NodeTracer } = require('@opentelemetry/node'); +const { NodeTracerRegistry } = require('@opentelemetry/node'); -const tracer = new NodeTracer(); +const registry = new NodeTracerRegistry(); ``` See [examples/redis](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/redis) for a short example. diff --git a/packages/opentelemetry-plugin-redis/src/redis.ts b/packages/opentelemetry-plugin-redis/src/redis.ts index 5d4cb833f8..0973e52c05 100644 --- a/packages/opentelemetry-plugin-redis/src/redis.ts +++ b/packages/opentelemetry-plugin-redis/src/redis.ts @@ -22,13 +22,14 @@ import { getTracedCreateStreamTrace, getTracedInternalSendCommand, } from './utils'; +import { VERSION } from './version'; export class RedisPlugin extends BasePlugin { static readonly COMPONENT = 'redis'; readonly supportedVersions = ['^2.6.0']; // equivalent to >= 2.6.0 <3 constructor(readonly moduleName: string) { - super(); + super('@opentelemetry/plugin-redis', VERSION); } protected patch() { diff --git a/packages/opentelemetry-plugin-redis/test/redis.test.ts b/packages/opentelemetry-plugin-redis/test/redis.test.ts index 422cfa995a..7cb7a00a45 100644 --- a/packages/opentelemetry-plugin-redis/test/redis.test.ts +++ b/packages/opentelemetry-plugin-redis/test/redis.test.ts @@ -19,7 +19,7 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; -import { NodeTracer } from '@opentelemetry/node'; +import { NodeTracerRegistry } from '@opentelemetry/node'; import { plugin, RedisPlugin } from '../src'; import * as redisTypes from 'redis'; import { NoopLogger } from '@opentelemetry/core'; @@ -48,7 +48,8 @@ const okStatus: Status = { }; describe('redis@2.x', () => { - const tracer = new NodeTracer(); + const registry = new NodeTracerRegistry(); + const tracer = registry.getTracer('external'); let redis: typeof redisTypes; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; @@ -67,8 +68,8 @@ describe('redis@2.x', () => { } redis = require('redis'); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); - plugin.enable(redis, tracer, new NoopLogger()); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + plugin.enable(redis, registry, new NoopLogger()); }); after(() => { diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index 82375d03aa..a64a3f93d9 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -69,15 +69,12 @@ export class XMLHttpRequestPlugin extends BasePlugin { readonly version: string = VERSION; moduleName = this.component; - protected _config!: XMLHttpRequestPluginConfig; - private _tasksCount = 0; private _xhrMem = new WeakMap(); private _usedResources = new WeakSet(); - constructor(config: XMLHttpRequestPluginConfig = {}) { - super(); - this._config = config; + constructor(protected _config: XMLHttpRequestPluginConfig = {}) { + super('@opentelemetry/plugin-xml-http-request', VERSION); } /** diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index 2d920b0bfb..931e31756d 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -27,10 +27,14 @@ import { import { ZoneScopeManager } from '@opentelemetry/scope-zone'; import * as tracing from '@opentelemetry/tracing'; import * as types from '@opentelemetry/types'; -import { PerformanceTimingNames as PTN, WebTracer } from '@opentelemetry/web'; +import { + PerformanceTimingNames as PTN, + WebTracerRegistry, +} from '@opentelemetry/web'; import { AttributeNames } from '../src/enums/AttributeNames'; import { EventNames } from '../src/enums/EventNames'; import { XMLHttpRequestPlugin } from '../src/xhr'; +import { Tracer } from '@opentelemetry/types'; class DummySpanExporter implements tracing.SpanExporter { export(spans: any) {} @@ -97,7 +101,8 @@ describe('xhr', () => { let clearData: any; describe('when request is successful', () => { - let webTracerWithZone: WebTracer; + let webTracerWithZone: Tracer; + let webTracerRegistryWithZone: WebTracerRegistry; let dummySpanExporter: DummySpanExporter; let exportSpy: any; let rootSpan: types.Span; @@ -136,7 +141,7 @@ describe('xhr', () => { spyEntries = sandbox.stub(performance, 'getEntriesByType'); spyEntries.withArgs('resource').returns(resources); - webTracerWithZone = new WebTracer({ + webTracerRegistryWithZone = new WebTracerRegistry({ logLevel: LogLevel.ERROR, httpTextFormat: new B3Format(), scopeManager: new ZoneScopeManager(), @@ -146,9 +151,10 @@ describe('xhr', () => { }), ], }); + webTracerWithZone = webTracerRegistryWithZone.getTracer('xhr-test'); dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); - webTracerWithZone.addSpanProcessor( + webTracerRegistryWithZone.addSpanProcessor( new tracing.SimpleSpanProcessor(dummySpanExporter) ); @@ -403,7 +409,8 @@ describe('xhr', () => { }); describe('when request is NOT successful', () => { - let webTracerWithZone: WebTracer; + let webTracerWithZoneRegistry: WebTracerRegistry; + let webTracerWithZone: Tracer; let dummySpanExporter: DummySpanExporter; let exportSpy: any; let rootSpan: types.Span; @@ -434,16 +441,17 @@ describe('xhr', () => { spyEntries = sandbox.stub(performance, 'getEntriesByType'); spyEntries.withArgs('resource').returns(resources); - webTracerWithZone = new WebTracer({ + webTracerWithZoneRegistry = new WebTracerRegistry({ logLevel: LogLevel.ERROR, scopeManager: new ZoneScopeManager(), plugins: [new XMLHttpRequestPlugin()], }); dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); - webTracerWithZone.addSpanProcessor( + webTracerWithZoneRegistry.addSpanProcessor( new tracing.SimpleSpanProcessor(dummySpanExporter) ); + webTracerWithZone = webTracerWithZoneRegistry.getTracer('xhr-test'); rootSpan = webTracerWithZone.startSpan('root'); diff --git a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts index bd2763247d..67434be058 100644 --- a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts +++ b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts @@ -16,14 +16,16 @@ import * as assert from 'assert'; import * as opentracing from 'opentracing'; -import { BasicTracer, Span } from '@opentelemetry/tracing'; +import { BasicTracerRegistry, Span } from '@opentelemetry/tracing'; import { TracerShim, SpanShim, SpanContextShim } from '../src/shim'; import { INVALID_SPAN_CONTEXT, timeInputToHrTime } from '@opentelemetry/core'; import { performance } from 'perf_hooks'; describe('OpenTracing Shim', () => { - const tracer = new BasicTracer(); - const shimTracer: opentracing.Tracer = new TracerShim(tracer); + const registry = new BasicTracerRegistry(); + const shimTracer: opentracing.Tracer = new TracerShim( + registry.getTracer('default') + ); opentracing.initGlobalTracer(shimTracer); describe('TracerShim', () => { diff --git a/packages/opentelemetry-tracing/README.md b/packages/opentelemetry-tracing/README.md index 8b29052a43..796567fb21 100644 --- a/packages/opentelemetry-tracing/README.md +++ b/packages/opentelemetry-tracing/README.md @@ -25,22 +25,19 @@ npm install --save @opentelemetry/tracing ```js const opentelemetry = require('@opentelemetry/core'); -const { BasicTracer } = require('@opentelemetry/tracing'); +const { BasicTracerRegistry } = require('@opentelemetry/tracing'); -// To start a trace, you first need to initialize the Tracer. -// NOTE: the default OpenTelemetry tracer does not record any tracing information. -const tracer = new BasicTracer(); - -// Initialize the OpenTelemetry APIs to use the BasicTracer bindings -opentelemetry.initGlobalTracer(tracer); +// To start a trace, you first need to initialize the Tracer registry. +// NOTE: the default OpenTelemetry tracer registry does not record any tracing information. +opentelemetry.initGlobalTracer(new BasicTracerRegistry()); // To create a span in a trace, we used the global singleton tracer to start a new span. -const span = opentelemetry.getTracer().startSpan('foo'); +const span = opentelemetry.getTracer('default').startSpan('foo'); -// Create an Attributes +// Set a span attribute span.setAttribute('key', 'value'); -// We must end the spans so they becomes available for exporting. +// We must end the spans so they become available for exporting. span.end(); ``` diff --git a/packages/opentelemetry-tracing/src/BasicTracerRegistry.ts b/packages/opentelemetry-tracing/src/BasicTracerRegistry.ts new file mode 100644 index 0000000000..b646b4a516 --- /dev/null +++ b/packages/opentelemetry-tracing/src/BasicTracerRegistry.ts @@ -0,0 +1,63 @@ +/*! + * Copyright 2019, 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 { ConsoleLogger } from '@opentelemetry/core'; +import * as types from '@opentelemetry/types'; +import { Logger } from '@opentelemetry/types'; +import { SpanProcessor, Tracer } from '.'; +import { DEFAULT_CONFIG } from './config'; +import { MultiSpanProcessor } from './MultiSpanProcessor'; +import { NoopSpanProcessor } from './NoopSpanProcessor'; +import { TracerConfig } from './types'; + +/** + * This class represents a basic tracer registry which platform libraries can extend + */ +export class BasicTracerRegistry implements types.TracerRegistry { + private readonly _registeredSpanProcessors: SpanProcessor[] = []; + private readonly _tracers: Map = new Map(); + + activeSpanProcessor = new NoopSpanProcessor(); + readonly logger: Logger; + + constructor(private _config: TracerConfig = DEFAULT_CONFIG) { + this.logger = _config.logger || new ConsoleLogger(_config.logLevel); + } + + getTracer(name: string, version = '*', config?: TracerConfig): Tracer { + const key = `${name}@${version}`; + if (!this._tracers.has(key)) { + this._tracers.set(key, new Tracer(config || this._config, this)); + } + + return this._tracers.get(key)!; + } + + /** + * Adds a new {@link SpanProcessor} to this tracer. + * @param spanProcessor the new SpanProcessor to be added. + */ + addSpanProcessor(spanProcessor: SpanProcessor): void { + this._registeredSpanProcessors.push(spanProcessor); + this.activeSpanProcessor = new MultiSpanProcessor( + this._registeredSpanProcessors + ); + } + + getActiveSpanProcessor(): SpanProcessor { + return this.activeSpanProcessor; + } +} diff --git a/packages/opentelemetry-tracing/src/Span.ts b/packages/opentelemetry-tracing/src/Span.ts index 0fe7cfdbd2..64a94630e2 100644 --- a/packages/opentelemetry-tracing/src/Span.ts +++ b/packages/opentelemetry-tracing/src/Span.ts @@ -22,7 +22,7 @@ import { timeInputToHrTime, } from '@opentelemetry/core'; import { ReadableSpan } from './export/ReadableSpan'; -import { BasicTracer } from './BasicTracer'; +import { Tracer } from './Tracer'; import { SpanProcessor } from './SpanProcessor'; import { TraceParams } from './types'; @@ -52,7 +52,7 @@ export class Span implements types.Span, ReadableSpan { /** Constructs a new Span instance. */ constructor( - parentTracer: BasicTracer, + parentTracer: Tracer, spanName: string, spanContext: types.SpanContext, kind: types.SpanKind, @@ -68,7 +68,7 @@ export class Span implements types.Span, ReadableSpan { this.startTime = timeInputToHrTime(startTime); this._logger = parentTracer.logger; this._traceParams = parentTracer.getActiveTraceParams(); - this._spanProcessor = parentTracer.activeSpanProcessor; + this._spanProcessor = parentTracer.getActiveSpanProcessor(); this._spanProcessor.onStart(this); } diff --git a/packages/opentelemetry-tracing/src/BasicTracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts similarity index 86% rename from packages/opentelemetry-tracing/src/BasicTracer.ts rename to packages/opentelemetry-tracing/src/Tracer.ts index 65e1fdbc7f..504df8b588 100644 --- a/packages/opentelemetry-tracing/src/BasicTracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -28,19 +28,17 @@ import { TraceFlags, Logger, } from '@opentelemetry/types'; -import { BasicTracerConfig, TraceParams } from './types'; +import { TracerConfig, TraceParams } from './types'; import { ScopeManager } from '@opentelemetry/scope-base'; import { Span } from './Span'; import { mergeConfig } from './utility'; -import { SpanProcessor } from './SpanProcessor'; -import { NoopSpanProcessor } from './NoopSpanProcessor'; -import { MultiSpanProcessor } from './MultiSpanProcessor'; import { DEFAULT_CONFIG } from './config'; +import { BasicTracerRegistry } from './BasicTracerRegistry'; /** * This class represents a basic tracer. */ -export class BasicTracer implements types.Tracer { +export class Tracer implements types.Tracer { private readonly _defaultAttributes: types.Attributes; private readonly _binaryFormat: types.BinaryFormat; private readonly _httpTextFormat: types.HttpTextFormat; @@ -48,13 +46,14 @@ export class BasicTracer implements types.Tracer { private readonly _scopeManager: ScopeManager; private readonly _traceParams: TraceParams; readonly logger: Logger; - private readonly _registeredSpanProcessor: SpanProcessor[] = []; - activeSpanProcessor = new NoopSpanProcessor(); /** * Constructs a new Tracer instance. */ - constructor(config: BasicTracerConfig = DEFAULT_CONFIG) { + constructor( + config: TracerConfig = DEFAULT_CONFIG, + private _tracerRegistry: BasicTracerRegistry + ) { const localConfig = mergeConfig(config); this._binaryFormat = localConfig.binaryFormat; this._defaultAttributes = localConfig.defaultAttributes; @@ -162,15 +161,8 @@ export class BasicTracer implements types.Tracer { return this._traceParams; } - /** - * Adds a new {@link SpanProcessor} to this tracer. - * @param spanProcessor the new SpanProcessor to be added. - */ - addSpanProcessor(spanProcessor: SpanProcessor): void { - this._registeredSpanProcessor.push(spanProcessor); - this.activeSpanProcessor = new MultiSpanProcessor( - this._registeredSpanProcessor - ); + getActiveSpanProcessor() { + return this._tracerRegistry.getActiveSpanProcessor(); } private _getParentSpanContext( diff --git a/packages/opentelemetry-tracing/src/index.ts b/packages/opentelemetry-tracing/src/index.ts index 55a68cbde6..d6fb9fb54b 100644 --- a/packages/opentelemetry-tracing/src/index.ts +++ b/packages/opentelemetry-tracing/src/index.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -export * from './BasicTracer'; +export * from './Tracer'; +export * from './BasicTracerRegistry'; export * from './export/ConsoleSpanExporter'; export * from './export/BatchSpanProcessor'; export * from './export/InMemorySpanExporter'; diff --git a/packages/opentelemetry-tracing/src/types.ts b/packages/opentelemetry-tracing/src/types.ts index ec2977372c..dd2be6b970 100644 --- a/packages/opentelemetry-tracing/src/types.ts +++ b/packages/opentelemetry-tracing/src/types.ts @@ -25,9 +25,9 @@ import { import { LogLevel } from '@opentelemetry/core'; /** - * BasicTracerConfig provides an interface for configuring a Basic Tracer. + * TracerConfig provides an interface for configuring a Basic Tracer. */ -export interface BasicTracerConfig { +export interface TracerConfig { /** * Binary formatter which can serialize/deserialize Spans. */ diff --git a/packages/opentelemetry-tracing/src/utility.ts b/packages/opentelemetry-tracing/src/utility.ts index 605bac8eb8..a417c6e74b 100644 --- a/packages/opentelemetry-tracing/src/utility.ts +++ b/packages/opentelemetry-tracing/src/utility.ts @@ -14,19 +14,19 @@ * limitations under the License. */ -import { BasicTracerConfig } from './types'; import { + DEFAULT_CONFIG, DEFAULT_MAX_ATTRIBUTES_PER_SPAN, DEFAULT_MAX_EVENTS_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN, } from './config'; -import { DEFAULT_CONFIG } from './config'; +import { TracerConfig } from './types'; /** * Function to merge Default configuration (as specified in './config') with * user provided configurations. */ -export function mergeConfig(userConfig: BasicTracerConfig) { +export function mergeConfig(userConfig: TracerConfig) { const traceParams = userConfig.traceParams; const target = Object.assign({}, DEFAULT_CONFIG, userConfig); diff --git a/packages/opentelemetry-tracing/test/BasicTracer.test.ts b/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts similarity index 80% rename from packages/opentelemetry-tracing/test/BasicTracer.test.ts rename to packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts index 92f9bfa1e7..020a5a5ea2 100644 --- a/packages/opentelemetry-tracing/test/BasicTracer.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerRegistry.test.ts @@ -14,62 +14,62 @@ * limitations under the License. */ -import * as assert from 'assert'; import { ALWAYS_SAMPLER, BinaryTraceContext, HttpTraceContext, NEVER_SAMPLER, NoopLogger, - TraceState, NoRecordingSpan, + TraceState, } from '@opentelemetry/core'; -import { TraceFlags } from '@opentelemetry/types'; -import { BasicTracer, Span } from '../src'; import { NoopScopeManager, ScopeManager } from '@opentelemetry/scope-base'; +import { TraceFlags } from '@opentelemetry/types'; +import * as assert from 'assert'; +import { BasicTracerRegistry, Span } from '../src'; -describe('BasicTracer', () => { +describe('BasicTracerRegistry', () => { describe('constructor', () => { it('should construct an instance without any options', () => { - const tracer = new BasicTracer(); - assert.ok(tracer instanceof BasicTracer); + const registry = new BasicTracerRegistry(); + assert.ok(registry instanceof BasicTracerRegistry); }); it('should construct an instance with binary format', () => { - const tracer = new BasicTracer({ + const registry = new BasicTracerRegistry({ binaryFormat: new BinaryTraceContext(), }); - assert.ok(tracer instanceof BasicTracer); + assert.ok(registry instanceof BasicTracerRegistry); }); it('should construct an instance with http text format', () => { - const tracer = new BasicTracer({ + const registry = new BasicTracerRegistry({ httpTextFormat: new HttpTraceContext(), scopeManager: new NoopScopeManager(), }); - assert.ok(tracer instanceof BasicTracer); + assert.ok(registry instanceof BasicTracerRegistry); }); it('should construct an instance with logger', () => { - const tracer = new BasicTracer({ + const registry = new BasicTracerRegistry({ logger: new NoopLogger(), scopeManager: new NoopScopeManager(), }); - assert.ok(tracer instanceof BasicTracer); + assert.ok(registry instanceof BasicTracerRegistry); }); it('should construct an instance with sampler', () => { - const tracer = new BasicTracer({ + const registry = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), sampler: ALWAYS_SAMPLER, }); - assert.ok(tracer instanceof BasicTracer); + assert.ok(registry instanceof BasicTracerRegistry); }); it('should construct an instance with default trace params', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), - }); + }).getTracer('default'); assert.deepStrictEqual(tracer.getActiveTraceParams(), { numberOfAttributesPerSpan: 32, numberOfEventsPerSpan: 128, @@ -78,12 +78,12 @@ describe('BasicTracer', () => { }); it('should construct an instance with customized numberOfAttributesPerSpan trace params', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), traceParams: { numberOfAttributesPerSpan: 100, }, - }); + }).getTracer('default'); assert.deepStrictEqual(tracer.getActiveTraceParams(), { numberOfAttributesPerSpan: 100, numberOfEventsPerSpan: 128, @@ -92,12 +92,12 @@ describe('BasicTracer', () => { }); it('should construct an instance with customized numberOfEventsPerSpan trace params', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), traceParams: { numberOfEventsPerSpan: 300, }, - }); + }).getTracer('default'); assert.deepStrictEqual(tracer.getActiveTraceParams(), { numberOfAttributesPerSpan: 32, numberOfEventsPerSpan: 300, @@ -106,12 +106,12 @@ describe('BasicTracer', () => { }); it('should construct an instance with customized numberOfLinksPerSpan trace params', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), traceParams: { numberOfLinksPerSpan: 10, }, - }); + }).getTracer('default'); assert.deepStrictEqual(tracer.getActiveTraceParams(), { numberOfAttributesPerSpan: 32, numberOfEventsPerSpan: 128, @@ -120,26 +120,26 @@ describe('BasicTracer', () => { }); it('should construct an instance with default attributes', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ defaultAttributes: { region: 'eu-west', asg: 'my-asg', }, }); - assert.ok(tracer instanceof BasicTracer); + assert.ok(tracer instanceof BasicTracerRegistry); }); }); describe('.startSpan()', () => { it('should start a span with name only', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span'); assert.ok(span); assert.ok(span instanceof Span); }); it('should start a span with name and options', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span', {}); assert.ok(span); assert.ok(span instanceof Span); @@ -152,9 +152,9 @@ describe('BasicTracer', () => { }); it('should start a span with defaultAttributes and spanoptions->attributes', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ defaultAttributes: { foo: 'bar' }, - }); + }).getTracer('default'); const span = tracer.startSpan('my-span', { attributes: { foo: 'foo', bar: 'bar' }, }) as Span; @@ -163,16 +163,16 @@ describe('BasicTracer', () => { }); it('should start a span with defaultAttributes and undefined spanoptions->attributes', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ defaultAttributes: { foo: 'bar' }, - }); + }).getTracer('default'); const span = tracer.startSpan('my-span', {}) as Span; assert.deepStrictEqual(span.attributes, { foo: 'bar' }); span.end(); }); it('should start a span with spanoptions->attributes', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span', { attributes: { foo: 'foo', bar: 'bar' }, }) as Span; @@ -181,7 +181,7 @@ describe('BasicTracer', () => { }); it('should start a span with name and parent spancontext', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const state = new TraceState('a=1,b=2'); const span = tracer.startSpan('my-span', { parent: { @@ -199,7 +199,7 @@ describe('BasicTracer', () => { }); it('should start a span with name and parent span', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span'); const childSpan = tracer.startSpan('child-span', { parent: span, @@ -212,7 +212,7 @@ describe('BasicTracer', () => { }); it('should start a span with name and with invalid parent span', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span', { parent: ('invalid-parent' as unknown) as undefined, }) as Span; @@ -220,7 +220,7 @@ describe('BasicTracer', () => { }); it('should start a span with name and with invalid spancontext', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span', { parent: { traceId: '0', spanId: '0' }, }); @@ -233,10 +233,10 @@ describe('BasicTracer', () => { }); it('should return a no recording span when never sampling', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: NEVER_SAMPLER, logger: new NoopLogger(), - }); + }).getTracer('default'); const span = tracer.startSpan('my-span'); assert.ok(span instanceof NoRecordingSpan); const context = span.context(); @@ -248,9 +248,9 @@ describe('BasicTracer', () => { }); it('should create real span when not sampled but recording events true', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: NEVER_SAMPLER, - }); + }).getTracer('default'); const span = tracer.startSpan('my-span', { isRecording: true }); assert.ok(span instanceof Span); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); @@ -258,10 +258,10 @@ describe('BasicTracer', () => { }); it('should not create real span when not sampled and recording events false', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: NEVER_SAMPLER, logger: new NoopLogger(), - }); + }).getTracer('default'); const span = tracer.startSpan('my-span', { isRecording: false }); assert.ok(span instanceof NoRecordingSpan); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); @@ -269,10 +269,10 @@ describe('BasicTracer', () => { }); it('should not create real span when not sampled and no recording events configured', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: NEVER_SAMPLER, logger: new NoopLogger(), - }); + }).getTracer('default'); const span = tracer.startSpan('my-span'); assert.ok(span instanceof NoRecordingSpan); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); @@ -280,10 +280,10 @@ describe('BasicTracer', () => { }); it('should create real span when sampled and recording events true', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: ALWAYS_SAMPLER, scopeManager: new NoopScopeManager(), - }); + }).getTracer('default'); const span = tracer.startSpan('my-span', { isRecording: true }); assert.ok(span instanceof Span); assert.strictEqual(span.context().traceFlags, TraceFlags.SAMPLED); @@ -294,10 +294,10 @@ describe('BasicTracer', () => { const defaultAttributes = { foo: 'bar', }; - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: new NoopScopeManager(), defaultAttributes, - }); + }).getTracer('default'); const span = tracer.startSpan('my-span') as Span; assert.ok(span instanceof Span); @@ -306,25 +306,25 @@ describe('BasicTracer', () => { }); describe('.getCurrentSpan()', () => { - it('should return undefined with NoopScopeManager', () => { - const tracer = new BasicTracer(); + it('should return null with NoopScopeManager', () => { + const tracer = new BasicTracerRegistry().getTracer('default'); const currentSpan = tracer.getCurrentSpan(); assert.deepStrictEqual(currentSpan, undefined); }); it('should return current span when it exists', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ scopeManager: { active: () => 'foo', } as ScopeManager, - }); + }).getTracer('default'); assert.deepStrictEqual(tracer.getCurrentSpan(), 'foo'); }); }); describe('.withSpan()', () => { it('should run scope with NoopScopeManager scope manager', done => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span'); tracer.withSpan(span, () => { assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); @@ -335,7 +335,7 @@ describe('BasicTracer', () => { describe('.bind()', () => { it('should bind scope with NoopScopeManager scope manager', done => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('my-span'); const fn = () => { assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); @@ -348,14 +348,14 @@ describe('BasicTracer', () => { describe('.getBinaryFormat()', () => { it('should get default binary formatter', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); assert.ok(tracer.getBinaryFormat() instanceof BinaryTraceContext); }); }); describe('.getHttpTextFormat()', () => { it('should get default HTTP text formatter', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); assert.ok(tracer.getHttpTextFormat() instanceof HttpTraceContext); }); }); diff --git a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts index 756dbfa734..7464273e8f 100644 --- a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts @@ -16,7 +16,7 @@ import * as assert from 'assert'; import { MultiSpanProcessor } from '../src/MultiSpanProcessor'; -import { SpanProcessor, Span, BasicTracer } from '../src'; +import { SpanProcessor, Span, BasicTracerRegistry } from '../src'; class TestProcessor implements SpanProcessor { spans: Span[] = []; @@ -30,7 +30,7 @@ class TestProcessor implements SpanProcessor { } describe('MultiSpanProcessor', () => { - const tracer = new BasicTracer(); + const tracer = new BasicTracerRegistry().getTracer('default'); const span = tracer.startSpan('one'); it('should handle empty span processor', () => { diff --git a/packages/opentelemetry-tracing/test/Span.test.ts b/packages/opentelemetry-tracing/test/Span.test.ts index 7b0d301678..60cbbbfc21 100644 --- a/packages/opentelemetry-tracing/test/Span.test.ts +++ b/packages/opentelemetry-tracing/test/Span.test.ts @@ -21,7 +21,7 @@ import { TraceFlags, SpanContext, } from '@opentelemetry/types'; -import { BasicTracer, Span } from '../src'; +import { BasicTracerRegistry, Span } from '../src'; import { hrTime, hrTimeToNanoseconds, @@ -33,9 +33,9 @@ import { const performanceTimeOrigin = hrTime(); describe('Span', () => { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ logger: new NoopLogger(), - }); + }).getTracer('default'); const name = 'span1'; const spanContext: SpanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', diff --git a/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts index 04805a0a2d..a12a045392 100644 --- a/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts @@ -18,26 +18,26 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { Span, - BasicTracer, + BasicTracerRegistry, InMemorySpanExporter, BatchSpanProcessor, } from '../../src'; import { NEVER_SAMPLER, ALWAYS_SAMPLER, NoopLogger } from '@opentelemetry/core'; function createSampledSpan(spanName: string): Span { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: ALWAYS_SAMPLER, - }); + }).getTracer('default'); const span = tracer.startSpan(spanName); span.end(); return span as Span; } function createUnSampledSpan(spanName: string): Span { - const tracer = new BasicTracer({ + const tracer = new BasicTracerRegistry({ sampler: NEVER_SAMPLER, logger: new NoopLogger(), - }); + }).getTracer('default'); const span = tracer.startSpan(spanName, { isRecording: false }); span.end(); return span as Span; diff --git a/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts b/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts index 95691ea0e0..c0224d85ca 100644 --- a/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts +++ b/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts @@ -17,7 +17,7 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { - BasicTracer, + BasicTracerRegistry, ConsoleSpanExporter, SimpleSpanProcessor, } from '../../src'; @@ -39,15 +39,17 @@ describe('ConsoleSpanExporter', () => { describe('.export()', () => { it('should export information about span', () => { assert.doesNotThrow(() => { - const basicTracer = new BasicTracer(); + const basicTracerRegistry = new BasicTracerRegistry(); consoleExporter = new ConsoleSpanExporter(); const spyConsole = sinon.spy(console, 'log'); const spyExport = sinon.spy(consoleExporter, 'export'); - basicTracer.addSpanProcessor(new SimpleSpanProcessor(consoleExporter)); + basicTracerRegistry.addSpanProcessor( + new SimpleSpanProcessor(consoleExporter) + ); - const span = basicTracer.startSpan('foo'); + const span = basicTracerRegistry.getTracer('default').startSpan('foo'); span.addEvent('foobar'); span.end(); diff --git a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts index 2de250a515..4eca595acd 100644 --- a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts +++ b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts @@ -18,14 +18,14 @@ import * as assert from 'assert'; import { InMemorySpanExporter, SimpleSpanProcessor, - BasicTracer, + BasicTracerRegistry, } from '../../src'; import { ExportResult } from '@opentelemetry/base'; describe('InMemorySpanExporter', () => { const memoryExporter = new InMemorySpanExporter(); - const tracer = new BasicTracer(); - tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const registry = new BasicTracerRegistry(); + registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); afterEach(() => { // reset spans in memory. @@ -33,9 +33,13 @@ describe('InMemorySpanExporter', () => { }); it('should get finished spans', () => { - const root = tracer.startSpan('root'); - const child = tracer.startSpan('child', { parent: root }); - const grandChild = tracer.startSpan('grand-child', { parent: child }); + const root = registry.getTracer('default').startSpan('root'); + const child = registry + .getTracer('default') + .startSpan('child', { parent: root }); + const grandChild = registry + .getTracer('default') + .startSpan('grand-child', { parent: child }); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); grandChild.end(); @@ -56,15 +60,21 @@ describe('InMemorySpanExporter', () => { }); it('should shutdown the exorter', () => { - const root = tracer.startSpan('root'); - tracer.startSpan('child', { parent: root }).end(); + const root = registry.getTracer('default').startSpan('root'); + registry + .getTracer('default') + .startSpan('child', { parent: root }) + .end(); root.end(); assert.strictEqual(memoryExporter.getFinishedSpans().length, 2); memoryExporter.shutdown(); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); // after shutdown no new spans are accepted - tracer.startSpan('child1', { parent: root }).end(); + registry + .getTracer('default') + .startSpan('child1', { parent: root }) + .end(); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); }); diff --git a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts index 18742a729e..c56d43e870 100644 --- a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts @@ -17,14 +17,14 @@ import * as assert from 'assert'; import { Span, - BasicTracer, + BasicTracerRegistry, InMemorySpanExporter, SimpleSpanProcessor, } from '../../src'; import { SpanContext, SpanKind, TraceFlags } from '@opentelemetry/types'; describe('SimpleSpanProcessor', () => { - const tracer = new BasicTracer(); + const registry = new BasicTracerRegistry(); const exporter = new InMemorySpanExporter(); describe('constructor', () => { @@ -42,7 +42,12 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span(tracer, 'span-name', spanContext, SpanKind.CLIENT); + const span = new Span( + registry.getTracer('default'), + 'span-name', + spanContext, + SpanKind.CLIENT + ); processor.onStart(span); assert.strictEqual(exporter.getFinishedSpans().length, 0); @@ -60,7 +65,12 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.UNSAMPLED, }; - const span = new Span(tracer, 'span-name', spanContext, SpanKind.CLIENT); + const span = new Span( + registry.getTracer('default'), + 'span-name', + spanContext, + SpanKind.CLIENT + ); processor.onStart(span); assert.strictEqual(exporter.getFinishedSpans().length, 0); diff --git a/packages/opentelemetry-types/src/index.ts b/packages/opentelemetry-types/src/index.ts index 97a8409bf9..e73c896f2e 100644 --- a/packages/opentelemetry-types/src/index.ts +++ b/packages/opentelemetry-types/src/index.ts @@ -35,5 +35,6 @@ export * from './trace/span_kind'; export * from './trace/status'; export * from './trace/TimedEvent'; export * from './trace/tracer'; +export * from './trace/tracer_registry'; export * from './trace/trace_flags'; export * from './trace/trace_state'; diff --git a/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts b/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts index efc63f8edf..3462a5df09 100644 --- a/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts +++ b/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Tracer } from '../tracer'; import { Logger } from '../../common/Logger'; +import { TracerRegistry } from '../tracer_registry'; /** Interface Plugin to apply patch. */ // tslint:disable-next-line:no-any @@ -32,13 +32,13 @@ export interface Plugin { * Method that enables the instrumentation patch. * @param moduleExports The value of the `module.exports` property that would * normally be exposed by the required module. ex: `http`, `https` etc. - * @param tracer a tracer instance. + * @param TracerRegistry a tracer registry. * @param logger a logger instance. * @param [config] an object to configure the plugin. */ enable( moduleExports: T, - tracer: Tracer, + TracerRegistry: TracerRegistry, logger: Logger, config?: PluginConfig ): T; diff --git a/packages/opentelemetry-types/src/trace/tracer_registry.ts b/packages/opentelemetry-types/src/trace/tracer_registry.ts new file mode 100644 index 0000000000..ce2c36cdb1 --- /dev/null +++ b/packages/opentelemetry-types/src/trace/tracer_registry.ts @@ -0,0 +1,31 @@ +/*! + * Copyright 2019, 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 { Tracer } from './tracer'; + +/** + * TracerRegistry provides an interface for creating {@link Tracer}s + */ +export interface TracerRegistry { + /** + * Returns a Tracer, creating one if one with the given name and version is not already created + * + * If there is no Span associated with the current context, null is returned. + * + * @returns Tracer A Tracer with the given name and version + */ + getTracer(name: string, version?: string): Tracer; +} diff --git a/packages/opentelemetry-web/src/WebTracer.ts b/packages/opentelemetry-web/src/WebTracerRegistry.ts similarity index 88% rename from packages/opentelemetry-web/src/WebTracer.ts rename to packages/opentelemetry-web/src/WebTracerRegistry.ts index b71c53ef4b..cf4db8114b 100644 --- a/packages/opentelemetry-web/src/WebTracer.ts +++ b/packages/opentelemetry-web/src/WebTracerRegistry.ts @@ -15,13 +15,13 @@ */ import { BasePlugin } from '@opentelemetry/core'; -import { BasicTracer, BasicTracerConfig } from '@opentelemetry/tracing'; +import { BasicTracerRegistry, TracerConfig } from '@opentelemetry/tracing'; import { StackScopeManager } from './StackScopeManager'; /** * WebTracerConfig provides an interface for configuring a Web Tracer. */ -export interface WebTracerConfig extends BasicTracerConfig { +export interface WebTracerConfig extends TracerConfig { /** * plugins to be used with tracer, they will be enabled automatically */ @@ -31,7 +31,7 @@ export interface WebTracerConfig extends BasicTracerConfig { /** * This class represents a web tracer with {@link StackScopeManager} */ -export class WebTracer extends BasicTracer { +export class WebTracerRegistry extends BasicTracerRegistry { /** * Constructs a new Tracer instance. * @param config Web Tracer config diff --git a/packages/opentelemetry-web/src/index.ts b/packages/opentelemetry-web/src/index.ts index 250c44496e..a06fb3cfa1 100644 --- a/packages/opentelemetry-web/src/index.ts +++ b/packages/opentelemetry-web/src/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export * from './WebTracer'; +export * from './WebTracerRegistry'; export * from './StackScopeManager'; export * from './enums/PerformanceTimingNames'; export * from './types'; diff --git a/packages/opentelemetry-web/test/WebTracer.test.ts b/packages/opentelemetry-web/test/WebTracer.test.ts index 5aa3a5a859..140571405c 100644 --- a/packages/opentelemetry-web/test/WebTracer.test.ts +++ b/packages/opentelemetry-web/test/WebTracer.test.ts @@ -15,22 +15,23 @@ */ import { BasePlugin } from '@opentelemetry/core'; +import { ZoneScopeManager } from '@opentelemetry/scope-zone'; +import { Tracer, TracerConfig } from '@opentelemetry/tracing'; import * as assert from 'assert'; import * as sinon from 'sinon'; -import { BasicTracerConfig } from '@opentelemetry/tracing'; import { WebTracerConfig } from '../src'; import { StackScopeManager } from '../src/StackScopeManager'; -import { WebTracer } from '../src/WebTracer'; -import { ZoneScopeManager } from '@opentelemetry/scope-zone'; +import { WebTracerRegistry } from '../src/WebTracerRegistry'; class DummyPlugin extends BasePlugin { + constructor() { + super('dummy'); + } patch() {} - unpatch() {} } describe('WebTracer', () => { - let tracer: WebTracer; describe('constructor', () => { let defaultOptions: WebTracerConfig; @@ -41,17 +42,19 @@ describe('WebTracer', () => { }); it('should construct an instance with required only options', () => { - tracer = new WebTracer(Object.assign({}, defaultOptions)); - assert.ok(tracer instanceof WebTracer); + const tracer = new WebTracerRegistry( + Object.assign({}, defaultOptions) + ).getTracer('default'); + assert.ok(tracer instanceof Tracer); }); it('should enable the scope manager', () => { - let options: BasicTracerConfig; + let options: TracerConfig; const scopeManager = new StackScopeManager(); options = { scopeManager }; const spy = sinon.spy(scopeManager, 'enable'); - tracer = new WebTracer(options); + new WebTracerRegistry(options); assert.ok(spy.calledOnce === true); }); @@ -68,7 +71,7 @@ describe('WebTracer', () => { const plugins = [dummyPlugin1, dummyPlugin2]; options = { plugins, scopeManager }; - tracer = new WebTracer(options); + new WebTracerRegistry(options); assert.ok(spyEnable1.calledOnce === true); assert.ok(spyEnable2.calledOnce === true); @@ -76,15 +79,15 @@ describe('WebTracer', () => { it('should work without default scope manager', () => { assert.doesNotThrow(() => { - tracer = new WebTracer({}); + new WebTracerRegistry({}); }); }); describe('when scopeManager is "ZoneScopeManager"', () => { it('should correctly return the scopes for 2 parallel actions', () => { - const webTracerWithZone = new WebTracer({ + const webTracerWithZone = new WebTracerRegistry({ scopeManager: new ZoneScopeManager(), - }); + }).getTracer('default'); const rootSpan = webTracerWithZone.startSpan('rootSpan');