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 <mayurkale@google.com>
This commit is contained in:
Daniel Dyla 2020-01-09 11:29:38 -05:00 committed by Mayur Kale
parent 059595a215
commit 18c6aa4f19
107 changed files with 981 additions and 942 deletions

1
.gitignore vendored
View File

@ -71,6 +71,7 @@ docs
#lerna #lerna
.changelog .changelog
package.json.lerna_backup
# OS generated files # OS generated files
.DS_Store .DS_Store

View File

@ -2,26 +2,26 @@
const benchmark = require('./benchmark'); const benchmark = require('./benchmark');
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { BasicTracer, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { BasicTracerRegistry, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const exporter = new InMemorySpanExporter(); const exporter = new InMemorySpanExporter();
const logger = new opentelemetry.NoopLogger(); const logger = new opentelemetry.NoopLogger();
const setups = [ const setups = [
{ {
name: 'BasicTracer', name: 'BasicTracerRegistry',
tracer: new BasicTracer({ logger }) registry: new BasicTracerRegistry({ logger })
}, },
{ {
name: 'NodeTracer', name: 'NodeTracerRegistry',
tracer: new NodeTracer({ logger }) registry: new NodeTracerRegistry({ logger })
} }
]; ];
for (const setup of setups) { for (const setup of setups) {
console.log(`Beginning ${setup.name} Benchmark...`); console.log(`Beginning ${setup.name} Benchmark...`);
const tracer = setup.tracer; const tracer = setup.registry.getTracer("benchmark");
const suite = benchmark() const suite = benchmark()
.add('#startSpan', function () { .add('#startSpan', function () {
const span = tracer.startSpan('op'); const span = tracer.startSpan('op');
@ -55,7 +55,7 @@ for (const setup of setups) {
.add('#startSpan with SimpleSpanProcessor', function () { .add('#startSpan with SimpleSpanProcessor', function () {
const simpleSpanProcessor = new SimpleSpanProcessor(exporter); const simpleSpanProcessor = new SimpleSpanProcessor(exporter);
tracer.addSpanProcessor(simpleSpanProcessor); registry.addSpanProcessor(simpleSpanProcessor);
const span = tracer.startSpan('op'); const span = tracer.startSpan('op');
span.end(); span.end();
@ -64,7 +64,7 @@ for (const setup of setups) {
.add('#startSpan with BatchSpanProcessor', function () { .add('#startSpan with BatchSpanProcessor', function () {
const batchSpanProcessor = new BatchSpanProcessor(exporter); const batchSpanProcessor = new BatchSpanProcessor(exporter);
tracer.addSpanProcessor(batchSpanProcessor); registry.addSpanProcessor(batchSpanProcessor);
const span = tracer.startSpan('op'); const span = tracer.startSpan('op');
span.end(); span.end();
batchSpanProcessor.shutdown(); batchSpanProcessor.shutdown();

View File

@ -1,5 +1,5 @@
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { BasicTracer, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { BasicTracerRegistry, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const { CollectorExporter } = require('@opentelemetry/exporter-collector');
@ -20,16 +20,17 @@ if (EXPORTER.toLowerCase().startsWith('z')) {
exporter = new CollectorExporter(options); exporter = new CollectorExporter(options);
} }
const tracer = new BasicTracer(); const registry = new BasicTracerRegistry();
// Configure span processor to send spans to the provided exporter // 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
const tracer = opentelemetry.getTracer('example-basic-tracer-node')
// Create a span. A span must be closed. // 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++) { for (let i = 0; i < 10; i++) {
doWork(span); doWork(span);
} }
@ -42,7 +43,7 @@ exporter.shutdown();
function doWork(parent) { function doWork(parent) {
// Start another span. In this example, the main method already started a // 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. // 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 parent: parent
}); });

View File

@ -1,10 +1,10 @@
const opentelemetry = require('@opentelemetry/core'); 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 { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const { CollectorExporter } = require('@opentelemetry/exporter-collector');
const tracer = new BasicTracer(); const registry = new BasicTracerRegistry();
const zipkinExporter = new ZipkinExporter({serviceName: 'basic-service'}); const zipkinExporter = new ZipkinExporter({serviceName: 'basic-service'});
const jaegerExporter = new JaegerExporter({ 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 // It is recommended to use this BatchSpanProcessor for better performance
// and optimization, especially in production. // 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. bufferSize: 10 // This is added for example, default size is 100.
})); }));
// It is recommended to use SimpleSpanProcessor in case of Jaeger exporter as // It is recommended to use SimpleSpanProcessor in case of Jaeger exporter as
// it's internal client already handles the spans with batching logic. // 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
const tracer = opentelemetry.getTracer('default');
// Create a span. A span must be closed. // 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++) { for (let i = 0; i < 10; i++) {
doWork(span); doWork(span);
} }
@ -43,7 +44,7 @@ collectorExporter.shutdown();
function doWork(parent) { function doWork(parent) {
// Start another span. In this example, the main method already started a // 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. // 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 parent: parent
}); });

View File

@ -10,7 +10,7 @@ const config = require('./setup');
config.setupTracerAndExporters('dns-client-service'); config.setupTracerAndExporters('dns-client-service');
const dns = require('dns').promises; 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. */ /** A function which makes a dns lookup and handles response. */
function makeLookup() { function makeLookup() {

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || ''; const EXPORTER = process.env.EXPORTER || '';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
      plugins: {       plugins: {
          dns: {           dns: {
            enabled: true,             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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -14,7 +14,7 @@ const grpc = require('grpc');
const messages = require('./helloworld_pb'); const messages = require('./helloworld_pb');
const services = require('./helloworld_grpc_pb'); const services = require('./helloworld_grpc_pb');
const PORT = 50051; const PORT = 50051;
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-grpc-client');
/** A function which makes requests and handles response. */ /** A function which makes requests and handles response. */
function main() { function main() {

View File

@ -10,7 +10,7 @@ const config = require('./setup');
config.setupTracerAndExporters('grpc-server-service'); config.setupTracerAndExporters('grpc-server-service');
const grpc = require('grpc'); const grpc = require('grpc');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-grpc-server');
const messages = require('./helloworld_pb'); const messages = require('./helloworld_pb');
const services = require('./helloworld_grpc_pb'); const services = require('./helloworld_grpc_pb');

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || ''; const EXPORTER = process.env.EXPORTER || '';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
grpc: { grpc: {
enabled: true, 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -13,7 +13,7 @@ const path = require('path');
const grpc = require('grpc'); const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader'); 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_PATH = path.join(__dirname, 'protos/defs.proto');
const PROTO_OPTIONS = { keepCase: true, enums: String, defaults: true, oneofs: true }; const PROTO_OPTIONS = { keepCase: true, enums: String, defaults: true, oneofs: true };

View File

@ -19,7 +19,7 @@ const PROTO_OPTIONS = { keepCase: true, enums: String, defaults: true, oneofs: t
const definition = protoLoader.loadSync(PROTO_PATH, PROTO_OPTIONS); const definition = protoLoader.loadSync(PROTO_PATH, PROTO_OPTIONS);
const rpcProto = grpc.loadPackageDefinition(definition).rpc; const rpcProto = grpc.loadPackageDefinition(definition).rpc;
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-grpc-capitalize-server');
/** Implements the Capitalize RPC method. */ /** Implements the Capitalize RPC method. */
function capitalize(call, callback) { function capitalize(call, callback) {

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || ''; const EXPORTER = process.env.EXPORTER || '';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
grpc: { grpc: {
enabled: true, enabled: true,
@ -31,10 +31,10 @@ function setupTracerAndExporters(service) {
// It is recommended to use this `BatchSpanProcessor` for better performance // It is recommended to use this `BatchSpanProcessor` for better performance
// and optimization, especially in production. // and optimization, especially in production.
tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); registry.addSpanProcessor(new SimpleSpanProcessor(exporter));
// Initialize the OpenTelemetry APIs to use the BasicTracer bindings // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -10,7 +10,7 @@ const config = require('./setup');
config.setupTracerAndExporters('http-client-service'); config.setupTracerAndExporters('http-client-service');
const http = require('http'); const http = require('http');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-http-client');
/** A function which makes requests and handles response. */ /** A function which makes requests and handles response. */
function makeRequest() { function makeRequest() {

View File

@ -9,7 +9,7 @@ const config = require('./setup');
config.setupTracerAndExporters('http-server-service'); config.setupTracerAndExporters('http-server-service');
const http = require('http'); 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. */ /** Starts a HTTP server that receives requests on sample server port. */
function startServer (port) { function startServer (port) {

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || ''; const EXPORTER = process.env.EXPORTER || '';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
let exporter; let exporter;
if (EXPORTER.toLowerCase().startsWith('z')) { 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -9,7 +9,7 @@ const config = require('./setup');
config.setupTracerAndExporters('https-client-service'); config.setupTracerAndExporters('https-client-service');
const https = require('https'); const https = require('https');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-https-client');
/** A function which makes requests and handles response. */ /** A function which makes requests and handles response. */
function makeRequest() { function makeRequest() {

View File

@ -10,7 +10,7 @@ const config = require('./setup');
config.setupTracerAndExporters('https-server-service'); config.setupTracerAndExporters('https-server-service');
const https = require('https'); 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. */ /** Starts a HTTPs server that receives requests on sample server port. */
function startServer (port) { function startServer (port) {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
@ -9,7 +9,7 @@ const EXPORTER = process.env.EXPORTER || '';
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
let exporter; let exporter;
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
if (EXPORTER.toLowerCase().startsWith('z')) { if (EXPORTER.toLowerCase().startsWith('z')) {
exporter = new ZipkinExporter({ 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -10,7 +10,7 @@ const config = require('./setup');
config.setupTracerAndExporters('http-client-service'); config.setupTracerAndExporters('http-client-service');
const http = require('http'); const http = require('http');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-mysql-http-client');
/** A function which makes requests and handles response. */ /** A function which makes requests and handles response. */
function makeRequest() { function makeRequest() {

View File

@ -11,7 +11,7 @@ config.setupTracerAndExporters('http-mysql-server-service');
const mysql = require('mysql'); const mysql = require('mysql');
const http = require('http'); const http = require('http');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-mysql-http-server');
const pool = mysql.createPool({ const pool = mysql.createPool({
host : 'localhost', host : 'localhost',

View File

@ -1,13 +1,13 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
mysql: { mysql: {
enabled: true, enabled: true,
@ -20,15 +20,15 @@ function setupTracerAndExporters(service) {
} }
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({ registry.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({
serviceName: service, serviceName: service,
}))); })));
tracer.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({ registry.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({
serviceName: service, serviceName: service,
}))); })));
// Initialize the OpenTelemetry APIs to use the BasicTracer bindings // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -1,17 +1,17 @@
"use strict"; "use strict";
const { NodeTracer } = require("@opentelemetry/node"); const { NodeTracerRegistry } = require("@opentelemetry/node");
const { SimpleSpanProcessor } = require("@opentelemetry/tracing"); const { SimpleSpanProcessor } = require("@opentelemetry/tracing");
const { JaegerExporter } = require("@opentelemetry/exporter-jaeger"); const { JaegerExporter } = require("@opentelemetry/exporter-jaeger");
const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin");
const { TracerShim } = require("@opentelemetry/shim-opentracing"); const { TracerShim } = require("@opentelemetry/shim-opentracing");
function shim(serviceName) { 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) { function getExporter(serviceName) {

View File

@ -4,7 +4,7 @@ const opentelemetry = require('@opentelemetry/core');
const types = require('@opentelemetry/types'); const types = require('@opentelemetry/types');
const config = require('./setup'); const config = require('./setup');
config.setupTracerAndExporters('redis-client-service'); config.setupTracerAndExporters('redis-client-service');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-redis-client');
const axios = require('axios').default; const axios = require('axios').default;
function makeRequest() { function makeRequest() {

View File

@ -4,7 +4,7 @@
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const config = require('./setup'); const config = require('./setup');
config.setupTracerAndExporters('redis-server-service'); config.setupTracerAndExporters('redis-server-service');
const tracer = opentelemetry.getTracer(); const tracer = opentelemetry.getTracer('example-redis-server');
// Require in rest of modules // Require in rest of modules
const express = require('express'); const express = require('express');

View File

@ -1,14 +1,14 @@
'use strict'; 'use strict';
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || ''; const EXPORTER = process.env.EXPORTER || '';
function setupTracerAndExporters(service) { function setupTracerAndExporters(service) {
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
let exporter; let exporter;
if (EXPORTER.toLowerCase().startsWith('z')) { 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 // Initialize the OpenTelemetry APIs to use the BasicTracerRegistry bindings
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
} }
exports.setupTracerAndExporters = setupTracerAndExporters; exports.setupTracerAndExporters = setupTracerAndExporters;

View File

@ -1,26 +1,27 @@
import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing';
import { WebTracer } from '@opentelemetry/web'; import { WebTracerRegistry } from '@opentelemetry/web';
import { DocumentLoad } from '@opentelemetry/plugin-document-load'; import { DocumentLoad } from '@opentelemetry/plugin-document-load';
import { ZoneScopeManager } from '@opentelemetry/scope-zone'; import { ZoneScopeManager } from '@opentelemetry/scope-zone';
import { CollectorExporter } from '@opentelemetry/exporter-collector' import { CollectorExporter } from '@opentelemetry/exporter-collector'
const webTracer = new WebTracer({ const registry = new WebTracerRegistry({
plugins: [ plugins: [
new DocumentLoad() 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(), scopeManager: new ZoneScopeManager(),
plugins: [ plugins: [
new DocumentLoad() new DocumentLoad()
] ]
}); });
webTracerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); registryWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
webTracerWithZone.addSpanProcessor(new SimpleSpanProcessor(new CollectorExporter())); 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 // example of keeping track of scope between async operations
const prepareClickEvent = () => { 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 url2 = 'https://raw.githubusercontent.com/open-telemetry/opentelemetry-js/master/packages/opentelemetry-web/package.json';
const element = document.getElementById('button1'); const element = document.getElementById('button1');
let mainSpan = webTracerWithZone.startSpan('main-span'); let mainSpan = tracerWithZone.startSpan('main-span');
webTracerWithZone.bind(element, mainSpan); tracerWithZone.bind(element, mainSpan);
const onClick = () => { const onClick = () => {
const span1 = webTracerWithZone.startSpan(`files-series-info-1`, { const span1 = tracerWithZone.startSpan(`files-series-info-1`, {
parent: webTracerWithZone.getCurrentSpan() parent: tracerWithZone.getCurrentSpan()
}); });
const span2 = webTracerWithZone.startSpan(`files-series-info-2`, { const span2 = tracerWithZone.startSpan(`files-series-info-2`, {
parent: webTracerWithZone.getCurrentSpan() parent: tracerWithZone.getCurrentSpan()
}); });
webTracerWithZone.withSpan(span1, () => { tracerWithZone.withSpan(span1, () => {
getData(url1).then((data) => { 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); console.log('info from package.json', data.description, data.version);
webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); tracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed');
span1.end(); span1.end();
}); });
}); });
webTracerWithZone.withSpan(span2, () => { tracerWithZone.withSpan(span2, () => {
getData(url2).then((data) => { getData(url2).then((data) => {
setTimeout(() => { 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); console.log('info from package.json', data.description, data.version);
webTracerWithZone.getCurrentSpan().addEvent('fetching-span2-completed'); tracerWithZone.getCurrentSpan().addEvent('fetching-span2-completed');
span2.end(); span2.end();
}, 100); }, 100);
}); });

View File

@ -27,10 +27,10 @@ export * from './trace/globaltracer-utils';
export * from './trace/instrumentation/BasePlugin'; export * from './trace/instrumentation/BasePlugin';
export * from './trace/NoopSpan'; export * from './trace/NoopSpan';
export * from './trace/NoopTracer'; export * from './trace/NoopTracer';
export * from './trace/NoopTracerRegistry';
export * from './trace/NoRecordingSpan'; export * from './trace/NoRecordingSpan';
export * from './trace/sampler/ProbabilitySampler'; export * from './trace/sampler/ProbabilitySampler';
export * from './trace/spancontext-utils'; export * from './trace/spancontext-utils';
export * from './trace/TracerDelegate';
export * from './trace/TraceState'; export * from './trace/TraceState';
export * from './metrics/NoopMeter'; export * from './metrics/NoopMeter';
export * from './utils/url'; export * from './utils/url';

View File

@ -59,3 +59,5 @@ export class NoopTracer implements Tracer {
return NOOP_HTTP_TEXT_FORMAT; return NOOP_HTTP_TEXT_FORMAT;
} }
} }
export const noopTracer = new NoopTracer();

View File

@ -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;
}
}

View File

@ -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<T>(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<T extends (...args: unknown[]) => ReturnType<T>>(
span: types.Span,
fn: T
): ReturnType<T> {
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
);
}
}

View File

@ -15,21 +15,31 @@
*/ */
import * as types from '@opentelemetry/types'; 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 * Set the current global tracer. Returns the initialized global tracer
*/ */
export function initGlobalTracer(tracer: types.Tracer): types.Tracer { export function initGlobalTracerRegistry(
return (globalTracerDelegate = new TracerDelegate(tracer)); tracerRegistry: types.TracerRegistry
): types.TracerRegistry {
return (globalTracerRegistry = tracerRegistry);
} }
/** /**
* Returns the global tracer * Returns the global tracer registry.
*/ */
export function getTracer(): types.Tracer { export function getTracerRegistry(): types.TracerRegistry {
// Return the global tracer delegate // Return the global tracer registry
return globalTracerDelegate; 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);
} }

View File

@ -21,6 +21,7 @@ import {
PluginConfig, PluginConfig,
PluginInternalFiles, PluginInternalFiles,
PluginInternalFilesVersion, PluginInternalFilesVersion,
TracerRegistry,
} from '@opentelemetry/types'; } from '@opentelemetry/types';
import * as semver from 'semver'; import * as semver from 'semver';
import * as path from 'path'; import * as path from 'path';
@ -39,14 +40,22 @@ export abstract class BasePlugin<T> implements Plugin<T> {
protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports
protected _config!: PluginConfig; protected _config!: PluginConfig;
constructor(
protected readonly _tracerName: string,
protected readonly _tracerVersion?: string
) {}
enable( enable(
moduleExports: T, moduleExports: T,
tracer: Tracer, tracerRegistry: TracerRegistry,
logger: Logger, logger: Logger,
config?: PluginConfig config?: PluginConfig
): T { ): T {
this._moduleExports = moduleExports; this._moduleExports = moduleExports;
this._tracer = tracer; this._tracer = tracerRegistry.getTracer(
this._tracerName,
this._tracerVersion
);
this._logger = logger; this._logger = logger;
this._internalFilesExports = this._loadInternalFilesExports(); this._internalFilesExports = this._loadInternalFilesExports();
if (config) this._config = config; if (config) this._config = config;

View File

@ -14,12 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { BasePlugin, NoopTracer, NoopLogger } from '../../src';
import * as assert from 'assert'; import * as assert from 'assert';
import * as path from 'path'; 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'; import * as types from './fixtures/test-package/foo/bar/internal';
const tracer = new NoopTracer(); const registry = new NoopTracerRegistry();
const logger = new NoopLogger(); const logger = new NoopLogger();
describe('BasePlugin', () => { describe('BasePlugin', () => {
@ -28,7 +29,7 @@ describe('BasePlugin', () => {
const testPackage = require('./fixtures/test-package'); const testPackage = require('./fixtures/test-package');
const plugin = new TestPlugin(); const plugin = new TestPlugin();
assert.doesNotThrow(() => { assert.doesNotThrow(() => {
plugin.enable(testPackage, tracer, logger); plugin.enable(testPackage, registry, logger);
}); });
// @TODO: https://github.com/open-telemetry/opentelemetry-js/issues/285 // @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 version = '0.1.0';
readonly _basedir = basedir; readonly _basedir = basedir;
constructor() {
super('test-package.opentelemetry');
}
protected readonly _internalFilesList = { protected readonly _internalFilesList = {
'0.1.0': { '0.1.0': {
internal: 'foo/bar/internal.js', internal: 'foo/bar/internal.js',

View File

@ -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);
}
}
});

View File

@ -17,11 +17,12 @@
import * as assert from 'assert'; import * as assert from 'assert';
import * as types from '@opentelemetry/types'; import * as types from '@opentelemetry/types';
import { import {
getTracer, getTracerRegistry,
initGlobalTracer, initGlobalTracerRegistry,
} from '../../src/trace/globaltracer-utils'; } from '../../src/trace/globaltracer-utils';
import { NoopTracer, NoopSpan } from '../../src'; import { NoopTracer, NoopSpan } from '../../src';
import { TraceFlags } from '@opentelemetry/types'; import { TraceFlags } from '@opentelemetry/types';
import { NoopTracerRegistry } from '../../src/trace/NoopTracerRegistry';
describe('globaltracer-utils', () => { describe('globaltracer-utils', () => {
const functions = [ const functions = [
@ -32,13 +33,13 @@ describe('globaltracer-utils', () => {
'getHttpTextFormat', 'getHttpTextFormat',
]; ];
it('should expose a tracer via getTracer', () => { it('should expose a tracer registry via getTracerRegistry', () => {
const tracer = getTracer(); const tracer = getTracerRegistry();
assert.ok(tracer); assert.ok(tracer);
assert.strictEqual(typeof tracer, 'object'); assert.strictEqual(typeof tracer, 'object');
}); });
describe('GlobalTracer', () => { describe('GlobalTracerRegistry', () => {
const spanContext = { const spanContext = {
traceId: 'd4cda95b652f4a1592b449d5929fda1b', traceId: 'd4cda95b652f4a1592b449d5929fda1b',
spanId: '6e0c63257de34c92', spanId: '6e0c63257de34c92',
@ -47,12 +48,12 @@ describe('globaltracer-utils', () => {
const dummySpan = new NoopSpan(spanContext); const dummySpan = new NoopSpan(spanContext);
afterEach(() => { afterEach(() => {
initGlobalTracer(new NoopTracer()); initGlobalTracerRegistry(new NoopTracerRegistry());
}); });
it('should not crash', () => { it('should not crash', () => {
functions.forEach(fn => { functions.forEach(fn => {
const tracer = getTracer(); const tracer = getTracerRegistry();
try { try {
((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function ((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function
assert.ok(true, fn); assert.ok(true, fn);
@ -64,8 +65,9 @@ describe('globaltracer-utils', () => {
}); });
}); });
it('should use the global tracer', () => { it('should use the global tracer registry', () => {
const tracer = initGlobalTracer(new TestTracer()); initGlobalTracerRegistry(new TestTracerRegistry());
const tracer = getTracerRegistry().getTracer('name');
const span = tracer.startSpan('test'); const span = tracer.startSpan('test');
assert.deepStrictEqual(span, dummySpan); assert.deepStrictEqual(span, dummySpan);
}); });
@ -78,5 +80,11 @@ describe('globaltracer-utils', () => {
return dummySpan; return dummySpan;
} }
} }
class TestTracerRegistry extends NoopTracerRegistry {
getTracer(_name: string, version?: string) {
return new TestTracer();
}
}
}); });
}); });

View File

@ -35,18 +35,18 @@ opentelemetry.initGlobalTracer(tracer);
## Usage in Node ## Usage in Node
```js ```js
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { BasicTracer, SimpleSpanProcessor } = require('@opentelemetry/tracing'); const { BasicTracerRegistry, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const { CollectorExporter } = require('@opentelemetry/exporter-collector');
const collectorOptions = { const collectorOptions = {
url: '<opentelemetry-collector-url>' // url is optional and can be omitted - default is http://localhost:55678/v1/trace url: '<opentelemetry-collector-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); const exporter = new CollectorExporter(collectorOptions);
tracer.addSpanProcessor(new SimpleSpanProcessor(exporter)); registry.addSpanProcessor(new SimpleSpanProcessor(exporter));
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
``` ```

View File

@ -16,7 +16,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import * as types from '@opentelemetry/types'; import * as types from '@opentelemetry/types';
import { Span, BasicTracer } from '@opentelemetry/tracing'; import { Span, BasicTracerRegistry } from '@opentelemetry/tracing';
import { import {
NoopLogger, NoopLogger,
hrTimeToMicroseconds, hrTimeToMicroseconds,
@ -32,9 +32,9 @@ import {
import * as zipkinTypes from '../src/types'; import * as zipkinTypes from '../src/types';
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
logger, logger,
}); }).getTracer('default');
const parentId = '5c1c63257de34c67'; const parentId = '5c1c63257de34c67';
const spanContext: types.SpanContext = { const spanContext: types.SpanContext = {
traceId: 'd4cda95b652f4a1592b449d5929fda1b', traceId: 'd4cda95b652f4a1592b449d5929fda1b',

View File

@ -11,14 +11,14 @@ For manual instrumentation see the
[@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing) package. [@opentelemetry/tracing](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-tracing) package.
## How does automated instrumentation work? ## 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)). 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. > **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. 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 ## 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 ## Installation
@ -50,14 +50,14 @@ npm install --save @opentelemetry/plugin-https
## Usage ## 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 ```js
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
// Create and configure NodeTracer // Create and configure NodeTracerRegistry
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
http: { http: {
enabled: true, enabled: true,
@ -68,25 +68,25 @@ const tracer = new NodeTracer({
} }
}); });
// Initialize the tracer // Initialize the registry
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
// Your application code - http will automatically be instrumented if // Your application code - http will automatically be instrumented if
// @opentelemetry/plugin-http is present // @opentelemetry/plugin-http is present
const http = require('http'); 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 ```js
const opentelemetry = require('@opentelemetry/core'); const opentelemetry = require('@opentelemetry/core');
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
// Create and initialize NodeTracer // Create and initialize NodeTracerRegistry
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
// Initialize the tracer // Initialize the registry
opentelemetry.initGlobalTracer(tracer); opentelemetry.initGlobalTracerRegistry(registry);
// Your application code // Your application code
// ... // ...

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { BasicTracer } from '@opentelemetry/tracing'; import { BasicTracerRegistry } from '@opentelemetry/tracing';
import { AsyncHooksScopeManager } from '@opentelemetry/scope-async-hooks'; import { AsyncHooksScopeManager } from '@opentelemetry/scope-async-hooks';
import { PluginLoader } from './instrumentation/PluginLoader'; import { PluginLoader } from './instrumentation/PluginLoader';
import { NodeTracerConfig, DEFAULT_INSTRUMENTATION_PLUGINS } from './config'; 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. * This class represents a node tracer with `async_hooks` module.
*/ */
export class NodeTracer extends BasicTracer { export class NodeTracerRegistry extends BasicTracerRegistry {
private readonly _pluginLoader: PluginLoader; private readonly _pluginLoader: PluginLoader;
/** /**

View File

@ -15,12 +15,12 @@
*/ */
import { Plugins } from './instrumentation/PluginLoader'; import { Plugins } from './instrumentation/PluginLoader';
import { BasicTracerConfig } from '@opentelemetry/tracing'; import { TracerConfig } from '@opentelemetry/tracing';
/** /**
* NodeTracerConfig provides an interface for configuring a Node Tracer. * NodeTracerConfig provides an interface for configuring a Node Tracer.
*/ */
export interface NodeTracerConfig extends BasicTracerConfig { export interface NodeTracerConfig extends TracerConfig {
/** Plugins options. */ /** Plugins options. */
plugins?: Plugins; plugins?: Plugins;
} }

View File

@ -14,4 +14,4 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './NodeTracer'; export * from './NodeTracerRegistry';

View File

@ -14,7 +14,12 @@
* limitations under the License. * 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 hook from 'require-in-the-middle';
import * as utils from './utils'; import * as utils from './utils';
@ -55,7 +60,7 @@ export class PluginLoader {
private _hookState = HookState.UNINITIALIZED; private _hookState = HookState.UNINITIALIZED;
/** Constructs a new PluginLoader instance. */ /** 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 * Loads a list of plugins. Each plugin module should implement the core
@ -115,7 +120,7 @@ export class PluginLoader {
this._plugins.push(plugin); this._plugins.push(plugin);
// Enable each supported 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) { } catch (e) {
this.logger.error( this.logger.error(
`PluginLoader#load: could not load plugin ${modulePath} of module ${name}. Error: ${e.message}` `PluginLoader#load: could not load plugin ${modulePath} of module ${name}. Error: ${e.message}`

View File

@ -23,7 +23,7 @@ import {
NoopLogger, NoopLogger,
NoRecordingSpan, NoRecordingSpan,
} from '@opentelemetry/core'; } from '@opentelemetry/core';
import { NodeTracer } from '../src/NodeTracer'; import { NodeTracerRegistry } from '../src/NodeTracerRegistry';
import { TraceFlags } from '@opentelemetry/types'; import { TraceFlags } from '@opentelemetry/types';
import { Span } from '@opentelemetry/tracing'; import { Span } from '@opentelemetry/tracing';
import * as path from 'path'; import * as path from 'path';
@ -39,8 +39,8 @@ const INSTALLED_PLUGINS_PATH = path.join(
'node_modules' 'node_modules'
); );
describe('NodeTracer', () => { describe('NodeTracerRegistry', () => {
let tracer: NodeTracer; let registry: NodeTracerRegistry;
before(() => { before(() => {
module.paths.push(INSTALLED_PLUGINS_PATH); module.paths.push(INSTALLED_PLUGINS_PATH);
}); });
@ -48,45 +48,45 @@ describe('NodeTracer', () => {
afterEach(() => { afterEach(() => {
// clear require cache // clear require cache
Object.keys(require.cache).forEach(key => delete require.cache[key]); Object.keys(require.cache).forEach(key => delete require.cache[key]);
tracer.stop(); registry.stop();
}); });
describe('constructor', () => { describe('constructor', () => {
it('should construct an instance with required only options', () => { it('should construct an instance with required only options', () => {
tracer = new NodeTracer(); registry = new NodeTracerRegistry();
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
it('should construct an instance with binary format', () => { it('should construct an instance with binary format', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
binaryFormat: new BinaryTraceContext(), binaryFormat: new BinaryTraceContext(),
}); });
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
it('should construct an instance with http text format', () => { it('should construct an instance with http text format', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
httpTextFormat: new HttpTraceContext(), httpTextFormat: new HttpTraceContext(),
}); });
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
it('should construct an instance with logger', () => { it('should construct an instance with logger', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
}); });
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
it('should construct an instance with sampler', () => { it('should construct an instance with sampler', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
sampler: ALWAYS_SAMPLER, sampler: ALWAYS_SAMPLER,
}); });
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
it('should load user configured plugins', () => { it('should load user configured plugins', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
plugins: { plugins: {
'simple-module': { 'simple-module': {
@ -102,7 +102,7 @@ describe('NodeTracer', () => {
}, },
}, },
}); });
const pluginLoader = tracer['_pluginLoader']; const pluginLoader = registry['_pluginLoader'];
assert.strictEqual(pluginLoader['_plugins'].length, 0); assert.strictEqual(pluginLoader['_plugins'].length, 0);
require('simple-module'); require('simple-module');
assert.strictEqual(pluginLoader['_plugins'].length, 1); assert.strictEqual(pluginLoader['_plugins'].length, 1);
@ -111,39 +111,39 @@ describe('NodeTracer', () => {
}); });
it('should construct an instance with default attributes', () => { it('should construct an instance with default attributes', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
defaultAttributes: { defaultAttributes: {
region: 'eu-west', region: 'eu-west',
asg: 'my-asg', asg: 'my-asg',
}, },
}); });
assert.ok(tracer instanceof NodeTracer); assert.ok(registry instanceof NodeTracerRegistry);
}); });
}); });
describe('.startSpan()', () => { describe('.startSpan()', () => {
it('should start a span with name only', () => { it('should start a span with name only', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
}); });
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
assert.ok(span); assert.ok(span);
}); });
it('should start a span with name and options', () => { it('should start a span with name and options', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
}); });
const span = tracer.startSpan('my-span', {}); const span = registry.getTracer('default').startSpan('my-span', {});
assert.ok(span); assert.ok(span);
}); });
it('should return a default span with no sampling', () => { it('should return a default span with no sampling', () => {
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
sampler: NEVER_SAMPLER, sampler: NEVER_SAMPLER,
logger: new NoopLogger(), logger: new NoopLogger(),
}); });
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
assert.ok(span instanceof NoRecordingSpan); assert.ok(span instanceof NoRecordingSpan);
assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED);
assert.strictEqual(span.isRecording(), false); assert.strictEqual(span.isRecording(), false);
@ -156,11 +156,11 @@ describe('NodeTracer', () => {
const defaultAttributes = { const defaultAttributes = {
foo: 'bar', foo: 'bar',
}; };
tracer = new NodeTracer({ registry = new NodeTracerRegistry({
defaultAttributes, 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.ok(span instanceof Span);
assert.deepStrictEqual(span.attributes, defaultAttributes); assert.deepStrictEqual(span.attributes, defaultAttributes);
}); });
@ -168,32 +168,48 @@ describe('NodeTracer', () => {
describe('.getCurrentSpan()', () => { describe('.getCurrentSpan()', () => {
it('should return undefined with AsyncHooksScopeManager when no span started', () => { it('should return undefined with AsyncHooksScopeManager when no span started', () => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
undefined
);
}); });
}); });
describe('.withSpan()', () => { describe('.withSpan()', () => {
it('should run scope with AsyncHooksScopeManager scope manager', done => { it('should run scope with AsyncHooksScopeManager scope manager', done => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
assert.deepStrictEqual(tracer.getCurrentSpan(), span); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
span
);
return done(); return done();
}); });
// @todo: below check is not running. assert.deepStrictEqual(
assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); registry.getTracer('default').getCurrentSpan(),
undefined
);
}); });
it('should run scope with AsyncHooksScopeManager scope manager with multiple spans', done => { it('should run scope with AsyncHooksScopeManager scope manager with multiple spans', done => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
assert.deepStrictEqual(tracer.getCurrentSpan(), span); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
span
);
const span1 = tracer.startSpan('my-span1', { parent: span }); const span1 = registry
tracer.withSpan(span1, () => { .getTracer('default')
assert.deepStrictEqual(tracer.getCurrentSpan(), span1); .startSpan('my-span1', { parent: span });
registry.getTracer('default').withSpan(span1, () => {
assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
span1
);
assert.deepStrictEqual( assert.deepStrictEqual(
span1.context().traceId, span1.context().traceId,
span.context().traceId span.context().traceId
@ -203,48 +219,66 @@ describe('NodeTracer', () => {
}); });
// when span ended. // when span ended.
// @todo: below check is not running. // @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 => { it('should find correct scope with promises', done => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
tracer.withSpan(span, async () => { registry.getTracer('default').withSpan(span, async () => {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
await sleep(5).then(() => { await sleep(5).then(() => {
assert.deepStrictEqual(tracer.getCurrentSpan(), span); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
span
);
}); });
} }
return done(); return done();
}); });
assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
undefined
);
}); });
}); });
describe('.bind()', () => { describe('.bind()', () => {
it('should bind scope with AsyncHooksScopeManager scope manager', done => { it('should bind scope with AsyncHooksScopeManager scope manager', done => {
const tracer = new NodeTracer({}); const registry = new NodeTracerRegistry({});
const span = tracer.startSpan('my-span'); const span = registry.getTracer('default').startSpan('my-span');
const fn = () => { const fn = () => {
assert.deepStrictEqual(tracer.getCurrentSpan(), span); assert.deepStrictEqual(
registry.getTracer('default').getCurrentSpan(),
span
);
return done(); return done();
}; };
const patchedFn = tracer.bind(fn, span); const patchedFn = registry.getTracer('default').bind(fn, span);
return patchedFn(); return patchedFn();
}); });
}); });
describe('.getBinaryFormat()', () => { describe('.getBinaryFormat()', () => {
it('should get default binary formatter', () => { it('should get default binary formatter', () => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
assert.ok(tracer.getBinaryFormat() instanceof BinaryTraceContext); assert.ok(
registry.getTracer('default').getBinaryFormat() instanceof
BinaryTraceContext
);
}); });
}); });
describe('.getHttpTextFormat()', () => { describe('.getHttpTextFormat()', () => {
it('should get default HTTP text formatter', () => { it('should get default HTTP text formatter', () => {
tracer = new NodeTracer({}); registry = new NodeTracerRegistry({});
assert.ok(tracer.getHttpTextFormat() instanceof HttpTraceContext); assert.ok(
registry.getTracer('default').getHttpTextFormat() instanceof
HttpTraceContext
);
}); });
}); });
}); });

View File

@ -14,14 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { NoopLogger, NoopTracer } from '@opentelemetry/core'; import { NoopLogger, NoopTracerRegistry } from '@opentelemetry/core';
import * as assert from 'assert'; import * as assert from 'assert';
import * as path from 'path'; import * as path from 'path';
import { import {
HookState, HookState,
PluginLoader, PluginLoader,
searchPathForTest,
Plugins, Plugins,
searchPathForTest,
} from '../../src/instrumentation/PluginLoader'; } from '../../src/instrumentation/PluginLoader';
const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules'); const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules');
@ -86,7 +86,7 @@ const notSupportedVersionPlugins: Plugins = {
}; };
describe('PluginLoader', () => { describe('PluginLoader', () => {
const tracer = new NoopTracer(); const registry = new NoopTracerRegistry();
const logger = new NoopLogger(); const logger = new NoopLogger();
before(() => { before(() => {
@ -101,19 +101,19 @@ describe('PluginLoader', () => {
describe('.state()', () => { describe('.state()', () => {
it('returns UNINITIALIZED when first called', () => { it('returns UNINITIALIZED when first called', () => {
const pluginLoader = new PluginLoader(tracer, logger); const pluginLoader = new PluginLoader(registry, logger);
assert.strictEqual(pluginLoader['_hookState'], HookState.UNINITIALIZED); assert.strictEqual(pluginLoader['_hookState'], HookState.UNINITIALIZED);
}); });
it('transitions from UNINITIALIZED to ENABLED', () => { it('transitions from UNINITIALIZED to ENABLED', () => {
const pluginLoader = new PluginLoader(tracer, logger); const pluginLoader = new PluginLoader(registry, logger);
pluginLoader.load(simplePlugins); pluginLoader.load(simplePlugins);
assert.strictEqual(pluginLoader['_hookState'], HookState.ENABLED); assert.strictEqual(pluginLoader['_hookState'], HookState.ENABLED);
pluginLoader.unload(); pluginLoader.unload();
}); });
it('transitions from ENABLED to DISABLED', () => { it('transitions from ENABLED to DISABLED', () => {
const pluginLoader = new PluginLoader(tracer, logger); const pluginLoader = new PluginLoader(registry, logger);
pluginLoader.load(simplePlugins).unload(); pluginLoader.load(simplePlugins).unload();
assert.strictEqual(pluginLoader['_hookState'], HookState.DISABLED); assert.strictEqual(pluginLoader['_hookState'], HookState.DISABLED);
}); });
@ -138,7 +138,7 @@ describe('PluginLoader', () => {
}); });
it('should load a plugin and patch the target modules', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(simplePlugins); pluginLoader.load(simplePlugins);
// The hook is only called the first time the module is loaded. // 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', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(httpPlugins); pluginLoader.load(httpPlugins);
// The hook is only called the first time the module is loaded. // 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 // @TODO: simplify this test once we can load module with custom path
it('should not load the plugin when supported versions does not match', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(notSupportedVersionPlugins); pluginLoader.load(notSupportedVersionPlugins);
// The hook is only called the first time the module is loaded. // 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 // @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', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(supportedVersionPlugins); pluginLoader.load(supportedVersionPlugins);
// The hook is only called the first time the module is loaded. // 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', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(disablePlugins); pluginLoader.load(disablePlugins);
const simpleModule = require('simple-module'); 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', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(missingPathPlugins); pluginLoader.load(missingPathPlugins);
const simpleModule = require('simple-module'); const simpleModule = require('simple-module');
@ -205,7 +205,7 @@ describe('PluginLoader', () => {
}); });
it('should not load a non existing plugin', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(nonexistentPlugins); pluginLoader.load(nonexistentPlugins);
assert.strictEqual(pluginLoader['_plugins'].length, 0); assert.strictEqual(pluginLoader['_plugins'].length, 0);
@ -213,7 +213,7 @@ describe('PluginLoader', () => {
}); });
it(`doesn't patch modules for which plugins aren't specified`, () => { 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({}); pluginLoader.load({});
assert.strictEqual(require('simple-module').value(), 0); assert.strictEqual(require('simple-module').value(), 0);
pluginLoader.unload(); pluginLoader.unload();
@ -222,7 +222,7 @@ describe('PluginLoader', () => {
describe('.unload()', () => { describe('.unload()', () => {
it('should unload the plugins and unpatch the target module when unloads', () => { 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); assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load(simplePlugins); pluginLoader.load(simplePlugins);
// The hook is only called the first time the module is loaded. // The hook is only called the first time the module is loaded.

View File

@ -18,9 +18,9 @@ npm install --save @opentelemetry/plugin-dns
## Usage ## Usage
```js ```js
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
dns: { dns: {
enabled: true, 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 : 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: { plugins: {
dns: { dns: {
enabled: true, enabled: true,

View File

@ -14,22 +14,23 @@
* limitations under the License. * 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 { 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 { import {
Dns, Dns,
LookupPromiseSignature, DnsPluginConfig,
LookupCallbackSignature,
LookupFunction, LookupFunction,
LookupFunctionSignature, LookupFunctionSignature,
LookupCallbackSignature, LookupPromiseSignature,
DnsPluginConfig,
} from './types'; } from './types';
import { AttributeNames } from './enums/AttributeNames'; import * as utils from './utils';
import { AddressFamily } from './enums/AddressFamily'; import { VERSION } from './version';
import { LookupAddress } from 'dns';
/** /**
* Dns instrumentation plugin for Opentelemetry * Dns instrumentation plugin for Opentelemetry
@ -39,7 +40,7 @@ export class DnsPlugin extends BasePlugin<Dns> {
protected _config!: DnsPluginConfig; protected _config!: DnsPluginConfig;
constructor(readonly moduleName: string, readonly version: string) { 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. // For now component is equal to moduleName but it can change in the future.
this.component = this.moduleName; this.component = this.moduleName;
this._config = {}; this._config = {};

View File

@ -20,19 +20,20 @@ import {
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import * as assert from 'assert'; import * as assert from 'assert';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin } from '../../src/dns'; import { plugin } from '../../src/dns';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import * as dns from 'dns'; import * as dns from 'dns';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); const tracer = registry.getTracer('default');
registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
describe('DnsPlugin', () => { describe('DnsPlugin', () => {
before(() => { before(() => {
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, tracer.logger);
assert.strictEqual(dns.lookup.__wrapped, true); assert.strictEqual(dns.lookup.__wrapped, true);
}); });

View File

@ -20,18 +20,18 @@ import {
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import * as assert from 'assert'; import * as assert from 'assert';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin, DnsPlugin } from '../../src/dns'; import { plugin, DnsPlugin } from '../../src/dns';
import * as dns from 'dns'; import * as dns from 'dns';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
describe('DnsPlugin', () => { describe('DnsPlugin', () => {
before(() => { before(() => {
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, registry.logger);
}); });
after(() => { after(() => {

View File

@ -14,14 +14,14 @@
* limitations under the License. * 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 assert from 'assert';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { CanonicalCode, SpanKind } from '@opentelemetry/types'; import { AttributeNames } from '../../src/enums/AttributeNames';
import { IgnoreMatcher } from '../../src/types'; import { IgnoreMatcher } from '../../src/types';
import * as utils from '../../src/utils'; 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('Utility', () => {
describe('parseResponseStatus()', () => { describe('parseResponseStatus()', () => {
@ -162,7 +162,7 @@ describe('Utility', () => {
it('should have error attributes', () => { it('should have error attributes', () => {
const errorMessage = 'test error'; const errorMessage = 'test error';
const span = new Span( const span = new Span(
new BasicTracer(), new BasicTracerRegistry().getTracer('default'),
'test', 'test',
{ spanId: '', traceId: '' }, { spanId: '', traceId: '' },
SpanKind.INTERNAL SpanKind.INTERNAL

View File

@ -20,7 +20,7 @@ import {
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import * as assert from 'assert'; import * as assert from 'assert';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin } from '../../src/dns'; import { plugin } from '../../src/dns';
import * as dns from 'dns'; import * as dns from 'dns';
import * as utils from '../utils/utils'; import * as utils from '../utils/utils';
@ -29,14 +29,14 @@ import { CanonicalCode } from '@opentelemetry/types';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
describe('dns.lookup()', () => { describe('dns.lookup()', () => {
before(function(done) { before(function(done) {
// mandatory // mandatory
if (process.env.CI) { if (process.env.CI) {
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, registry.logger);
done(); done();
return; return;
} }
@ -48,7 +48,7 @@ describe('dns.lookup()', () => {
} }
done(); done();
}); });
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, registry.logger);
}); });
afterEach(() => { afterEach(() => {

View File

@ -20,7 +20,7 @@ import {
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import * as assert from 'assert'; import * as assert from 'assert';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin } from '../../src/dns'; import { plugin } from '../../src/dns';
import * as dns from 'dns'; import * as dns from 'dns';
import * as utils from '../utils/utils'; import * as utils from '../utils/utils';
@ -30,8 +30,8 @@ import { CanonicalCode } from '@opentelemetry/types';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
describe('dns.promises.lookup()', () => { describe('dns.promises.lookup()', () => {
before(function(done) { before(function(done) {
@ -42,7 +42,7 @@ describe('dns.promises.lookup()', () => {
// if node version is supported, it's mandatory for CI // if node version is supported, it's mandatory for CI
if (process.env.CI) { if (process.env.CI) {
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, registry.logger);
done(); done();
return; return;
} }
@ -54,7 +54,7 @@ describe('dns.promises.lookup()', () => {
} }
done(); done();
}); });
plugin.enable(dns, tracer, tracer.logger); plugin.enable(dns, registry, registry.logger);
}); });
afterEach(() => { afterEach(() => {

View File

@ -21,7 +21,6 @@ import {
TRACE_PARENT_HEADER, TRACE_PARENT_HEADER,
} from '@opentelemetry/core'; } from '@opentelemetry/core';
import { PluginConfig, Span, SpanOptions } from '@opentelemetry/types'; import { PluginConfig, Span, SpanOptions } from '@opentelemetry/types';
import { AttributeNames } from './enums/AttributeNames';
import { import {
addSpanNetworkEvent, addSpanNetworkEvent,
hasKey, hasKey,
@ -29,6 +28,8 @@ import {
PerformanceLegacy, PerformanceLegacy,
PerformanceTimingNames as PTN, PerformanceTimingNames as PTN,
} from '@opentelemetry/web'; } from '@opentelemetry/web';
import { AttributeNames } from './enums/AttributeNames';
import { VERSION } from './version';
/** /**
* This class represents a document load plugin * This class represents a document load plugin
@ -44,7 +45,7 @@ export class DocumentLoad extends BasePlugin<unknown> {
* @param config * @param config
*/ */
constructor(config: PluginConfig = {}) { constructor(config: PluginConfig = {}) {
super(); super('@opentelemetry/plugin-document-load', VERSION);
this._onDocumentLoaded = this._onDocumentLoaded.bind(this); this._onDocumentLoaded = this._onDocumentLoaded.bind(this);
this._config = config; this._config = config;
} }

View File

@ -18,18 +18,16 @@
* Can't use Sinon Fake Time here as then cannot stub the performance getEntriesByType with desired metrics * 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 { ConsoleLogger, TRACE_PARENT_HEADER } from '@opentelemetry/core';
import { import {
BasicTracer, BasicTracerRegistry,
ReadableSpan, ReadableSpan,
SimpleSpanProcessor, SimpleSpanProcessor,
SpanExporter, SpanExporter,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { Logger, PluginConfig, TimedEvent } from '@opentelemetry/types'; 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 { ExportResult } from '../../opentelemetry-base/build/src';
import { DocumentLoad } from '../src'; import { DocumentLoad } from '../src';
import { PerformanceTimingNames as PTN } from '@opentelemetry/web'; import { PerformanceTimingNames as PTN } from '@opentelemetry/web';
@ -193,7 +191,7 @@ function ensureNetworkEventsExists(events: TimedEvent[]) {
describe('DocumentLoad Plugin', () => { describe('DocumentLoad Plugin', () => {
let plugin: DocumentLoad; let plugin: DocumentLoad;
let moduleExports: any; let moduleExports: any;
let tracer: BasicTracer; let registry: BasicTracerRegistry;
let logger: Logger; let logger: Logger;
let config: PluginConfig; let config: PluginConfig;
let spanProcessor: SimpleSpanProcessor; let spanProcessor: SimpleSpanProcessor;
@ -205,13 +203,13 @@ describe('DocumentLoad Plugin', () => {
value: 'complete', value: 'complete',
}); });
moduleExports = {}; moduleExports = {};
tracer = new BasicTracer(); registry = new BasicTracerRegistry();
logger = new ConsoleLogger(); logger = new ConsoleLogger();
config = {}; config = {};
plugin = new DocumentLoad(); plugin = new DocumentLoad();
dummyExporter = new DummyExporter(); dummyExporter = new DummyExporter();
spanProcessor = new SimpleSpanProcessor(dummyExporter); spanProcessor = new SimpleSpanProcessor(dummyExporter);
tracer.addSpanProcessor(spanProcessor); registry.addSpanProcessor(spanProcessor);
}); });
afterEach(() => { afterEach(() => {
@ -239,7 +237,7 @@ describe('DocumentLoad Plugin', () => {
spyEntries.restore(); spyEntries.restore();
}); });
it('should start collecting the performance immediately', done => { it('should start collecting the performance immediately', done => {
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
assert.strictEqual(window.document.readyState, 'complete'); assert.strictEqual(window.document.readyState, 'complete');
assert.strictEqual(spyEntries.callCount, 2); assert.strictEqual(spyEntries.callCount, 2);
@ -266,7 +264,7 @@ describe('DocumentLoad Plugin', () => {
it('should collect performance after document load event', done => { it('should collect performance after document load event', done => {
const spy = sinon.spy(window, 'addEventListener'); const spy = sinon.spy(window, 'addEventListener');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
const args = spy.args[0]; const args = spy.args[0];
const name = args[0]; const name = args[0];
assert.strictEqual(name, 'load'); assert.strictEqual(name, 'load');
@ -301,7 +299,7 @@ describe('DocumentLoad Plugin', () => {
it('should export correct span with events', done => { it('should export correct span with events', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; 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 => { it('should create a root span with server context traceId', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan;
const fetchSpan = spyOnEnd.args[1][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 => { it('should create span for each of the resource', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan; const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan;
const spanResource2 = spyOnEnd.args[2][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 => { it('should create span for each of the resource', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan; const spanResource1 = spyOnEnd.args[1][0][0] as ReadableSpan;
@ -473,7 +471,7 @@ describe('DocumentLoad Plugin', () => {
it('should still export rootSpan and fetchSpan', done => { it('should still export rootSpan and fetchSpan', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan;
@ -505,7 +503,7 @@ describe('DocumentLoad Plugin', () => {
it('should export correct span with events', done => { it('should export correct span with events', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan; const rootSpan = spyOnEnd.args[0][0][0] as ReadableSpan;
const fetchSpan = spyOnEnd.args[1][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 => { it('should not create any span', done => {
const spyOnEnd = sinon.spy(dummyExporter, 'export'); const spyOnEnd = sinon.spy(dummyExporter, 'export');
plugin.enable(moduleExports, tracer, logger, config); plugin.enable(moduleExports, registry, logger, config);
setTimeout(() => { setTimeout(() => {
assert.ok(spyOnEnd.callCount === 0); assert.ok(spyOnEnd.callCount === 0);
done(); done();

View File

@ -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. To load a specific plugin (**gRPC** in this case), specify it in the Node Tracer's configuration.
```javascript ```javascript
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
grpc: { grpc: {
enabled: true, 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. 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 ```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. See [examples/grpc](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/grpc) for a short example.

View File

@ -16,33 +16,33 @@
import { BasePlugin } from '@opentelemetry/core'; import { BasePlugin } from '@opentelemetry/core';
import { import {
CanonicalCode,
Span,
SpanContext,
SpanKind, SpanKind,
SpanOptions, SpanOptions,
Span,
Status, Status,
CanonicalCode,
SpanContext,
} from '@opentelemetry/types'; } 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 { AttributeNames } from './enums/AttributeNames';
import { import {
grpc, grpc,
ModuleExportsMapping,
GrpcPluginOptions,
ServerCallWithMeta,
SendUnaryDataCallback,
GrpcClientFunc, GrpcClientFunc,
GrpcInternalClientTypes, GrpcInternalClientTypes,
GrpcPluginOptions,
ModuleExportsMapping,
SendUnaryDataCallback,
ServerCallWithMeta,
} from './types'; } from './types';
import { import {
findIndex, findIndex,
_grpcStatusCodeToCanonicalCode, _grpcStatusCodeToCanonicalCode,
_grpcStatusCodeToSpanStatus, _grpcStatusCodeToSpanStatus,
} from './utils'; } from './utils';
import { VERSION } from './version';
import * as events from 'events';
import * as grpcTypes from 'grpc';
import * as shimmer from 'shimmer';
import * as path from 'path';
/** The metadata key under which span context is stored as a binary value. */ /** The metadata key under which span context is stored as a binary value. */
export const GRPC_TRACE_KEY = 'grpc-trace-bin'; export const GRPC_TRACE_KEY = 'grpc-trace-bin';
@ -56,7 +56,7 @@ export class GrpcPlugin extends BasePlugin<grpc> {
protected _config!: GrpcPluginOptions; protected _config!: GrpcPluginOptions;
constructor(readonly moduleName: string, readonly version: string) { constructor(readonly moduleName: string, readonly version: string) {
super(); super('@opentelemetry/plugin-grpc', VERSION);
this._config = {}; this._config = {};
} }

View File

@ -14,22 +14,20 @@
* limitations under the License. * limitations under the License.
*/ */
import { NoopLogger, NoopTracer } from '@opentelemetry/core'; import { NoopLogger, NoopTracerRegistry } from '@opentelemetry/core';
import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { SpanKind, Tracer } from '@opentelemetry/types'; import { SpanKind } from '@opentelemetry/types';
import { NodeTracer } from '@opentelemetry/node'; import * as assert from 'assert';
import * as grpc from 'grpc';
import { assertSpan, assertPropagation } from './utils/assertionUtils'; import * as semver from 'semver';
import * as sinon from 'sinon';
import { GrpcPlugin, plugin } from '../src'; import { GrpcPlugin, plugin } from '../src';
import { SendUnaryDataCallback } from '../src/types'; import { SendUnaryDataCallback } from '../src/types';
import { assertPropagation, assertSpan } from './utils/assertionUtils';
import * as assert from 'assert';
import * as semver from 'semver';
import * as grpc from 'grpc';
import * as sinon from 'sinon';
const PROTO_PATH = __dirname + '/fixtures/grpc-test.proto'; const PROTO_PATH = __dirname + '/fixtures/grpc-test.proto';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
@ -318,7 +316,7 @@ describe('GrpcPlugin', () => {
}); });
it('should patch client constructor makeClientConstructor() and makeGenericClientConstructor()', () => { 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({}); (plugin['_moduleExports'] as any).makeGenericClientConstructor({});
assert.strictEqual(clientPatchStub.callCount, 1); assert.strictEqual(clientPatchStub.callCount, 1);
}); });
@ -370,7 +368,7 @@ describe('GrpcPlugin', () => {
const runTest = ( const runTest = (
method: typeof methodList[0], method: typeof methodList[0],
tracer: Tracer, registry: NodeTracerRegistry,
checkSpans = true checkSpans = true
) => { ) => {
it(`should ${ it(`should ${
@ -410,9 +408,11 @@ describe('GrpcPlugin', () => {
const expectEmpty = memoryExporter.getFinishedSpans(); const expectEmpty = memoryExporter.getFinishedSpans();
assert.strictEqual(expectEmpty.length, 0); assert.strictEqual(expectEmpty.length, 0);
const span = tracer.startSpan('TestSpan', { kind: SpanKind.PRODUCER }); const span = registry
return tracer.withSpan(span, async () => { .getTracer('default')
const rootSpan = tracer.getCurrentSpan(); .startSpan('TestSpan', { kind: SpanKind.PRODUCER });
return registry.getTracer('default').withSpan(span, async () => {
const rootSpan = registry.getTracer('default').getCurrentSpan();
if (!rootSpan) { if (!rootSpan) {
assert.ok(false); assert.ok(false);
return; // return so typechecking passes for rootSpan.end() return; // return so typechecking passes for rootSpan.end()
@ -465,7 +465,7 @@ describe('GrpcPlugin', () => {
method: typeof methodList[0], method: typeof methodList[0],
key: string, key: string,
errorCode: number, errorCode: number,
tracer: Tracer registry: NodeTracerRegistry
) => { ) => {
it(`should raise an error for client/server rootSpans: method=${method.methodName}, status=${key}`, async () => { it(`should raise an error for client/server rootSpans: method=${method.methodName}, status=${key}`, async () => {
const expectEmpty = memoryExporter.getFinishedSpans(); const expectEmpty = memoryExporter.getFinishedSpans();
@ -503,9 +503,11 @@ describe('GrpcPlugin', () => {
const expectEmpty = memoryExporter.getFinishedSpans(); const expectEmpty = memoryExporter.getFinishedSpans();
assert.strictEqual(expectEmpty.length, 0); assert.strictEqual(expectEmpty.length, 0);
const span = tracer.startSpan('TestSpan', { kind: SpanKind.PRODUCER }); const span = registry
return tracer.withSpan(span, async () => { .getTracer('default')
const rootSpan = tracer.getCurrentSpan(); .startSpan('TestSpan', { kind: SpanKind.PRODUCER });
return registry.getTracer('default').withSpan(span, async () => {
const rootSpan = registry.getTracer('default').getCurrentSpan();
if (!rootSpan) { if (!rootSpan) {
assert.ok(false); assert.ok(false);
return; // return so typechecking passes for rootSpan.end() return; // return so typechecking passes for rootSpan.end()
@ -552,8 +554,8 @@ describe('GrpcPlugin', () => {
describe('enable()', () => { describe('enable()', () => {
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
@ -562,7 +564,7 @@ describe('GrpcPlugin', () => {
const config = { const config = {
// TODO: add plugin options here once supported // 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; const proto = grpc.load(PROTO_PATH).pkg_test;
server = startServer(grpc, proto); server = startServer(grpc, proto);
@ -579,7 +581,7 @@ describe('GrpcPlugin', () => {
methodList.forEach(method => { methodList.forEach(method => {
describe(`Test automatic tracing for grpc remote method ${method.description}`, () => { 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 // tslint:disable-next-line:no-any
const errorCode = Number(grpc.status[statusKey as any]); const errorCode = Number(grpc.status[statusKey as any]);
if (errorCode > grpc.status.OK) { if (errorCode > grpc.status.OK) {
runErrorTest(method, statusKey, errorCode, tracer); runErrorTest(method, statusKey, errorCode, registry);
} }
}); });
}); });
@ -598,14 +600,14 @@ describe('GrpcPlugin', () => {
describe('disable()', () => { describe('disable()', () => {
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ logger }); const registry = new NodeTracerRegistry({ logger });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
before(() => { before(() => {
plugin.enable(grpc, tracer, logger); plugin.enable(grpc, registry, logger);
plugin.disable(); plugin.disable();
const proto = grpc.load(PROTO_PATH).pkg_test; const proto = grpc.load(PROTO_PATH).pkg_test;
@ -622,7 +624,7 @@ describe('GrpcPlugin', () => {
methodList.map(method => { methodList.map(method => {
describe(`Test automatic tracing for grpc remote method ${method.description}`, () => { describe(`Test automatic tracing for grpc remote method ${method.description}`, () => {
runTest(method, tracer, false); runTest(method, registry, false);
}); });
}); });
}); });

View File

@ -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. To load a specific plugin (HTTP in this case), specify it in the Node Tracer's configuration.
```js ```js
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
http: { http: {
enabled: true, 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. 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 ```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. See [examples/http](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/http) for a short example.

View File

@ -16,10 +16,10 @@
import { BasePlugin, isValid } from '@opentelemetry/core'; import { BasePlugin, isValid } from '@opentelemetry/core';
import { import {
CanonicalCode,
Span, Span,
SpanKind, SpanKind,
SpanOptions, SpanOptions,
CanonicalCode,
Status, Status,
} from '@opentelemetry/types'; } from '@opentelemetry/types';
import { import {
@ -29,22 +29,23 @@ import {
RequestOptions, RequestOptions,
ServerResponse, ServerResponse,
} from 'http'; } from 'http';
import { Socket } from 'net';
import * as semver from 'semver'; import * as semver from 'semver';
import * as shimmer from 'shimmer'; import * as shimmer from 'shimmer';
import * as url from 'url'; import * as url from 'url';
import {
HttpPluginConfig,
Http,
Func,
ResponseEndArgs,
ParsedRequestOptions,
HttpRequestArgs,
Err,
} from './types';
import { Format } from './enums/Format';
import { AttributeNames } from './enums/AttributeNames'; import { AttributeNames } from './enums/AttributeNames';
import { Format } from './enums/Format';
import {
Err,
Func,
Http,
HttpPluginConfig,
HttpRequestArgs,
ParsedRequestOptions,
ResponseEndArgs,
} from './types';
import * as utils from './utils'; import * as utils from './utils';
import { Socket } from 'net'; import { VERSION } from './version';
/** /**
* Http instrumentation plugin for Opentelemetry * Http instrumentation plugin for Opentelemetry
@ -56,7 +57,7 @@ export class HttpPlugin extends BasePlugin<Http> {
private readonly _spanNotEnded: WeakSet<Span>; private readonly _spanNotEnded: WeakSet<Span>;
constructor(readonly moduleName: string, readonly version: string) { 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. // For now component is equal to moduleName but it can change in the future.
this.component = this.moduleName; this.component = this.moduleName;
this._spanNotEnded = new WeakSet<Span>(); this._spanNotEnded = new WeakSet<Span>();

View File

@ -20,10 +20,12 @@ import * as nock from 'nock';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { plugin } from '../../src/http'; import { plugin } from '../../src/http';
import { NodeTracer } from '@opentelemetry/node'; import {
import { NoopLogger } from '@opentelemetry/core'; NoopLogger,
NoopTracerRegistry,
noopTracer,
} from '@opentelemetry/core';
import { AddressInfo } from 'net'; import { AddressInfo } from 'net';
import { DummyPropagation } from '../utils/DummyPropagation';
import { httpRequest } from '../utils/httpRequest'; import { httpRequest } from '../utils/httpRequest';
describe('HttpPlugin', () => { describe('HttpPlugin', () => {
@ -31,17 +33,13 @@ describe('HttpPlugin', () => {
let serverPort = 0; let serverPort = 0;
describe('disable()', () => { describe('disable()', () => {
const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NoopTracerRegistry();
logger,
httpTextFormat,
});
before(() => { before(() => {
nock.cleanAll(); nock.cleanAll();
nock.enableNetConnect(); nock.enableNetConnect();
plugin.enable(http, tracer, tracer.logger); plugin.enable(http, registry, logger);
// Ensure that http module is patched. // Ensure that http module is patched.
assert.strictEqual(http.Server.prototype.emit.__wrapped, true); assert.strictEqual(http.Server.prototype.emit.__wrapped, true);
server = http.createServer((request, response) => { server = http.createServer((request, response) => {
@ -55,8 +53,8 @@ describe('HttpPlugin', () => {
}); });
beforeEach(() => { beforeEach(() => {
tracer.startSpan = sinon.spy(); noopTracer.startSpan = sinon.spy();
tracer.withSpan = sinon.spy(); noopTracer.withSpan = sinon.spy();
}); });
afterEach(() => { afterEach(() => {
@ -67,7 +65,7 @@ describe('HttpPlugin', () => {
server.close(); server.close();
}); });
describe('unpatch()', () => { describe('unpatch()', () => {
it('should not call tracer methods for creating span', async () => { it('should not call registry methods for creating span', async () => {
plugin.disable(); plugin.disable();
const testPath = '/incoming/unpatch/'; const testPath = '/incoming/unpatch/';
@ -75,12 +73,15 @@ describe('HttpPlugin', () => {
await httpRequest.get(options).then(result => { await httpRequest.get(options).then(result => {
assert.strictEqual( assert.strictEqual(
(tracer.startSpan as sinon.SinonSpy).called, (noopTracer.startSpan as sinon.SinonSpy).called,
false false
); );
assert.strictEqual(http.Server.prototype.emit.__wrapped, undefined); 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
);
}); });
}); });
}); });

View File

@ -19,7 +19,7 @@ import {
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { NoopLogger } from '@opentelemetry/core'; 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 { CanonicalCode, Span as ISpan, SpanKind } from '@opentelemetry/types';
import * as assert from 'assert'; import * as assert from 'assert';
import * as http from 'http'; import * as http from 'http';
@ -45,11 +45,11 @@ const serverName = 'my.server.name';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
function doNock( function doNock(
hostname: string, hostname: string,
@ -109,7 +109,7 @@ describe('HttpPlugin', () => {
plugin.component, plugin.component,
process.versions.node process.versions.node
); );
pluginWithBadOptions.enable(http, tracer, tracer.logger, config); pluginWithBadOptions.enable(http, registry, registry.logger, config);
server = http.createServer((request, response) => { server = http.createServer((request, response) => {
response.end('Test Server Response'); response.end('Test Server Response');
}); });
@ -187,7 +187,7 @@ describe('HttpPlugin', () => {
applyCustomAttributesOnSpan: customAttributeFunction, applyCustomAttributesOnSpan: customAttributeFunction,
serverName, serverName,
}; };
plugin.enable(http, tracer, tracer.logger, config); plugin.enable(http, registry, registry.logger, config);
server = http.createServer((request, response) => { server = http.createServer((request, response) => {
response.end('Test Server Response'); response.end('Test Server Response');
}); });
@ -208,7 +208,7 @@ describe('HttpPlugin', () => {
const httpNotPatched = new HttpPlugin( const httpNotPatched = new HttpPlugin(
plugin.component, plugin.component,
process.versions.node process.versions.node
).enable({} as Http, tracer, tracer.logger, {}); ).enable({} as Http, registry, registry.logger, {});
assert.strictEqual(Object.keys(httpNotPatched).length, 0); assert.strictEqual(Object.keys(httpNotPatched).length, 0);
}); });
@ -323,8 +323,8 @@ describe('HttpPlugin', () => {
const testPath = '/outgoing/rootSpan/childs/1'; const testPath = '/outgoing/rootSpan/childs/1';
doNock(hostname, testPath, 200, 'Ok'); doNock(hostname, testPath, 200, 'Ok');
const name = 'TestRootSpan'; const name = 'TestRootSpan';
const span = tracer.startSpan(name); const span = registry.getTracer('default').startSpan(name);
return tracer.withSpan(span, async () => { return registry.getTracer('default').withSpan(span, async () => {
const result = await httpRequest.get( const result = await httpRequest.get(
`${protocol}://${hostname}${testPath}` `${protocol}://${hostname}${testPath}`
); );
@ -366,8 +366,8 @@ describe('HttpPlugin', () => {
httpErrorCodes[i].toString() httpErrorCodes[i].toString()
); );
const name = 'TestRootSpan'; const name = 'TestRootSpan';
const span = tracer.startSpan(name); const span = registry.getTracer('default').startSpan(name);
return tracer.withSpan(span, async () => { return registry.getTracer('default').withSpan(span, async () => {
const result = await httpRequest.get( const result = await httpRequest.get(
`${protocol}://${hostname}${testPath}` `${protocol}://${hostname}${testPath}`
); );
@ -405,8 +405,8 @@ describe('HttpPlugin', () => {
const num = 5; const num = 5;
doNock(hostname, testPath, 200, 'Ok', num); doNock(hostname, testPath, 200, 'Ok', num);
const name = 'TestRootSpan'; const name = 'TestRootSpan';
const span = tracer.startSpan(name); const span = registry.getTracer('default').startSpan(name);
await tracer.withSpan(span, async () => { await registry.getTracer('default').withSpan(span, async () => {
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
await httpRequest.get(`${protocol}://${hostname}${testPath}`); await httpRequest.get(`${protocol}://${hostname}${testPath}`);
const spans = memoryExporter.getFinishedSpans(); const spans = memoryExporter.getFinishedSpans();

View File

@ -28,7 +28,7 @@ import * as superagent from 'superagent';
import * as got from 'got'; import * as got from 'got';
import * as request from 'request-promise-native'; import * as request from 'request-promise-native';
import * as path from 'path'; import * as path from 'path';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -45,11 +45,11 @@ describe('Packages', () => {
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
@ -58,7 +58,7 @@ describe('Packages', () => {
const config: HttpPluginConfig = { const config: HttpPluginConfig = {
applyCustomAttributesOnSpan: customAttributeFunction, applyCustomAttributesOnSpan: customAttributeFunction,
}; };
plugin.enable(http, tracer, tracer.logger, config); plugin.enable(http, registry, registry.logger, config);
}); });
after(() => { after(() => {

View File

@ -22,7 +22,7 @@ import { NoopScopeManager } from '@opentelemetry/scope-base';
import { IgnoreMatcher } from '../../src/types'; import { IgnoreMatcher } from '../../src/types';
import * as utils from '../../src/utils'; import * as utils from '../../src/utils';
import * as http from 'http'; import * as http from 'http';
import { Span, BasicTracer } from '@opentelemetry/tracing'; import { Span, BasicTracerRegistry } from '@opentelemetry/tracing';
import { AttributeNames } from '../../src'; import { AttributeNames } from '../../src';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
@ -248,9 +248,9 @@ describe('Utility', () => {
const errorMessage = 'test error'; const errorMessage = 'test error';
for (const obj of [undefined, { statusCode: 400 }]) { for (const obj of [undefined, { statusCode: 400 }]) {
const span = new Span( const span = new Span(
new BasicTracer({ new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
}), }).getTracer('default'),
'test', 'test',
{ spanId: '', traceId: '' }, { spanId: '', traceId: '' },
SpanKind.INTERNAL SpanKind.INTERNAL

View File

@ -24,7 +24,7 @@ import { DummyPropagation } from '../utils/DummyPropagation';
import { httpRequest } from '../utils/httpRequest'; import { httpRequest } from '../utils/httpRequest';
import * as url from 'url'; import * as url from 'url';
import * as utils from '../utils/utils'; import * as utils from '../utils/utils';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -60,11 +60,11 @@ describe('HttpPlugin Integration tests', () => {
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
@ -83,7 +83,7 @@ describe('HttpPlugin Integration tests', () => {
try { try {
plugin.disable(); plugin.disable();
} catch (e) {} } catch (e) {}
plugin.enable(http, tracer, tracer.logger, config); plugin.enable(http, registry, registry.logger, config);
}); });
after(() => { after(() => {

View File

@ -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. To load a specific plugin (HTTPS in this case), specify it in the Node Tracer's configuration.
```js ```js
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
https: { https: {
enabled: true, 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. 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 ```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. See [examples/https](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/https) for a short example.

View File

@ -14,19 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { NoopLogger } from '@opentelemetry/core';
import { Http } from '@opentelemetry/plugin-http';
import * as assert from 'assert'; import * as assert from 'assert';
import * as fs from 'fs'; import * as fs from 'fs';
import * as https from 'https'; import * as https from 'https';
import { AddressInfo } from 'net';
import * as nock from 'nock'; import * as nock from 'nock';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { plugin } from '../../src/https'; 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 { DummyPropagation } from '../utils/DummyPropagation';
import { httpsRequest } from '../utils/httpsRequest'; import { httpsRequest } from '../utils/httpsRequest';
import { NodeTracerRegistry } from '@opentelemetry/node';
import * as types from '@opentelemetry/types';
describe('HttpsPlugin', () => { describe('HttpsPlugin', () => {
let server: https.Server; let server: https.Server;
@ -35,15 +35,18 @@ describe('HttpsPlugin', () => {
describe('disable()', () => { describe('disable()', () => {
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
// const tracer = registry.getTracer('test-https')
let tracer: types.Tracer;
before(() => { before(() => {
nock.cleanAll(); nock.cleanAll();
nock.enableNetConnect(); 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. // Ensure that https module is patched.
assert.strictEqual(https.Server.prototype.emit.__wrapped, true); assert.strictEqual(https.Server.prototype.emit.__wrapped, true);
server = https.createServer( server = https.createServer(

View File

@ -19,7 +19,7 @@ import {
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
Http, Http,
HttpPluginConfig, HttpPluginConfig,
@ -50,11 +50,12 @@ const pathname = '/test';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); const tracer = registry.getTracer('test-https');
registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
function doNock( function doNock(
hostname: string, hostname: string,
@ -113,7 +114,7 @@ describe('HttpsPlugin', () => {
pluginWithBadOptions = new HttpsPlugin(process.versions.node); pluginWithBadOptions = new HttpsPlugin(process.versions.node);
pluginWithBadOptions.enable( pluginWithBadOptions.enable(
(https as unknown) as Http, (https as unknown) as Http,
tracer, registry,
tracer.logger, tracer.logger,
config config
); );
@ -202,7 +203,7 @@ describe('HttpsPlugin', () => {
}; };
plugin.enable( plugin.enable(
(https as unknown) as Http, (https as unknown) as Http,
tracer, registry,
tracer.logger, tracer.logger,
config config
); );
@ -231,7 +232,7 @@ describe('HttpsPlugin', () => {
it(`should not patch if it's not a ${protocol} module`, () => { it(`should not patch if it's not a ${protocol} module`, () => {
const httpsNotPatched = new HttpsPlugin(process.versions.node).enable( const httpsNotPatched = new HttpsPlugin(process.versions.node).enable(
{} as Http, {} as Http,
tracer, registry,
tracer.logger, tracer.logger,
{} {}
); );

View File

@ -15,7 +15,7 @@
*/ */
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { SpanKind } from '@opentelemetry/types'; import { SpanKind, Span } from '@opentelemetry/types';
import * as assert from 'assert'; import * as assert from 'assert';
import * as https from 'https'; import * as https from 'https';
import * as http from 'http'; import * as http from 'http';
@ -29,37 +29,35 @@ import * as superagent from 'superagent';
import * as got from 'got'; import * as got from 'got';
import * as request from 'request-promise-native'; import * as request from 'request-promise-native';
import * as path from 'path'; import * as path from 'path';
import { NodeTracer } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { Http } from '@opentelemetry/plugin-http';
import { Http, HttpPluginConfig } from '@opentelemetry/plugin-http'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { customAttributeFunction } from './https-enable.test';
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const protocol = 'https';
export const customAttributeFunction = (span: Span): void => {
span.setAttribute('span kind', SpanKind.CLIENT);
};
describe('Packages', () => { describe('Packages', () => {
describe('get', () => { describe('get', () => {
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
before(() => { before(() => {
const config: HttpPluginConfig = { plugin.enable((https as unknown) as Http, registry, registry.logger);
applyCustomAttributesOnSpan: customAttributeFunction,
};
plugin.enable((https as unknown) as Http, tracer, tracer.logger, config);
}); });
after(() => { after(() => {
@ -95,8 +93,8 @@ describe('Packages', () => {
// https://github.com/nock/nock/pull/1551 // https://github.com/nock/nock/pull/1551
// https://github.com/sindresorhus/got/commit/bf1aa5492ae2bc78cbbec6b7d764906fb156e6c2#diff-707a4781d57c42085155dcb27edb9ccbR258 // https://github.com/sindresorhus/got/commit/bf1aa5492ae2bc78cbbec6b7d764906fb156e6c2#diff-707a4781d57c42085155dcb27edb9ccbR258
// TODO: check if this is still the case when new version // TODO: check if this is still the case when new version
`${protocol}://www.google.com` 'https://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/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8`
); );
const result = await httpPackage.get(urlparsed.href!); const result = await httpPackage.get(urlparsed.href!);
if (!resHeaders) { if (!resHeaders) {

View File

@ -30,7 +30,7 @@ import { DummyPropagation } from '../utils/DummyPropagation';
import { httpsRequest } from '../utils/httpsRequest'; import { httpsRequest } from '../utils/httpsRequest';
import * as url from 'url'; import * as url from 'url';
import * as utils from '../utils/utils'; import * as utils from '../utils/utils';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -65,11 +65,11 @@ describe('HttpsPlugin Integration tests', () => {
const httpTextFormat = new DummyPropagation(); const httpTextFormat = new DummyPropagation();
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
logger, logger,
httpTextFormat, httpTextFormat,
}); });
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
beforeEach(() => { beforeEach(() => {
memoryExporter.reset(); memoryExporter.reset();
}); });
@ -88,7 +88,12 @@ describe('HttpsPlugin Integration tests', () => {
try { try {
plugin.disable(); plugin.disable();
} catch (e) {} } 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(() => { after(() => {

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { SpanKind, Status } from '@opentelemetry/types'; import { SpanKind } from '@opentelemetry/types';
import { hrTimeToNanoseconds } from '@opentelemetry/core'; import { hrTimeToNanoseconds } from '@opentelemetry/core';
import * as assert from 'assert'; import * as assert from 'assert';
import * as http from 'http'; import * as http from 'http';
@ -36,7 +36,6 @@ export const assertSpan = (
pathname: string; pathname: string;
reqHeaders?: http.OutgoingHttpHeaders; reqHeaders?: http.OutgoingHttpHeaders;
path?: string | null; path?: string | null;
forceStatus?: Status;
serverName?: string; serverName?: string;
component: string; component: string;
} }
@ -68,13 +67,12 @@ export const assertSpan = (
span.attributes[AttributeNames.HTTP_STATUS_CODE], span.attributes[AttributeNames.HTTP_STATUS_CODE],
validations.httpStatusCode validations.httpStatusCode
); );
assert.ok(span.endTime);
assert.strictEqual(span.links.length, 0); assert.strictEqual(span.links.length, 0);
assert.strictEqual(span.events.length, 0); assert.strictEqual(span.events.length, 0);
assert.deepStrictEqual( assert.deepStrictEqual(
span.status, span.status,
validations.forceStatus || parseResponseStatus(validations.httpStatusCode) parseResponseStatus(validations.httpStatusCode)
); );
assert.ok(span.endTime, 'must be finished'); assert.ok(span.endTime, 'must be finished');

View File

@ -18,6 +18,7 @@ import { BasePlugin } from '@opentelemetry/core';
import * as ioredisTypes from 'ioredis'; import * as ioredisTypes from 'ioredis';
import * as shimmer from 'shimmer'; import * as shimmer from 'shimmer';
import { traceConnection, traceSendCommand } from './utils'; import { traceConnection, traceSendCommand } from './utils';
import { VERSION } from './version';
export class IORedisPlugin extends BasePlugin<typeof ioredisTypes> { export class IORedisPlugin extends BasePlugin<typeof ioredisTypes> {
static readonly COMPONENT = 'ioredis'; static readonly COMPONENT = 'ioredis';
@ -25,7 +26,7 @@ export class IORedisPlugin extends BasePlugin<typeof ioredisTypes> {
readonly supportedVersions = ['^2.0.0']; readonly supportedVersions = ['^2.0.0'];
constructor(readonly moduleName: string) { constructor(readonly moduleName: string) {
super(); super('@opentelemetry/plugin-ioredis', VERSION);
} }
protected patch(): typeof ioredisTypes { protected patch(): typeof ioredisTypes {

View File

@ -19,7 +19,7 @@ import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin, IORedisPlugin } from '../src'; import { plugin, IORedisPlugin } from '../src';
import * as ioredisTypes from 'ioredis'; import * as ioredisTypes from 'ioredis';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
@ -49,7 +49,7 @@ const okStatus: Status = {
}; };
describe('ioredis', () => { describe('ioredis', () => {
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
let ioredis: typeof ioredisTypes; let ioredis: typeof ioredisTypes;
const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL;
const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal;
@ -68,8 +68,8 @@ describe('ioredis', () => {
} }
ioredis = require('ioredis'); ioredis = require('ioredis');
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
plugin.enable(ioredis, tracer, new NoopLogger()); plugin.enable(ioredis, registry, new NoopLogger());
}); });
after(() => { after(() => {
@ -84,7 +84,7 @@ describe('ioredis', () => {
describe('#createClient()', () => { describe('#createClient()', () => {
it('should propagate the current span to event handlers', done => { 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; let client: ioredisTypes.Redis;
const attributes = { const attributes = {
...DEFAULT_ATTRIBUTES, ...DEFAULT_ATTRIBUTES,
@ -93,7 +93,10 @@ describe('ioredis', () => {
const readyHandler = () => { const readyHandler = () => {
const endedSpans = memoryExporter.getFinishedSpans(); 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.length, 2);
assert.strictEqual(endedSpans[0].name, `connect`); assert.strictEqual(endedSpans[0].name, `connect`);
assert.strictEqual(endedSpans[1].name, `info`); assert.strictEqual(endedSpans[1].name, `info`);
@ -119,7 +122,7 @@ describe('ioredis', () => {
client.quit(done); client.quit(done);
}; };
tracer.withSpan(span, () => { registry.getTracer('ioredis-test').withSpan(span, () => {
client = new ioredis(URL); client = new ioredis(URL);
client.on('ready', readyHandler); client.on('ready', readyHandler);
client.on('error', errorHandler); client.on('error', errorHandler);
@ -183,8 +186,10 @@ describe('ioredis', () => {
' ' ' '
)}`, )}`,
}; };
const span = tracer.startSpan('test span'); const span = registry
tracer.withSpan(span, () => { .getTracer('ioredis-test')
.startSpan('test span');
registry.getTracer('ioredis-test').withSpan(span, () => {
command.method((err, _result) => { command.method((err, _result) => {
assert.ifError(err); assert.ifError(err);
assert.strictEqual(memoryExporter.getFinishedSpans().length, 1); assert.strictEqual(memoryExporter.getFinishedSpans().length, 1);
@ -211,8 +216,8 @@ describe('ioredis', () => {
...DEFAULT_ATTRIBUTES, ...DEFAULT_ATTRIBUTES,
[AttributeNames.DB_STATEMENT]: 'hset hash random random', [AttributeNames.DB_STATEMENT]: 'hset hash random random',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('ioredis-test').withSpan(span, async () => {
try { try {
await client.hset('hash', 'random', 'random'); await client.hset('hash', 'random', 'random');
assert.strictEqual(memoryExporter.getFinishedSpans().length, 1); assert.strictEqual(memoryExporter.getFinishedSpans().length, 1);
@ -239,8 +244,8 @@ describe('ioredis', () => {
...DEFAULT_ATTRIBUTES, ...DEFAULT_ATTRIBUTES,
[AttributeNames.DB_STATEMENT]: 'scan 0', [AttributeNames.DB_STATEMENT]: 'scan 0',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('ioredis-test').withSpan(span, () => {
const stream = client.scanStream(); const stream = client.scanStream();
stream stream
.on('data', resultKeys => { .on('data', resultKeys => {
@ -275,8 +280,8 @@ describe('ioredis', () => {
}); });
it('should create a child span for pubsub', async () => { it('should create a child span for pubsub', async () => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('ioredis-test').withSpan(span, async () => {
try { try {
const pub = new ioredis(URL); const pub = new ioredis(URL);
const sub = 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', [AttributeNames.DB_STATEMENT]: 'eval return {KEYS[1],ARGV[1]} 1 test',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('ioredis-test').withSpan(span, () => {
// This will define a command echo: // This will define a command echo:
client.defineCommand('echo', { client.defineCommand('echo', {
numberOfKeys: 1, numberOfKeys: 1,
@ -372,8 +377,8 @@ describe('ioredis', () => {
[AttributeNames.DB_STATEMENT]: 'multi', [AttributeNames.DB_STATEMENT]: 'multi',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('ioredis-test').withSpan(span, () => {
client client
.multi() .multi()
.set('foo', 'bar') .set('foo', 'bar')
@ -408,8 +413,8 @@ describe('ioredis', () => {
[AttributeNames.DB_STATEMENT]: 'set foo bar', [AttributeNames.DB_STATEMENT]: 'set foo bar',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('ioredis-test').withSpan(span, () => {
const pipeline = client.pipeline(); const pipeline = client.pipeline();
pipeline.set('foo', 'bar'); pipeline.set('foo', 'bar');
pipeline.del('cc'); pipeline.del('cc');
@ -441,8 +446,8 @@ describe('ioredis', () => {
...DEFAULT_ATTRIBUTES, ...DEFAULT_ATTRIBUTES,
[AttributeNames.DB_STATEMENT]: 'get test', [AttributeNames.DB_STATEMENT]: 'get test',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('ioredis-test').withSpan(span, async () => {
try { try {
const value = await client.get('test'); const value = await client.get('test');
assert.strictEqual(value, 'data'); assert.strictEqual(value, 'data');
@ -470,8 +475,8 @@ describe('ioredis', () => {
...DEFAULT_ATTRIBUTES, ...DEFAULT_ATTRIBUTES,
[AttributeNames.DB_STATEMENT]: 'del test', [AttributeNames.DB_STATEMENT]: 'del test',
}; };
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('ioredis-test').withSpan(span, async () => {
try { try {
const result = await client.del('test'); const result = await client.del('test');
assert.strictEqual(result, 1); assert.strictEqual(result, 1);
@ -502,8 +507,10 @@ describe('ioredis', () => {
IOREDIS_CALLBACK_OPERATIONS.forEach(operation => { IOREDIS_CALLBACK_OPERATIONS.forEach(operation => {
it(`should not create a child span for cb style ${operation.description}`, done => { it(`should not create a child span for cb style ${operation.description}`, done => {
const span = tracer.startSpan('test span'); const span = registry
tracer.withSpan(span, () => { .getTracer('ioredis-test')
.startSpan('test span');
registry.getTracer('ioredis-test').withSpan(span, () => {
operation.method((err, _) => { operation.method((err, _) => {
assert.ifError(err); assert.ifError(err);
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); 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 () => { it('should not create a child span for hset promise upon error', async () => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('ioredis-test').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('ioredis-test').withSpan(span, async () => {
try { try {
await client.hset('hash', 'random', 'random'); await client.hset('hash', 'random', 'random');
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);

View File

@ -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. To load a specific plugin (mongodb in this case), specify it in the Node Tracer's configuration.
```js ```js
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
mongodb: { mongodb: {
enabled: true, 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. 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 ```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. See [examples/mongodb](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/mongodb) for a short example.

View File

@ -18,16 +18,17 @@
/* tslint:disable:deprecation */ /* tslint:disable:deprecation */
import { BasePlugin } from '@opentelemetry/core'; import { BasePlugin } from '@opentelemetry/core';
import { Span, SpanKind, CanonicalCode } from '@opentelemetry/types'; import { CanonicalCode, Span, SpanKind } from '@opentelemetry/types';
import {
Func,
MongoInternalCommand,
MongoInternalTopology,
AttributeNames,
MongodbCommandType,
} from './types';
import * as mongodb from 'mongodb'; import * as mongodb from 'mongodb';
import * as shimmer from 'shimmer'; import * as shimmer from 'shimmer';
import {
AttributeNames,
Func,
MongodbCommandType,
MongoInternalCommand,
MongoInternalTopology,
} from './types';
import { VERSION } from './version';
/** MongoDBCore instrumentation plugin for OpenTelemetry */ /** MongoDBCore instrumentation plugin for OpenTelemetry */
export class MongoDBPlugin extends BasePlugin<typeof mongodb> { export class MongoDBPlugin extends BasePlugin<typeof mongodb> {
@ -40,7 +41,7 @@ export class MongoDBPlugin extends BasePlugin<typeof mongodb> {
readonly supportedVersions = ['>=2 <4']; readonly supportedVersions = ['>=2 <4'];
constructor(readonly moduleName: string) { constructor(readonly moduleName: string) {
super(); super('@opentelemetry/plugin-mongodb-core', VERSION);
} }
/** /**
@ -106,7 +107,7 @@ export class MongoDBPlugin extends BasePlugin<typeof mongodb> {
const resultHandler = const resultHandler =
typeof options === 'function' ? options : callback; typeof options === 'function' ? options : callback;
if ( if (
currentSpan === undefined || !currentSpan ||
typeof resultHandler !== 'function' || typeof resultHandler !== 'function' ||
typeof commands !== 'object' typeof commands !== 'object'
) { ) {
@ -210,7 +211,7 @@ export class MongoDBPlugin extends BasePlugin<typeof mongodb> {
): mongodb.Cursor { ): mongodb.Cursor {
const currentSpan = plugin._tracer.getCurrentSpan(); const currentSpan = plugin._tracer.getCurrentSpan();
const resultHandler = args[0]; const resultHandler = args[0];
if (currentSpan === undefined || typeof resultHandler !== 'function') { if (!currentSpan || typeof resultHandler !== 'function') {
return original.apply(this, args); return original.apply(this, args);
} }
const span = plugin._tracer.startSpan(`mongodb.query`, { const span = plugin._tracer.startSpan(`mongodb.query`, {

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import * as assert from 'assert'; import * as assert from 'assert';
import * as mongodb from 'mongodb'; import * as mongodb from 'mongodb';
import { plugin } from '../src'; import { plugin } from '../src';
@ -65,8 +65,12 @@ function accessCollection(
function assertSpans( function assertSpans(
spans: ReadableSpan[], spans: ReadableSpan[],
expectedName: string, expectedName: string,
expectedKind: SpanKind expectedKind: SpanKind,
log = false
) { ) {
if (log) {
console.log(spans);
}
assert.strictEqual(spans.length, 2); assert.strictEqual(spans.length, 2);
spans.forEach(span => { spans.forEach(span => {
assert(span.endTime instanceof Array); assert(span.endTime instanceof Array);
@ -75,10 +79,7 @@ function assertSpans(
const [mongoSpan] = spans; const [mongoSpan] = spans;
assert.strictEqual(mongoSpan.name, expectedName); assert.strictEqual(mongoSpan.name, expectedName);
assert.strictEqual(mongoSpan.kind, expectedKind); assert.strictEqual(mongoSpan.kind, expectedKind);
assert.strictEqual( assert.strictEqual(mongoSpan.attributes[AttributeNames.COMPONENT], 'mongodb');
mongoSpan.attributes[AttributeNames.COMPONENT],
'mongodb'
);
assert.strictEqual( assert.strictEqual(
mongoSpan.attributes[AttributeNames.PEER_HOSTNAME], mongoSpan.attributes[AttributeNames.PEER_HOSTNAME],
process.env.MONGODB_HOST || 'localhost' process.env.MONGODB_HOST || 'localhost'
@ -104,12 +105,13 @@ describe('MongoDBPlugin', () => {
let client: mongodb.MongoClient; let client: mongodb.MongoClient;
let collection: mongodb.Collection; let collection: mongodb.Collection;
const logger = new NoopLogger(); const logger = new NoopLogger();
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); const spanProcessor = new SimpleSpanProcessor(memoryExporter);
registry.addSpanProcessor(spanProcessor);
before(done => { before(done => {
plugin.enable(mongodb, tracer, logger); plugin.enable(mongodb, registry, logger);
accessCollection(URL, DB_NAME, COLLECTION_NAME) accessCollection(URL, DB_NAME, COLLECTION_NAME)
.then(result => { .then(result => {
client = result.client; client = result.client;
@ -155,8 +157,8 @@ describe('MongoDBPlugin', () => {
it('should create a child span for insert', done => { it('should create a child span for insert', done => {
const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }];
const span = tracer.startSpan(`insertRootSpan`); const span = registry.getTracer('default').startSpan(`insertRootSpan`);
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
collection.insertMany(insertData, (err, result) => { collection.insertMany(insertData, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -171,8 +173,8 @@ describe('MongoDBPlugin', () => {
}); });
it('should create a child span for update', done => { it('should create a child span for update', done => {
const span = tracer.startSpan('updateRootSpan'); const span = registry.getTracer('default').startSpan('updateRootSpan');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
collection.updateOne({ a: 2 }, { $set: { b: 1 } }, (err, result) => { collection.updateOne({ a: 2 }, { $set: { b: 1 } }, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -187,8 +189,8 @@ describe('MongoDBPlugin', () => {
}); });
it('should create a child span for remove', done => { it('should create a child span for remove', done => {
const span = tracer.startSpan('removeRootSpan'); const span = registry.getTracer('default').startSpan('removeRootSpan');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
collection.deleteOne({ a: 3 }, (err, result) => { collection.deleteOne({ a: 3 }, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -206,8 +208,8 @@ describe('MongoDBPlugin', () => {
/** Should intercept cursor */ /** Should intercept cursor */
describe('Instrumenting cursor operations', () => { describe('Instrumenting cursor operations', () => {
it('should create a child span for find', done => { it('should create a child span for find', done => {
const span = tracer.startSpan('findRootSpan'); const span = registry.getTracer('default').startSpan('findRootSpan');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
collection.find({}).toArray((err, result) => { collection.find({}).toArray((err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -225,8 +227,8 @@ describe('MongoDBPlugin', () => {
/** Should intercept command */ /** Should intercept command */
describe('Instrumenting command operations', () => { describe('Instrumenting command operations', () => {
it('should create a child span for create index', done => { it('should create a child span for create index', done => {
const span = tracer.startSpan('indexRootSpan'); const span = registry.getTracer('default').startSpan('indexRootSpan');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
collection.createIndex({ a: 1 }, (err, result) => { collection.createIndex({ a: 1 }, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -252,7 +254,7 @@ describe('MongoDBPlugin', () => {
it('should not create a child span for query', done => { it('should not create a child span for query', done => {
const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; 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) => { collection.insertMany(insertData, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -262,7 +264,7 @@ describe('MongoDBPlugin', () => {
}); });
it('should not create a child span for cursor', done => { 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) => { collection.find({}).toArray((err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);
@ -272,7 +274,7 @@ describe('MongoDBPlugin', () => {
}); });
it('should not create a child span for command', done => { 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) => { collection.createIndex({ a: 1 }, (err, result) => {
span.end(); span.end();
assert.ifError(err); assert.ifError(err);

View File

@ -5,6 +5,7 @@
"outDir": "build" "outDir": "build"
}, },
"include": [ "include": [
"src/**/*.ts" "src/**/*.ts",
"test/**/*.ts"
] ]
} }

View File

@ -20,9 +20,9 @@ import * as mysqlTypes from 'mysql';
import * as shimmer from 'shimmer'; import * as shimmer from 'shimmer';
import { AttributeNames } from './enums'; import { AttributeNames } from './enums';
import { getConnectionAttributes, getSpanName } from './utils'; import { getConnectionAttributes, getSpanName } from './utils';
import { VERSION } from './version';
export class MysqlPlugin extends BasePlugin<typeof mysqlTypes> { export class MysqlPlugin extends BasePlugin<typeof mysqlTypes> {
readonly moduleName = 'mysql';
readonly supportedVersions = ['2.*']; readonly supportedVersions = ['2.*'];
static readonly COMPONENT = 'mysql'; static readonly COMPONENT = 'mysql';
@ -36,6 +36,10 @@ export class MysqlPlugin extends BasePlugin<typeof mysqlTypes> {
private _enabled = false; private _enabled = false;
constructor(readonly moduleName: string) {
super('@opentelemetry/plugin-mysql', VERSION);
}
protected patch(): typeof mysqlTypes { protected patch(): typeof mysqlTypes {
this._enabled = true; this._enabled = true;
shimmer.wrap( shimmer.wrap(
@ -283,4 +287,4 @@ export class MysqlPlugin extends BasePlugin<typeof mysqlTypes> {
} }
} }
export const plugin = new MysqlPlugin(); export const plugin = new MysqlPlugin(MysqlPlugin.COMPONENT);

View File

@ -15,7 +15,7 @@
*/ */
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -38,7 +38,7 @@ describe('mysql@2.x', () => {
let connection: mysql.Connection; let connection: mysql.Connection;
let pool: mysql.Pool; let pool: mysql.Pool;
let poolCluster: mysql.PoolCluster; let poolCluster: mysql.PoolCluster;
const tracer = new NodeTracer({ plugins: {} }); const registry = new NodeTracerRegistry({ plugins: {} });
const logger = new NoopLogger(); const logger = new NoopLogger();
const testMysql = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available 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 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.test!.parent!.pending = true;
this.skip(); this.skip();
} }
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
if (testMysqlLocally) { if (testMysqlLocally) {
testUtils.startDocker('mysql'); testUtils.startDocker('mysql');
// wait 15 seconds for docker container to start // wait 15 seconds for docker container to start
@ -71,7 +71,7 @@ describe('mysql@2.x', () => {
}); });
beforeEach(function() { beforeEach(function() {
plugin.enable(mysql, tracer, logger); plugin.enable(mysql, registry, logger);
connection = mysql.createConnection({ connection = mysql.createConnection({
port, port,
user, user,
@ -118,8 +118,8 @@ describe('mysql@2.x', () => {
describe('#Connection', () => { describe('#Connection', () => {
it('should intercept connection.query(text: string)', done => { it('should intercept connection.query(text: string)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
const query = connection.query(statement); const query = connection.query(statement);
let rows = 0; let rows = 0;
@ -140,8 +140,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept connection.query(text: string, callback)', done => { it('should intercept connection.query(text: string, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
connection.query(statement, (err, res) => { connection.query(statement, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -156,8 +156,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept connection.query(text: options, callback)', done => { it('should intercept connection.query(text: options, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
connection.query({ sql: statement, values: [1] }, (err, res) => { connection.query({ sql: statement, values: [1] }, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -172,8 +172,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept connection.query(text: options, values: [], callback)', done => { it('should intercept connection.query(text: options, values: [], callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
// @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries
// but does not match the typings // but does not match the typings
@ -190,8 +190,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept connection.query(text: string, values: [], callback)', done => { it('should intercept connection.query(text: string, values: [], callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
connection.query(statement, [1], (err, res) => { connection.query(statement, [1], (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -206,8 +206,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept connection.query(text: string, value: any, callback)', done => { it('should intercept connection.query(text: string, value: any, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
connection.query(statement, 1, (err, res) => { connection.query(statement, 1, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -222,8 +222,8 @@ describe('mysql@2.x', () => {
}); });
it('should attach error messages to spans', done => { it('should attach error messages to spans', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
connection.query(statement, (err, res) => { connection.query(statement, (err, res) => {
assert.ok(err); assert.ok(err);
@ -238,8 +238,8 @@ describe('mysql@2.x', () => {
describe('#Pool', () => { describe('#Pool', () => {
it('should intercept pool.query(text: string)', done => { it('should intercept pool.query(text: string)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
const query = pool.query(statement); const query = pool.query(statement);
let rows = 0; let rows = 0;
@ -260,8 +260,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.getConnection().query(text: string)', done => { it('should intercept pool.getConnection().query(text: string)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
pool.getConnection((err, conn) => { pool.getConnection((err, conn) => {
const query = conn.query(statement); const query = conn.query(statement);
@ -284,8 +284,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.query(text: string, callback)', done => { it('should intercept pool.query(text: string, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
pool.query(statement, (err, res) => { pool.query(statement, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -300,8 +300,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.getConnection().query(text: string, callback)', done => { it('should intercept pool.getConnection().query(text: string, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
pool.getConnection((err, conn) => { pool.getConnection((err, conn) => {
conn.query(statement, (err, res) => { conn.query(statement, (err, res) => {
@ -318,8 +318,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.query(text: options, callback)', done => { it('should intercept pool.query(text: options, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
pool.query({ sql: statement, values: [1] }, (err, res) => { pool.query({ sql: statement, values: [1] }, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -334,8 +334,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.query(text: options, values: [], callback)', done => { it('should intercept pool.query(text: options, values: [], callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
// @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries
// but does not match the typings // but does not match the typings
@ -352,8 +352,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.query(text: string, values: [], callback)', done => { it('should intercept pool.query(text: string, values: [], callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
pool.query(statement, [1], (err, res) => { pool.query(statement, [1], (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -368,8 +368,8 @@ describe('mysql@2.x', () => {
}); });
it('should intercept pool.query(text: string, value: any, callback)', done => { it('should intercept pool.query(text: string, value: any, callback)', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
pool.query(statement, 1, (err, res) => { pool.query(statement, 1, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -384,8 +384,8 @@ describe('mysql@2.x', () => {
}); });
it('should attach error messages to spans', done => { it('should attach error messages to spans', done => {
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
pool.query(statement, (err, res) => { pool.query(statement, (err, res) => {
assert.ok(err); assert.ok(err);
@ -402,8 +402,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: string)', done => { it('should intercept poolClusterConnection.query(text: string)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
const query = poolClusterConnection.query(statement); const query = poolClusterConnection.query(statement);
let rows = 0; let rows = 0;
@ -427,8 +427,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: string, callback)', done => { it('should intercept poolClusterConnection.query(text: string, callback)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+1 as solution'; const statement = 'SELECT 1+1 as solution';
poolClusterConnection.query(statement, (err, res) => { poolClusterConnection.query(statement, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -446,8 +446,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: options, callback)', done => { it('should intercept poolClusterConnection.query(text: options, callback)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
poolClusterConnection.query( poolClusterConnection.query(
{ sql: statement, values: [1] }, { sql: statement, values: [1] },
@ -468,8 +468,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: options, values: [], callback)', done => { it('should intercept poolClusterConnection.query(text: options, values: [], callback)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1+? as solution'; const statement = 'SELECT 1+? as solution';
// @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries
// but does not match the typings // but does not match the typings
@ -489,8 +489,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: string, values: [], callback)', done => { it('should intercept poolClusterConnection.query(text: string, values: [], callback)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
poolClusterConnection.query(statement, [1], (err, res) => { poolClusterConnection.query(statement, [1], (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -508,8 +508,8 @@ describe('mysql@2.x', () => {
it('should intercept poolClusterConnection.query(text: string, value: any, callback)', done => { it('should intercept poolClusterConnection.query(text: string, value: any, callback)', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
poolClusterConnection.query(statement, 1, (err, res) => { poolClusterConnection.query(statement, 1, (err, res) => {
assert.ifError(err); assert.ifError(err);
@ -527,8 +527,8 @@ describe('mysql@2.x', () => {
it('should attach error messages to spans', done => { it('should attach error messages to spans', done => {
poolCluster.getConnection((err, poolClusterConnection) => { poolCluster.getConnection((err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT ? as solution'; const statement = 'SELECT ? as solution';
poolClusterConnection.query(statement, (err, res) => { poolClusterConnection.query(statement, (err, res) => {
assert.ok(err); assert.ok(err);
@ -544,8 +544,8 @@ describe('mysql@2.x', () => {
it('should get connection by name', done => { it('should get connection by name', done => {
poolCluster.getConnection('name', (err, poolClusterConnection) => { poolCluster.getConnection('name', (err, poolClusterConnection) => {
assert.ifError(err); assert.ifError(err);
const span = tracer.startSpan('test span'); const span = registry.getTracer('default').startSpan('test span');
tracer.withSpan(span, () => { registry.getTracer('default').withSpan(span, () => {
const statement = 'SELECT 1 as solution'; const statement = 'SELECT 1 as solution';
poolClusterConnection.query(statement, (err, res) => { poolClusterConnection.query(statement, (err, res) => {
assert.ifError(err); assert.ifError(err);

View File

@ -25,6 +25,7 @@ import {
PgPoolExtended, PgPoolExtended,
} from './types'; } from './types';
import * as utils from './utils'; import * as utils from './utils';
import { VERSION } from './version';
export class PostgresPoolPlugin extends BasePlugin<typeof pgPoolTypes> { export class PostgresPoolPlugin extends BasePlugin<typeof pgPoolTypes> {
protected _config: PostgresPoolPluginOptions; protected _config: PostgresPoolPluginOptions;
@ -35,7 +36,7 @@ export class PostgresPoolPlugin extends BasePlugin<typeof pgPoolTypes> {
readonly supportedVersions = ['2.*']; readonly supportedVersions = ['2.*'];
constructor(readonly moduleName: string) { constructor(readonly moduleName: string) {
super(); super('@opentelemetry/plugin-pg-pool', VERSION);
this._config = {}; this._config = {};
} }

View File

@ -15,7 +15,7 @@
*/ */
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -92,7 +92,7 @@ const runCallbackTest = (
describe('pg-pool@2.x', () => { describe('pg-pool@2.x', () => {
let pool: pgPool<pg.Client>; let pool: pgPool<pg.Client>;
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
const logger = new NoopLogger(); const logger = new NoopLogger();
const testPostgres = process.env.TEST_POSTGRES; // For CI: assumes local postgres db is already available 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 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(); this.skip();
} }
pool = new pgPool(CONFIG); pool = new pgPool(CONFIG);
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
if (testPostgresLocally) { if (testPostgresLocally) {
testUtils.startDocker('postgres'); testUtils.startDocker('postgres');
} }
@ -123,8 +123,8 @@ describe('pg-pool@2.x', () => {
}); });
beforeEach(function() { beforeEach(function() {
plugin.enable(pgPool, tracer, logger); plugin.enable(pgPool, registry, logger);
pgPlugin.enable(pg, tracer, logger); pgPlugin.enable(pg, registry, logger);
}); });
afterEach(() => { afterEach(() => {
@ -152,8 +152,8 @@ describe('pg-pool@2.x', () => {
[AttributeNames.DB_STATEMENT]: 'SELECT NOW()', [AttributeNames.DB_STATEMENT]: 'SELECT NOW()',
}; };
const events: TimedEvent[] = []; const events: TimedEvent[] = [];
const span = tracer.startSpan('test span'); const span = registry.getTracer('test-pg-pool').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('test-pg-pool').withSpan(span, async () => {
const client = await pool.connect(); const client = await pool.connect();
runCallbackTest(span, pgPoolattributes, events, okStatus, 1, 0); runCallbackTest(span, pgPoolattributes, events, okStatus, 1, 0);
assert.ok(client, 'pool.connect() returns a promise'); assert.ok(client, 'pool.connect() returns a promise');
@ -178,8 +178,10 @@ describe('pg-pool@2.x', () => {
[AttributeNames.DB_STATEMENT]: 'SELECT NOW()', [AttributeNames.DB_STATEMENT]: 'SELECT NOW()',
}; };
const events: TimedEvent[] = []; const events: TimedEvent[] = [];
const parentSpan = tracer.startSpan('test span'); const parentSpan = registry
tracer.withSpan(parentSpan, () => { .getTracer('test-pg-pool')
.startSpan('test span');
registry.getTracer('test-pg-pool').withSpan(parentSpan, () => {
const resNoPromise = pool.connect((err, client, release) => { const resNoPromise = pool.connect((err, client, release) => {
if (err) { if (err) {
return done(err); return done(err);
@ -212,8 +214,8 @@ describe('pg-pool@2.x', () => {
[AttributeNames.DB_STATEMENT]: 'SELECT NOW()', [AttributeNames.DB_STATEMENT]: 'SELECT NOW()',
}; };
const events: TimedEvent[] = []; const events: TimedEvent[] = [];
const span = tracer.startSpan('test span'); const span = registry.getTracer('test-pg-pool').startSpan('test span');
await tracer.withSpan(span, async () => { await registry.getTracer('test-pg-pool').withSpan(span, async () => {
try { try {
const result = await pool.query('SELECT NOW()'); const result = await pool.query('SELECT NOW()');
runCallbackTest(span, pgPoolattributes, events, okStatus, 2, 0); runCallbackTest(span, pgPoolattributes, events, okStatus, 2, 0);
@ -235,8 +237,10 @@ describe('pg-pool@2.x', () => {
[AttributeNames.DB_STATEMENT]: 'SELECT NOW()', [AttributeNames.DB_STATEMENT]: 'SELECT NOW()',
}; };
const events: TimedEvent[] = []; const events: TimedEvent[] = [];
const parentSpan = tracer.startSpan('test span'); const parentSpan = registry
tracer.withSpan(parentSpan, () => { .getTracer('test-pg-pool')
.startSpan('test span');
registry.getTracer('test-pg-pool').withSpan(parentSpan, () => {
const resNoPromise = pool.query('SELECT NOW()', (err, result) => { const resNoPromise = pool.query('SELECT NOW()', (err, result) => {
if (err) { if (err) {
return done(err); return done(err);

View File

@ -16,15 +16,16 @@
import { BasePlugin } from '@opentelemetry/core'; import { BasePlugin } from '@opentelemetry/core';
import { CanonicalCode, Span } from '@opentelemetry/types'; import { CanonicalCode, Span } from '@opentelemetry/types';
import * as pgTypes from 'pg';
import * as shimmer from 'shimmer';
import { import {
PostgresPluginOptions,
PgClientExtended, PgClientExtended,
PgPluginQueryConfig, PgPluginQueryConfig,
PostgresCallback, PostgresCallback,
PostgresPluginOptions,
} from './types'; } from './types';
import * as pgTypes from 'pg';
import * as shimmer from 'shimmer';
import * as utils from './utils'; import * as utils from './utils';
import { VERSION } from './version';
export class PostgresPlugin extends BasePlugin<typeof pgTypes> { export class PostgresPlugin extends BasePlugin<typeof pgTypes> {
protected _config: PostgresPluginOptions; protected _config: PostgresPluginOptions;
@ -37,7 +38,7 @@ export class PostgresPlugin extends BasePlugin<typeof pgTypes> {
readonly supportedVersions = ['7.*']; readonly supportedVersions = ['7.*'];
constructor(readonly moduleName: string) { constructor(readonly moduleName: string) {
super(); super('@opentelemetry/plugin-pg', VERSION);
this._config = {}; this._config = {};
} }

View File

@ -15,7 +15,7 @@
*/ */
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
@ -81,7 +81,8 @@ const runCallbackTest = (
describe('pg@7.x', () => { describe('pg@7.x', () => {
let client: pg.Client; let client: pg.Client;
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
const tracer = registry.getTracer('external');
const logger = new NoopLogger(); const logger = new NoopLogger();
const testPostgres = process.env.RUN_POSTGRES_TESTS; // For CI: assumes local postgres db is already available 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 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.test!.parent!.pending = true;
this.skip(); this.skip();
} }
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
if (testPostgresLocally) { if (testPostgresLocally) {
testUtils.startDocker('postgres'); testUtils.startDocker('postgres');
} }
@ -115,7 +116,7 @@ describe('pg@7.x', () => {
}); });
beforeEach(function() { beforeEach(function() {
plugin.enable(pg, tracer, logger); plugin.enable(pg, registry, logger);
}); });
afterEach(() => { afterEach(() => {

View File

@ -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 To load a specific plugin (**redis** in this case), specify it in the Node Tracer's configuration
```js ```js
const { NodeTracer } = require('@opentelemetry/node'); const { NodeTracerRegistry } = require('@opentelemetry/node');
const tracer = new NodeTracer({ const registry = new NodeTracerRegistry({
plugins: { plugins: {
redis: { redis: {
enabled: true, 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. 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 ```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. See [examples/redis](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/redis) for a short example.

View File

@ -22,13 +22,14 @@ import {
getTracedCreateStreamTrace, getTracedCreateStreamTrace,
getTracedInternalSendCommand, getTracedInternalSendCommand,
} from './utils'; } from './utils';
import { VERSION } from './version';
export class RedisPlugin extends BasePlugin<typeof redisTypes> { export class RedisPlugin extends BasePlugin<typeof redisTypes> {
static readonly COMPONENT = 'redis'; static readonly COMPONENT = 'redis';
readonly supportedVersions = ['^2.6.0']; // equivalent to >= 2.6.0 <3 readonly supportedVersions = ['^2.6.0']; // equivalent to >= 2.6.0 <3
constructor(readonly moduleName: string) { constructor(readonly moduleName: string) {
super(); super('@opentelemetry/plugin-redis', VERSION);
} }
protected patch() { protected patch() {

View File

@ -19,7 +19,7 @@ import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
} from '@opentelemetry/tracing'; } from '@opentelemetry/tracing';
import { NodeTracer } from '@opentelemetry/node'; import { NodeTracerRegistry } from '@opentelemetry/node';
import { plugin, RedisPlugin } from '../src'; import { plugin, RedisPlugin } from '../src';
import * as redisTypes from 'redis'; import * as redisTypes from 'redis';
import { NoopLogger } from '@opentelemetry/core'; import { NoopLogger } from '@opentelemetry/core';
@ -48,7 +48,8 @@ const okStatus: Status = {
}; };
describe('redis@2.x', () => { describe('redis@2.x', () => {
const tracer = new NodeTracer(); const registry = new NodeTracerRegistry();
const tracer = registry.getTracer('external');
let redis: typeof redisTypes; let redis: typeof redisTypes;
const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL; const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL;
const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal; const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal;
@ -67,8 +68,8 @@ describe('redis@2.x', () => {
} }
redis = require('redis'); redis = require('redis');
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
plugin.enable(redis, tracer, new NoopLogger()); plugin.enable(redis, registry, new NoopLogger());
}); });
after(() => { after(() => {

View File

@ -69,15 +69,12 @@ export class XMLHttpRequestPlugin extends BasePlugin<XMLHttpRequest> {
readonly version: string = VERSION; readonly version: string = VERSION;
moduleName = this.component; moduleName = this.component;
protected _config!: XMLHttpRequestPluginConfig;
private _tasksCount = 0; private _tasksCount = 0;
private _xhrMem = new WeakMap<XMLHttpRequest, XhrMem>(); private _xhrMem = new WeakMap<XMLHttpRequest, XhrMem>();
private _usedResources = new WeakSet<PerformanceResourceTiming>(); private _usedResources = new WeakSet<PerformanceResourceTiming>();
constructor(config: XMLHttpRequestPluginConfig = {}) { constructor(protected _config: XMLHttpRequestPluginConfig = {}) {
super(); super('@opentelemetry/plugin-xml-http-request', VERSION);
this._config = config;
} }
/** /**

View File

@ -27,10 +27,14 @@ import {
import { ZoneScopeManager } from '@opentelemetry/scope-zone'; import { ZoneScopeManager } from '@opentelemetry/scope-zone';
import * as tracing from '@opentelemetry/tracing'; import * as tracing from '@opentelemetry/tracing';
import * as types from '@opentelemetry/types'; 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 { AttributeNames } from '../src/enums/AttributeNames';
import { EventNames } from '../src/enums/EventNames'; import { EventNames } from '../src/enums/EventNames';
import { XMLHttpRequestPlugin } from '../src/xhr'; import { XMLHttpRequestPlugin } from '../src/xhr';
import { Tracer } from '@opentelemetry/types';
class DummySpanExporter implements tracing.SpanExporter { class DummySpanExporter implements tracing.SpanExporter {
export(spans: any) {} export(spans: any) {}
@ -97,7 +101,8 @@ describe('xhr', () => {
let clearData: any; let clearData: any;
describe('when request is successful', () => { describe('when request is successful', () => {
let webTracerWithZone: WebTracer; let webTracerWithZone: Tracer;
let webTracerRegistryWithZone: WebTracerRegistry;
let dummySpanExporter: DummySpanExporter; let dummySpanExporter: DummySpanExporter;
let exportSpy: any; let exportSpy: any;
let rootSpan: types.Span; let rootSpan: types.Span;
@ -136,7 +141,7 @@ describe('xhr', () => {
spyEntries = sandbox.stub(performance, 'getEntriesByType'); spyEntries = sandbox.stub(performance, 'getEntriesByType');
spyEntries.withArgs('resource').returns(resources); spyEntries.withArgs('resource').returns(resources);
webTracerWithZone = new WebTracer({ webTracerRegistryWithZone = new WebTracerRegistry({
logLevel: LogLevel.ERROR, logLevel: LogLevel.ERROR,
httpTextFormat: new B3Format(), httpTextFormat: new B3Format(),
scopeManager: new ZoneScopeManager(), scopeManager: new ZoneScopeManager(),
@ -146,9 +151,10 @@ describe('xhr', () => {
}), }),
], ],
}); });
webTracerWithZone = webTracerRegistryWithZone.getTracer('xhr-test');
dummySpanExporter = new DummySpanExporter(); dummySpanExporter = new DummySpanExporter();
exportSpy = sinon.stub(dummySpanExporter, 'export'); exportSpy = sinon.stub(dummySpanExporter, 'export');
webTracerWithZone.addSpanProcessor( webTracerRegistryWithZone.addSpanProcessor(
new tracing.SimpleSpanProcessor(dummySpanExporter) new tracing.SimpleSpanProcessor(dummySpanExporter)
); );
@ -403,7 +409,8 @@ describe('xhr', () => {
}); });
describe('when request is NOT successful', () => { describe('when request is NOT successful', () => {
let webTracerWithZone: WebTracer; let webTracerWithZoneRegistry: WebTracerRegistry;
let webTracerWithZone: Tracer;
let dummySpanExporter: DummySpanExporter; let dummySpanExporter: DummySpanExporter;
let exportSpy: any; let exportSpy: any;
let rootSpan: types.Span; let rootSpan: types.Span;
@ -434,16 +441,17 @@ describe('xhr', () => {
spyEntries = sandbox.stub(performance, 'getEntriesByType'); spyEntries = sandbox.stub(performance, 'getEntriesByType');
spyEntries.withArgs('resource').returns(resources); spyEntries.withArgs('resource').returns(resources);
webTracerWithZone = new WebTracer({ webTracerWithZoneRegistry = new WebTracerRegistry({
logLevel: LogLevel.ERROR, logLevel: LogLevel.ERROR,
scopeManager: new ZoneScopeManager(), scopeManager: new ZoneScopeManager(),
plugins: [new XMLHttpRequestPlugin()], plugins: [new XMLHttpRequestPlugin()],
}); });
dummySpanExporter = new DummySpanExporter(); dummySpanExporter = new DummySpanExporter();
exportSpy = sinon.stub(dummySpanExporter, 'export'); exportSpy = sinon.stub(dummySpanExporter, 'export');
webTracerWithZone.addSpanProcessor( webTracerWithZoneRegistry.addSpanProcessor(
new tracing.SimpleSpanProcessor(dummySpanExporter) new tracing.SimpleSpanProcessor(dummySpanExporter)
); );
webTracerWithZone = webTracerWithZoneRegistry.getTracer('xhr-test');
rootSpan = webTracerWithZone.startSpan('root'); rootSpan = webTracerWithZone.startSpan('root');

View File

@ -16,14 +16,16 @@
import * as assert from 'assert'; import * as assert from 'assert';
import * as opentracing from 'opentracing'; 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 { TracerShim, SpanShim, SpanContextShim } from '../src/shim';
import { INVALID_SPAN_CONTEXT, timeInputToHrTime } from '@opentelemetry/core'; import { INVALID_SPAN_CONTEXT, timeInputToHrTime } from '@opentelemetry/core';
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
describe('OpenTracing Shim', () => { describe('OpenTracing Shim', () => {
const tracer = new BasicTracer(); const registry = new BasicTracerRegistry();
const shimTracer: opentracing.Tracer = new TracerShim(tracer); const shimTracer: opentracing.Tracer = new TracerShim(
registry.getTracer('default')
);
opentracing.initGlobalTracer(shimTracer); opentracing.initGlobalTracer(shimTracer);
describe('TracerShim', () => { describe('TracerShim', () => {

View File

@ -25,22 +25,19 @@ npm install --save @opentelemetry/tracing
```js ```js
const opentelemetry = require('@opentelemetry/core'); 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. // To start a trace, you first need to initialize the Tracer registry.
// NOTE: the default OpenTelemetry tracer does not record any tracing information. // NOTE: the default OpenTelemetry tracer registry does not record any tracing information.
const tracer = new BasicTracer(); opentelemetry.initGlobalTracer(new BasicTracerRegistry());
// Initialize the OpenTelemetry APIs to use the BasicTracer bindings
opentelemetry.initGlobalTracer(tracer);
// To create a span in a trace, we used the global singleton tracer to start a new span. // 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'); 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(); span.end();
``` ```

View File

@ -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<string, Tracer> = 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;
}
}

View File

@ -22,7 +22,7 @@ import {
timeInputToHrTime, timeInputToHrTime,
} from '@opentelemetry/core'; } from '@opentelemetry/core';
import { ReadableSpan } from './export/ReadableSpan'; import { ReadableSpan } from './export/ReadableSpan';
import { BasicTracer } from './BasicTracer'; import { Tracer } from './Tracer';
import { SpanProcessor } from './SpanProcessor'; import { SpanProcessor } from './SpanProcessor';
import { TraceParams } from './types'; import { TraceParams } from './types';
@ -52,7 +52,7 @@ export class Span implements types.Span, ReadableSpan {
/** Constructs a new Span instance. */ /** Constructs a new Span instance. */
constructor( constructor(
parentTracer: BasicTracer, parentTracer: Tracer,
spanName: string, spanName: string,
spanContext: types.SpanContext, spanContext: types.SpanContext,
kind: types.SpanKind, kind: types.SpanKind,
@ -68,7 +68,7 @@ export class Span implements types.Span, ReadableSpan {
this.startTime = timeInputToHrTime(startTime); this.startTime = timeInputToHrTime(startTime);
this._logger = parentTracer.logger; this._logger = parentTracer.logger;
this._traceParams = parentTracer.getActiveTraceParams(); this._traceParams = parentTracer.getActiveTraceParams();
this._spanProcessor = parentTracer.activeSpanProcessor; this._spanProcessor = parentTracer.getActiveSpanProcessor();
this._spanProcessor.onStart(this); this._spanProcessor.onStart(this);
} }

View File

@ -28,19 +28,17 @@ import {
TraceFlags, TraceFlags,
Logger, Logger,
} from '@opentelemetry/types'; } from '@opentelemetry/types';
import { BasicTracerConfig, TraceParams } from './types'; import { TracerConfig, TraceParams } from './types';
import { ScopeManager } from '@opentelemetry/scope-base'; import { ScopeManager } from '@opentelemetry/scope-base';
import { Span } from './Span'; import { Span } from './Span';
import { mergeConfig } from './utility'; import { mergeConfig } from './utility';
import { SpanProcessor } from './SpanProcessor';
import { NoopSpanProcessor } from './NoopSpanProcessor';
import { MultiSpanProcessor } from './MultiSpanProcessor';
import { DEFAULT_CONFIG } from './config'; import { DEFAULT_CONFIG } from './config';
import { BasicTracerRegistry } from './BasicTracerRegistry';
/** /**
* This class represents a basic tracer. * 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 _defaultAttributes: types.Attributes;
private readonly _binaryFormat: types.BinaryFormat; private readonly _binaryFormat: types.BinaryFormat;
private readonly _httpTextFormat: types.HttpTextFormat; private readonly _httpTextFormat: types.HttpTextFormat;
@ -48,13 +46,14 @@ export class BasicTracer implements types.Tracer {
private readonly _scopeManager: ScopeManager; private readonly _scopeManager: ScopeManager;
private readonly _traceParams: TraceParams; private readonly _traceParams: TraceParams;
readonly logger: Logger; readonly logger: Logger;
private readonly _registeredSpanProcessor: SpanProcessor[] = [];
activeSpanProcessor = new NoopSpanProcessor();
/** /**
* Constructs a new Tracer instance. * Constructs a new Tracer instance.
*/ */
constructor(config: BasicTracerConfig = DEFAULT_CONFIG) { constructor(
config: TracerConfig = DEFAULT_CONFIG,
private _tracerRegistry: BasicTracerRegistry
) {
const localConfig = mergeConfig(config); const localConfig = mergeConfig(config);
this._binaryFormat = localConfig.binaryFormat; this._binaryFormat = localConfig.binaryFormat;
this._defaultAttributes = localConfig.defaultAttributes; this._defaultAttributes = localConfig.defaultAttributes;
@ -162,15 +161,8 @@ export class BasicTracer implements types.Tracer {
return this._traceParams; return this._traceParams;
} }
/** getActiveSpanProcessor() {
* Adds a new {@link SpanProcessor} to this tracer. return this._tracerRegistry.getActiveSpanProcessor();
* @param spanProcessor the new SpanProcessor to be added.
*/
addSpanProcessor(spanProcessor: SpanProcessor): void {
this._registeredSpanProcessor.push(spanProcessor);
this.activeSpanProcessor = new MultiSpanProcessor(
this._registeredSpanProcessor
);
} }
private _getParentSpanContext( private _getParentSpanContext(

View File

@ -14,7 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './BasicTracer'; export * from './Tracer';
export * from './BasicTracerRegistry';
export * from './export/ConsoleSpanExporter'; export * from './export/ConsoleSpanExporter';
export * from './export/BatchSpanProcessor'; export * from './export/BatchSpanProcessor';
export * from './export/InMemorySpanExporter'; export * from './export/InMemorySpanExporter';

View File

@ -25,9 +25,9 @@ import {
import { LogLevel } from '@opentelemetry/core'; 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. * Binary formatter which can serialize/deserialize Spans.
*/ */

View File

@ -14,19 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { BasicTracerConfig } from './types';
import { import {
DEFAULT_CONFIG,
DEFAULT_MAX_ATTRIBUTES_PER_SPAN, DEFAULT_MAX_ATTRIBUTES_PER_SPAN,
DEFAULT_MAX_EVENTS_PER_SPAN, DEFAULT_MAX_EVENTS_PER_SPAN,
DEFAULT_MAX_LINKS_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN,
} from './config'; } from './config';
import { DEFAULT_CONFIG } from './config'; import { TracerConfig } from './types';
/** /**
* Function to merge Default configuration (as specified in './config') with * Function to merge Default configuration (as specified in './config') with
* user provided configurations. * user provided configurations.
*/ */
export function mergeConfig(userConfig: BasicTracerConfig) { export function mergeConfig(userConfig: TracerConfig) {
const traceParams = userConfig.traceParams; const traceParams = userConfig.traceParams;
const target = Object.assign({}, DEFAULT_CONFIG, userConfig); const target = Object.assign({}, DEFAULT_CONFIG, userConfig);

View File

@ -14,62 +14,62 @@
* limitations under the License. * limitations under the License.
*/ */
import * as assert from 'assert';
import { import {
ALWAYS_SAMPLER, ALWAYS_SAMPLER,
BinaryTraceContext, BinaryTraceContext,
HttpTraceContext, HttpTraceContext,
NEVER_SAMPLER, NEVER_SAMPLER,
NoopLogger, NoopLogger,
TraceState,
NoRecordingSpan, NoRecordingSpan,
TraceState,
} from '@opentelemetry/core'; } from '@opentelemetry/core';
import { TraceFlags } from '@opentelemetry/types';
import { BasicTracer, Span } from '../src';
import { NoopScopeManager, ScopeManager } from '@opentelemetry/scope-base'; 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', () => { describe('constructor', () => {
it('should construct an instance without any options', () => { it('should construct an instance without any options', () => {
const tracer = new BasicTracer(); const registry = new BasicTracerRegistry();
assert.ok(tracer instanceof BasicTracer); assert.ok(registry instanceof BasicTracerRegistry);
}); });
it('should construct an instance with binary format', () => { it('should construct an instance with binary format', () => {
const tracer = new BasicTracer({ const registry = new BasicTracerRegistry({
binaryFormat: new BinaryTraceContext(), binaryFormat: new BinaryTraceContext(),
}); });
assert.ok(tracer instanceof BasicTracer); assert.ok(registry instanceof BasicTracerRegistry);
}); });
it('should construct an instance with http text format', () => { it('should construct an instance with http text format', () => {
const tracer = new BasicTracer({ const registry = new BasicTracerRegistry({
httpTextFormat: new HttpTraceContext(), httpTextFormat: new HttpTraceContext(),
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
}); });
assert.ok(tracer instanceof BasicTracer); assert.ok(registry instanceof BasicTracerRegistry);
}); });
it('should construct an instance with logger', () => { it('should construct an instance with logger', () => {
const tracer = new BasicTracer({ const registry = new BasicTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
}); });
assert.ok(tracer instanceof BasicTracer); assert.ok(registry instanceof BasicTracerRegistry);
}); });
it('should construct an instance with sampler', () => { it('should construct an instance with sampler', () => {
const tracer = new BasicTracer({ const registry = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
sampler: ALWAYS_SAMPLER, sampler: ALWAYS_SAMPLER,
}); });
assert.ok(tracer instanceof BasicTracer); assert.ok(registry instanceof BasicTracerRegistry);
}); });
it('should construct an instance with default trace params', () => { it('should construct an instance with default trace params', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
}); }).getTracer('default');
assert.deepStrictEqual(tracer.getActiveTraceParams(), { assert.deepStrictEqual(tracer.getActiveTraceParams(), {
numberOfAttributesPerSpan: 32, numberOfAttributesPerSpan: 32,
numberOfEventsPerSpan: 128, numberOfEventsPerSpan: 128,
@ -78,12 +78,12 @@ describe('BasicTracer', () => {
}); });
it('should construct an instance with customized numberOfAttributesPerSpan trace params', () => { it('should construct an instance with customized numberOfAttributesPerSpan trace params', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
traceParams: { traceParams: {
numberOfAttributesPerSpan: 100, numberOfAttributesPerSpan: 100,
}, },
}); }).getTracer('default');
assert.deepStrictEqual(tracer.getActiveTraceParams(), { assert.deepStrictEqual(tracer.getActiveTraceParams(), {
numberOfAttributesPerSpan: 100, numberOfAttributesPerSpan: 100,
numberOfEventsPerSpan: 128, numberOfEventsPerSpan: 128,
@ -92,12 +92,12 @@ describe('BasicTracer', () => {
}); });
it('should construct an instance with customized numberOfEventsPerSpan trace params', () => { it('should construct an instance with customized numberOfEventsPerSpan trace params', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
traceParams: { traceParams: {
numberOfEventsPerSpan: 300, numberOfEventsPerSpan: 300,
}, },
}); }).getTracer('default');
assert.deepStrictEqual(tracer.getActiveTraceParams(), { assert.deepStrictEqual(tracer.getActiveTraceParams(), {
numberOfAttributesPerSpan: 32, numberOfAttributesPerSpan: 32,
numberOfEventsPerSpan: 300, numberOfEventsPerSpan: 300,
@ -106,12 +106,12 @@ describe('BasicTracer', () => {
}); });
it('should construct an instance with customized numberOfLinksPerSpan trace params', () => { it('should construct an instance with customized numberOfLinksPerSpan trace params', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
traceParams: { traceParams: {
numberOfLinksPerSpan: 10, numberOfLinksPerSpan: 10,
}, },
}); }).getTracer('default');
assert.deepStrictEqual(tracer.getActiveTraceParams(), { assert.deepStrictEqual(tracer.getActiveTraceParams(), {
numberOfAttributesPerSpan: 32, numberOfAttributesPerSpan: 32,
numberOfEventsPerSpan: 128, numberOfEventsPerSpan: 128,
@ -120,26 +120,26 @@ describe('BasicTracer', () => {
}); });
it('should construct an instance with default attributes', () => { it('should construct an instance with default attributes', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
defaultAttributes: { defaultAttributes: {
region: 'eu-west', region: 'eu-west',
asg: 'my-asg', asg: 'my-asg',
}, },
}); });
assert.ok(tracer instanceof BasicTracer); assert.ok(tracer instanceof BasicTracerRegistry);
}); });
}); });
describe('.startSpan()', () => { describe('.startSpan()', () => {
it('should start a span with name only', () => { it('should start a span with name only', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
const span = tracer.startSpan('my-span'); const span = tracer.startSpan('my-span');
assert.ok(span); assert.ok(span);
assert.ok(span instanceof Span); assert.ok(span instanceof Span);
}); });
it('should start a span with name and options', () => { 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', {}); const span = tracer.startSpan('my-span', {});
assert.ok(span); assert.ok(span);
assert.ok(span instanceof Span); assert.ok(span instanceof Span);
@ -152,9 +152,9 @@ describe('BasicTracer', () => {
}); });
it('should start a span with defaultAttributes and spanoptions->attributes', () => { it('should start a span with defaultAttributes and spanoptions->attributes', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
defaultAttributes: { foo: 'bar' }, defaultAttributes: { foo: 'bar' },
}); }).getTracer('default');
const span = tracer.startSpan('my-span', { const span = tracer.startSpan('my-span', {
attributes: { foo: 'foo', bar: 'bar' }, attributes: { foo: 'foo', bar: 'bar' },
}) as Span; }) as Span;
@ -163,16 +163,16 @@ describe('BasicTracer', () => {
}); });
it('should start a span with defaultAttributes and undefined spanoptions->attributes', () => { it('should start a span with defaultAttributes and undefined spanoptions->attributes', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
defaultAttributes: { foo: 'bar' }, defaultAttributes: { foo: 'bar' },
}); }).getTracer('default');
const span = tracer.startSpan('my-span', {}) as Span; const span = tracer.startSpan('my-span', {}) as Span;
assert.deepStrictEqual(span.attributes, { foo: 'bar' }); assert.deepStrictEqual(span.attributes, { foo: 'bar' });
span.end(); span.end();
}); });
it('should start a span with spanoptions->attributes', () => { it('should start a span with spanoptions->attributes', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
const span = tracer.startSpan('my-span', { const span = tracer.startSpan('my-span', {
attributes: { foo: 'foo', bar: 'bar' }, attributes: { foo: 'foo', bar: 'bar' },
}) as Span; }) as Span;
@ -181,7 +181,7 @@ describe('BasicTracer', () => {
}); });
it('should start a span with name and parent spancontext', () => { 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 state = new TraceState('a=1,b=2');
const span = tracer.startSpan('my-span', { const span = tracer.startSpan('my-span', {
parent: { parent: {
@ -199,7 +199,7 @@ describe('BasicTracer', () => {
}); });
it('should start a span with name and parent span', () => { 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 span = tracer.startSpan('my-span');
const childSpan = tracer.startSpan('child-span', { const childSpan = tracer.startSpan('child-span', {
parent: span, parent: span,
@ -212,7 +212,7 @@ describe('BasicTracer', () => {
}); });
it('should start a span with name and with invalid parent span', () => { 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', { const span = tracer.startSpan('my-span', {
parent: ('invalid-parent' as unknown) as undefined, parent: ('invalid-parent' as unknown) as undefined,
}) as Span; }) as Span;
@ -220,7 +220,7 @@ describe('BasicTracer', () => {
}); });
it('should start a span with name and with invalid spancontext', () => { 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', { const span = tracer.startSpan('my-span', {
parent: { traceId: '0', spanId: '0' }, parent: { traceId: '0', spanId: '0' },
}); });
@ -233,10 +233,10 @@ describe('BasicTracer', () => {
}); });
it('should return a no recording span when never sampling', () => { it('should return a no recording span when never sampling', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: NEVER_SAMPLER, sampler: NEVER_SAMPLER,
logger: new NoopLogger(), logger: new NoopLogger(),
}); }).getTracer('default');
const span = tracer.startSpan('my-span'); const span = tracer.startSpan('my-span');
assert.ok(span instanceof NoRecordingSpan); assert.ok(span instanceof NoRecordingSpan);
const context = span.context(); const context = span.context();
@ -248,9 +248,9 @@ describe('BasicTracer', () => {
}); });
it('should create real span when not sampled but recording events true', () => { it('should create real span when not sampled but recording events true', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: NEVER_SAMPLER, sampler: NEVER_SAMPLER,
}); }).getTracer('default');
const span = tracer.startSpan('my-span', { isRecording: true }); const span = tracer.startSpan('my-span', { isRecording: true });
assert.ok(span instanceof Span); assert.ok(span instanceof Span);
assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); 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', () => { it('should not create real span when not sampled and recording events false', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: NEVER_SAMPLER, sampler: NEVER_SAMPLER,
logger: new NoopLogger(), logger: new NoopLogger(),
}); }).getTracer('default');
const span = tracer.startSpan('my-span', { isRecording: false }); const span = tracer.startSpan('my-span', { isRecording: false });
assert.ok(span instanceof NoRecordingSpan); assert.ok(span instanceof NoRecordingSpan);
assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); 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', () => { 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, sampler: NEVER_SAMPLER,
logger: new NoopLogger(), logger: new NoopLogger(),
}); }).getTracer('default');
const span = tracer.startSpan('my-span'); const span = tracer.startSpan('my-span');
assert.ok(span instanceof NoRecordingSpan); assert.ok(span instanceof NoRecordingSpan);
assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED); assert.strictEqual(span.context().traceFlags, TraceFlags.UNSAMPLED);
@ -280,10 +280,10 @@ describe('BasicTracer', () => {
}); });
it('should create real span when sampled and recording events true', () => { it('should create real span when sampled and recording events true', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: ALWAYS_SAMPLER, sampler: ALWAYS_SAMPLER,
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
}); }).getTracer('default');
const span = tracer.startSpan('my-span', { isRecording: true }); const span = tracer.startSpan('my-span', { isRecording: true });
assert.ok(span instanceof Span); assert.ok(span instanceof Span);
assert.strictEqual(span.context().traceFlags, TraceFlags.SAMPLED); assert.strictEqual(span.context().traceFlags, TraceFlags.SAMPLED);
@ -294,10 +294,10 @@ describe('BasicTracer', () => {
const defaultAttributes = { const defaultAttributes = {
foo: 'bar', foo: 'bar',
}; };
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: new NoopScopeManager(), scopeManager: new NoopScopeManager(),
defaultAttributes, defaultAttributes,
}); }).getTracer('default');
const span = tracer.startSpan('my-span') as Span; const span = tracer.startSpan('my-span') as Span;
assert.ok(span instanceof Span); assert.ok(span instanceof Span);
@ -306,25 +306,25 @@ describe('BasicTracer', () => {
}); });
describe('.getCurrentSpan()', () => { describe('.getCurrentSpan()', () => {
it('should return undefined with NoopScopeManager', () => { it('should return null with NoopScopeManager', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
const currentSpan = tracer.getCurrentSpan(); const currentSpan = tracer.getCurrentSpan();
assert.deepStrictEqual(currentSpan, undefined); assert.deepStrictEqual(currentSpan, undefined);
}); });
it('should return current span when it exists', () => { it('should return current span when it exists', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
scopeManager: { scopeManager: {
active: () => 'foo', active: () => 'foo',
} as ScopeManager, } as ScopeManager,
}); }).getTracer('default');
assert.deepStrictEqual(tracer.getCurrentSpan(), 'foo'); assert.deepStrictEqual(tracer.getCurrentSpan(), 'foo');
}); });
}); });
describe('.withSpan()', () => { describe('.withSpan()', () => {
it('should run scope with NoopScopeManager scope manager', done => { 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'); const span = tracer.startSpan('my-span');
tracer.withSpan(span, () => { tracer.withSpan(span, () => {
assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); assert.deepStrictEqual(tracer.getCurrentSpan(), undefined);
@ -335,7 +335,7 @@ describe('BasicTracer', () => {
describe('.bind()', () => { describe('.bind()', () => {
it('should bind scope with NoopScopeManager scope manager', done => { 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 span = tracer.startSpan('my-span');
const fn = () => { const fn = () => {
assert.deepStrictEqual(tracer.getCurrentSpan(), undefined); assert.deepStrictEqual(tracer.getCurrentSpan(), undefined);
@ -348,14 +348,14 @@ describe('BasicTracer', () => {
describe('.getBinaryFormat()', () => { describe('.getBinaryFormat()', () => {
it('should get default binary formatter', () => { it('should get default binary formatter', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
assert.ok(tracer.getBinaryFormat() instanceof BinaryTraceContext); assert.ok(tracer.getBinaryFormat() instanceof BinaryTraceContext);
}); });
}); });
describe('.getHttpTextFormat()', () => { describe('.getHttpTextFormat()', () => {
it('should get default HTTP text formatter', () => { it('should get default HTTP text formatter', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
assert.ok(tracer.getHttpTextFormat() instanceof HttpTraceContext); assert.ok(tracer.getHttpTextFormat() instanceof HttpTraceContext);
}); });
}); });

View File

@ -16,7 +16,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { MultiSpanProcessor } from '../src/MultiSpanProcessor'; import { MultiSpanProcessor } from '../src/MultiSpanProcessor';
import { SpanProcessor, Span, BasicTracer } from '../src'; import { SpanProcessor, Span, BasicTracerRegistry } from '../src';
class TestProcessor implements SpanProcessor { class TestProcessor implements SpanProcessor {
spans: Span[] = []; spans: Span[] = [];
@ -30,7 +30,7 @@ class TestProcessor implements SpanProcessor {
} }
describe('MultiSpanProcessor', () => { describe('MultiSpanProcessor', () => {
const tracer = new BasicTracer(); const tracer = new BasicTracerRegistry().getTracer('default');
const span = tracer.startSpan('one'); const span = tracer.startSpan('one');
it('should handle empty span processor', () => { it('should handle empty span processor', () => {

View File

@ -21,7 +21,7 @@ import {
TraceFlags, TraceFlags,
SpanContext, SpanContext,
} from '@opentelemetry/types'; } from '@opentelemetry/types';
import { BasicTracer, Span } from '../src'; import { BasicTracerRegistry, Span } from '../src';
import { import {
hrTime, hrTime,
hrTimeToNanoseconds, hrTimeToNanoseconds,
@ -33,9 +33,9 @@ import {
const performanceTimeOrigin = hrTime(); const performanceTimeOrigin = hrTime();
describe('Span', () => { describe('Span', () => {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
logger: new NoopLogger(), logger: new NoopLogger(),
}); }).getTracer('default');
const name = 'span1'; const name = 'span1';
const spanContext: SpanContext = { const spanContext: SpanContext = {
traceId: 'd4cda95b652f4a1592b449d5929fda1b', traceId: 'd4cda95b652f4a1592b449d5929fda1b',

View File

@ -18,26 +18,26 @@ import * as assert from 'assert';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { import {
Span, Span,
BasicTracer, BasicTracerRegistry,
InMemorySpanExporter, InMemorySpanExporter,
BatchSpanProcessor, BatchSpanProcessor,
} from '../../src'; } from '../../src';
import { NEVER_SAMPLER, ALWAYS_SAMPLER, NoopLogger } from '@opentelemetry/core'; import { NEVER_SAMPLER, ALWAYS_SAMPLER, NoopLogger } from '@opentelemetry/core';
function createSampledSpan(spanName: string): Span { function createSampledSpan(spanName: string): Span {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: ALWAYS_SAMPLER, sampler: ALWAYS_SAMPLER,
}); }).getTracer('default');
const span = tracer.startSpan(spanName); const span = tracer.startSpan(spanName);
span.end(); span.end();
return span as Span; return span as Span;
} }
function createUnSampledSpan(spanName: string): Span { function createUnSampledSpan(spanName: string): Span {
const tracer = new BasicTracer({ const tracer = new BasicTracerRegistry({
sampler: NEVER_SAMPLER, sampler: NEVER_SAMPLER,
logger: new NoopLogger(), logger: new NoopLogger(),
}); }).getTracer('default');
const span = tracer.startSpan(spanName, { isRecording: false }); const span = tracer.startSpan(spanName, { isRecording: false });
span.end(); span.end();
return span as Span; return span as Span;

View File

@ -17,7 +17,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { import {
BasicTracer, BasicTracerRegistry,
ConsoleSpanExporter, ConsoleSpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
} from '../../src'; } from '../../src';
@ -39,15 +39,17 @@ describe('ConsoleSpanExporter', () => {
describe('.export()', () => { describe('.export()', () => {
it('should export information about span', () => { it('should export information about span', () => {
assert.doesNotThrow(() => { assert.doesNotThrow(() => {
const basicTracer = new BasicTracer(); const basicTracerRegistry = new BasicTracerRegistry();
consoleExporter = new ConsoleSpanExporter(); consoleExporter = new ConsoleSpanExporter();
const spyConsole = sinon.spy(console, 'log'); const spyConsole = sinon.spy(console, 'log');
const spyExport = sinon.spy(consoleExporter, 'export'); 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.addEvent('foobar');
span.end(); span.end();

View File

@ -18,14 +18,14 @@ import * as assert from 'assert';
import { import {
InMemorySpanExporter, InMemorySpanExporter,
SimpleSpanProcessor, SimpleSpanProcessor,
BasicTracer, BasicTracerRegistry,
} from '../../src'; } from '../../src';
import { ExportResult } from '@opentelemetry/base'; import { ExportResult } from '@opentelemetry/base';
describe('InMemorySpanExporter', () => { describe('InMemorySpanExporter', () => {
const memoryExporter = new InMemorySpanExporter(); const memoryExporter = new InMemorySpanExporter();
const tracer = new BasicTracer(); const registry = new BasicTracerRegistry();
tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); registry.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
afterEach(() => { afterEach(() => {
// reset spans in memory. // reset spans in memory.
@ -33,9 +33,13 @@ describe('InMemorySpanExporter', () => {
}); });
it('should get finished spans', () => { it('should get finished spans', () => {
const root = tracer.startSpan('root'); const root = registry.getTracer('default').startSpan('root');
const child = tracer.startSpan('child', { parent: root }); const child = registry
const grandChild = tracer.startSpan('grand-child', { parent: child }); .getTracer('default')
.startSpan('child', { parent: root });
const grandChild = registry
.getTracer('default')
.startSpan('grand-child', { parent: child });
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);
grandChild.end(); grandChild.end();
@ -56,15 +60,21 @@ describe('InMemorySpanExporter', () => {
}); });
it('should shutdown the exorter', () => { it('should shutdown the exorter', () => {
const root = tracer.startSpan('root'); const root = registry.getTracer('default').startSpan('root');
tracer.startSpan('child', { parent: root }).end(); registry
.getTracer('default')
.startSpan('child', { parent: root })
.end();
root.end(); root.end();
assert.strictEqual(memoryExporter.getFinishedSpans().length, 2); assert.strictEqual(memoryExporter.getFinishedSpans().length, 2);
memoryExporter.shutdown(); memoryExporter.shutdown();
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);
// after shutdown no new spans are accepted // 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); assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);
}); });

Some files were not shown because too many files have changed in this diff Show More