diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d96c9c80f7..6ced9993340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se * default: `true` (no change in behavior) * note: `false` will become the default behavior in the next major version in order to comply with [specification requirements](https://github.com/open-telemetry/opentelemetry-specification/blob/f3511a5ccda376dfd1de76dfa086fc9b35b54757/specification/resource/sdk.md?plain=1#L31-L36) +* feat(sdk-trace-base): add `spanProcessors` property in `TracerConfig` interface. [#5138](https://github.com/open-telemetry/opentelemetry-js/pull/5138) @david-luna + ### :bug: (Bug Fix) * fix(sdk-metrics): await exports in `PeriodicExportingMetricReader` when async resource attributes have not yet settled [#5119](https://github.com/open-telemetry/opentelemetry-js/pull/5119/) @pichlermarc diff --git a/api/README.md b/api/README.md index 59d4cd7a08d..40015dbf051 100644 --- a/api/README.md +++ b/api/README.md @@ -45,8 +45,9 @@ const { trace } = require("@opentelemetry/api"); const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require("@opentelemetry/sdk-trace-base"); // Create and register an SDK -const provider = new BasicTracerProvider(); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); trace.setGlobalTracerProvider(provider); // Acquire a tracer from the global tracer provider which will be used to trace the application diff --git a/examples/basic-tracer-node/index.js b/examples/basic-tracer-node/index.js index 889d4ba31e4..ff50b8e8b72 100644 --- a/examples/basic-tracer-node/index.js +++ b/examples/basic-tracer-node/index.js @@ -6,19 +6,20 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); +// Configure span processor to send spans to the exporter +const exporter = new JaegerExporter({ + endpoint: 'http://localhost:14268/api/traces', +}); const provider = new BasicTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'basic-service', }), + spanProcessors: [ + new SimpleSpanProcessor(exporter), + new SimpleSpanProcessor(new ConsoleSpanExporter()), + ] }); -// Configure span processor to send spans to the exporter -const exporter = new JaegerExporter({ - endpoint: 'http://localhost:14268/api/traces', -}); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); - /** * Initialize the OpenTelemetry APIs to use the BasicTracerProvider bindings. * diff --git a/examples/grpc-js/tracer.js b/examples/grpc-js/tracer.js index 77d30dbd1c2..8266f407d84 100644 --- a/examples/grpc-js/tracer.js +++ b/examples/grpc-js/tracer.js @@ -13,21 +13,15 @@ const { GrpcInstrumentation } = require('@opentelemetry/instrumentation-grpc'); const EXPORTER = process.env.EXPORTER || ''; module.exports = (serviceName) => { + const useZipkin = EXPORTER.toLowerCase().startsWith('z'); + const exporter = useZipkin ? new ZipkinExporter() : new JaegerExporter(); const provider = new NodeTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: serviceName, }), + spanProcessors: [new SimpleSpanProcessor(exporter)] }); - let exporter; - if (EXPORTER.toLowerCase().startsWith('z')) { - exporter = new ZipkinExporter(); - } else { - exporter = new JaegerExporter(); - } - - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings provider.register(); diff --git a/examples/http/tracer.js b/examples/http/tracer.js index b2351221bde..b96993446b6 100644 --- a/examples/http/tracer.js +++ b/examples/http/tracer.js @@ -13,21 +13,15 @@ const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); const EXPORTER = process.env.EXPORTER || ''; module.exports = (serviceName) => { + const useZipkin = EXPORTER.toLowerCase().startsWith('z'); + const exporter = useZipkin ? new ZipkinExporter() : new JaegerExporter(); const provider = new NodeTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: serviceName, }), + spanProcessors: [new SimpleSpanProcessor(exporter)] }); - - let exporter; - if (EXPORTER.toLowerCase().startsWith('z')) { - exporter = new ZipkinExporter(); - } else { - exporter = new JaegerExporter(); - } - - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - + // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings provider.register(); diff --git a/examples/https/tracer.js b/examples/https/tracer.js index 9d76f30355b..d59835da96f 100644 --- a/examples/https/tracer.js +++ b/examples/https/tracer.js @@ -14,21 +14,14 @@ const EXPORTER = process.env.EXPORTER || ''; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; module.exports = (serviceName) => { - let exporter; + const useZipkin = EXPORTER.toLowerCase().startsWith('z'); + const exporter = useZipkin ? new ZipkinExporter() : new JaegerExporter(); const provider = new NodeTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: serviceName, }), + spanProcessors: [new SimpleSpanProcessor(exporter)] }); - - if (EXPORTER.toLowerCase().startsWith('z')) { - exporter = new ZipkinExporter(); - } else { - exporter = new JaegerExporter(); - } - - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings provider.register(); diff --git a/examples/opentelemetry-web/examples/fetch-proto/index.js b/examples/opentelemetry-web/examples/fetch-proto/index.js index 0faaa0149aa..346ff12163f 100644 --- a/examples/opentelemetry-web/examples/fetch-proto/index.js +++ b/examples/opentelemetry-web/examples/fetch-proto/index.js @@ -12,17 +12,16 @@ const { SEMRESATTRS_SERVICE_NAME } = require("@opentelemetry/semantic-convention const provider = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'fetch-proto-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors: [ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new OTLPTraceExporterProto()), + ] }); -// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests -// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the -// exporter without delay -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.addSpanProcessor( - new SimpleSpanProcessor(new OTLPTraceExporterProto()) -); - provider.register({ contextManager: new ZoneContextManager(), propagator: new B3Propagator(), diff --git a/examples/opentelemetry-web/examples/fetch/index.js b/examples/opentelemetry-web/examples/fetch/index.js index 3326beb19b6..8e0ac16e03d 100644 --- a/examples/opentelemetry-web/examples/fetch/index.js +++ b/examples/opentelemetry-web/examples/fetch/index.js @@ -12,14 +12,16 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const provider = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'fetch-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors:[ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new OTLPTraceExporter()), + ] }); -// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests -// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the -// exporter without delay -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())); provider.register({ contextManager: new ZoneContextManager(), propagator: new B3Propagator(), diff --git a/examples/opentelemetry-web/examples/fetchXhr/index.js b/examples/opentelemetry-web/examples/fetchXhr/index.js index 1d93af4c49d..92e9b72eb3c 100644 --- a/examples/opentelemetry-web/examples/fetchXhr/index.js +++ b/examples/opentelemetry-web/examples/fetchXhr/index.js @@ -12,14 +12,16 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const provider = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'fetch-xhr-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors: [ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new OTLPTraceExporter()), + ] }); -// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests -// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the -// exporter without delay -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())); provider.register({ contextManager: new ZoneContextManager(), }); diff --git a/examples/opentelemetry-web/examples/fetchXhrB3/index.js b/examples/opentelemetry-web/examples/fetchXhrB3/index.js index 2923cccc6b7..368ae309f44 100644 --- a/examples/opentelemetry-web/examples/fetchXhrB3/index.js +++ b/examples/opentelemetry-web/examples/fetchXhrB3/index.js @@ -13,14 +13,16 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const provider = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'fetch-xhr-b3-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors: [ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new OTLPTraceExporter()), + ] }); -// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests -// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the -// exporter without delay -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())); provider.register({ contextManager: new ZoneContextManager(), propagator: new B3Propagator(), diff --git a/examples/opentelemetry-web/examples/xml-http-request/index.js b/examples/opentelemetry-web/examples/xml-http-request/index.js index 7530528ed87..908716f9a0a 100644 --- a/examples/opentelemetry-web/examples/xml-http-request/index.js +++ b/examples/opentelemetry-web/examples/xml-http-request/index.js @@ -12,15 +12,16 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const providerWithZone = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'xml-http-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors: [ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new OTLPTraceExporter()), + ] }); -// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests -// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the -// exporter without delay -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter())); - providerWithZone.register({ contextManager: new ZoneContextManager(), propagator: new B3Propagator(), diff --git a/examples/opentelemetry-web/examples/zipkin/index.js b/examples/opentelemetry-web/examples/zipkin/index.js index d76de7e563b..a6382a1bc77 100644 --- a/examples/opentelemetry-web/examples/zipkin/index.js +++ b/examples/opentelemetry-web/examples/zipkin/index.js @@ -7,19 +7,23 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention const provider = new WebTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'zipkin-web-service' - }) + }), + // Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests + // to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the + // exporter without delay + spanProcessors: [ + new SimpleSpanProcessor(new ConsoleSpanExporter()), + new SimpleSpanProcessor(new ZipkinExporter({ + // testing interceptor + // getExportRequestHeaders: () => { + // return { + // foo: 'bar', + // } + // } + })), + ] }); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); -provider.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({ - // testing interceptor - // getExportRequestHeaders: ()=> { - // return { - // foo: 'bar', - // } - // } -}))); - provider.register(); const tracer = provider.getTracer('example-tracer-web'); diff --git a/examples/opentracing-shim/shim.js b/examples/opentracing-shim/shim.js index 0f791071ee4..caea31c178c 100644 --- a/examples/opentracing-shim/shim.js +++ b/examples/opentracing-shim/shim.js @@ -11,9 +11,9 @@ const { TracerShim } = require('@opentelemetry/shim-opentracing'); function shim(serviceName) { const provider = new NodeTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: serviceName }), + spanProcessors: [new SimpleSpanProcessor(getExporter(serviceName))], }); - provider.addSpanProcessor(new SimpleSpanProcessor(getExporter(serviceName))); // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings provider.register(); diff --git a/examples/otlp-exporter-node/tracing.js b/examples/otlp-exporter-node/tracing.js index 475665f23cd..fb740fb2096 100644 --- a/examples/otlp-exporter-node/tracing.js +++ b/examples/otlp-exporter-node/tracing.js @@ -26,9 +26,11 @@ const provider = new BasicTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'basic-service', }), + spanProcessors: [ + new SimpleSpanProcessor(exporter), + new SimpleSpanProcessor(new ConsoleSpanExporter()), + ] }); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); const tracer = trace.getTracer('example-otlp-exporter-node'); diff --git a/experimental/examples/opencensus-shim/setup.js b/experimental/examples/opencensus-shim/setup.js index 1bb277eddb4..e3e189eae2d 100644 --- a/experimental/examples/opencensus-shim/setup.js +++ b/experimental/examples/opencensus-shim/setup.js @@ -48,12 +48,14 @@ module.exports = function setup(serviceName) { const resource = new Resource({ [SEMRESATTRS_SERVICE_NAME]: serviceName, }); - const tracerProvider = new NodeTracerProvider({ resource }); - tracerProvider.addSpanProcessor( - new BatchSpanProcessor(new OTLPTraceExporter(), { - scheduledDelayMillis: 5000, - }) - ); + const tracerProvider = new NodeTracerProvider({ + resource, + spanProcessors: [ + new BatchSpanProcessor(new OTLPTraceExporter(), { + scheduledDelayMillis: 5000, + }) + ] + }); tracerProvider.register(); const meterProvider = new MeterProvider({ resource }); diff --git a/experimental/packages/exporter-trace-otlp-grpc/README.md b/experimental/packages/exporter-trace-otlp-grpc/README.md index 09bb155c657..a18a7a787bf 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/README.md +++ b/experimental/packages/exporter-trace-otlp-grpc/README.md @@ -33,9 +33,10 @@ const collectorOptions = { url: 'http://:', }; -const provider = new BasicTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(exporter)] +}); provider.register(); ['SIGINT', 'SIGTERM'].forEach(signal => { @@ -59,9 +60,10 @@ const collectorOptions = { credentials: grpc.credentials.createSsl(), }; -const provider = new BasicTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(exporter)] +}); provider.register(); ['SIGINT', 'SIGTERM'].forEach(signal => { @@ -100,9 +102,10 @@ const collectorOptions = { metadata, // // an optional grpc.Metadata object to be sent with each request }; -const provider = new BasicTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(exporter)] +}); provider.register(); ['SIGINT', 'SIGTERM'].forEach(signal => { diff --git a/experimental/packages/exporter-trace-otlp-http/README.md b/experimental/packages/exporter-trace-otlp-http/README.md index 770c8dc22dc..427792eff5a 100644 --- a/experimental/packages/exporter-trace-otlp-http/README.md +++ b/experimental/packages/exporter-trace-otlp-http/README.md @@ -36,18 +36,21 @@ const collectorOptions = { concurrencyLimit: 10, // an optional limit on pending requests }; -const provider = new WebTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new BatchSpanProcessor(exporter, { - // The maximum queue size. After the size is reached spans are dropped. - maxQueueSize: 100, - // The maximum batch size of every export. It must be smaller or equal to maxQueueSize. - maxExportBatchSize: 10, - // The interval between two consecutive exports - scheduledDelayMillis: 500, - // How long the export can run before it is cancelled - exportTimeoutMillis: 30000, -})); +const provider = new WebTracerProvider({ + spanProcessors: [ + new BatchSpanProcessor(exporter, { + // The maximum queue size. After the size is reached spans are dropped. + maxQueueSize: 100, + // The maximum batch size of every export. It must be smaller or equal to maxQueueSize. + maxExportBatchSize: 10, + // The interval between two consecutive exports + scheduledDelayMillis: 500, + // How long the export can run before it is cancelled + exportTimeoutMillis: 30000, + }) + ] +}); provider.register(); @@ -67,14 +70,17 @@ const collectorOptions = { concurrencyLimit: 10, // an optional limit on pending requests }; -const provider = new BasicTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new BatchSpanProcessor(exporter, { - // The maximum queue size. After the size is reached spans are dropped. - maxQueueSize: 1000, - // The interval between two consecutive exports - scheduledDelayMillis: 30000, -})); +const provider = new BasicTracerProvider({ + spanProcessors: [ + new BatchSpanProcessor(exporter, { + // The maximum queue size. After the size is reached spans are dropped. + maxQueueSize: 1000, + // The interval between two consecutive exports + scheduledDelayMillis: 30000, + }) + ] +}); provider.register(); diff --git a/experimental/packages/exporter-trace-otlp-proto/README.md b/experimental/packages/exporter-trace-otlp-proto/README.md index 9b6141b873f..984fbaa4603 100644 --- a/experimental/packages/exporter-trace-otlp-proto/README.md +++ b/experimental/packages/exporter-trace-otlp-proto/README.md @@ -32,9 +32,10 @@ const collectorOptions = { }, //an optional object containing custom headers to be sent with each request will only work with http }; -const provider = new BasicTracerProvider(); const exporter = new OTLPTraceExporter(collectorOptions); -provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(exporter)] +}); provider.register(); diff --git a/experimental/packages/opentelemetry-browser-detector/README.md b/experimental/packages/opentelemetry-browser-detector/README.md index b1cbe45e574..bc0d0ad8a54 100644 --- a/experimental/packages/opentelemetry-browser-detector/README.md +++ b/experimental/packages/opentelemetry-browser-detector/README.md @@ -24,10 +24,18 @@ async function start(){ let detectedResources= await detectResources({detectors:[browserDetector]}); resource=resource.merge(detectedResources); const provider = new WebTracerProvider({ - resource + resource, + spanProcessors: [ + new BatchSpanProcessor( + new OTLPTraceExporter({ url:CONF.url, headers: {} }), + { + exportTimeoutMillis: CONF.timeOutMillis, + scheduledDelayMillis:CONF.delayMillis + } + ) + ] }); - provider.addSpanProcessor(new BatchSpanProcessor(new OTLPTraceExporter( {url:CONF.url ,headers:{}}),{exportTimeoutMillis:CONF.timeOutMillis,scheduledDelayMillis:CONF.delayMillis})); provider.register({ // Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional contextManager: new ZoneContextManager(), diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/README.md b/experimental/packages/opentelemetry-instrumentation-fetch/README.md index 2d3c2d4aeed..bf966ef1383 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/README.md +++ b/experimental/packages/opentelemetry-instrumentation-fetch/README.md @@ -26,9 +26,9 @@ import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const provider = new WebTracerProvider(); - -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const provider = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); provider.register({ contextManager: new ZoneContextManager(), @@ -40,15 +40,14 @@ registerInstrumentations({ // or plugin can be also initialised separately and then set the tracer provider or meter provider const fetchInstrumentation = new FetchInstrumentation(); -const provider = new WebTracerProvider(); +const provider = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); provider.register({ contextManager: new ZoneContextManager(), }); fetchInstrumentation.setTracerProvider(provider); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); - - // and some test fetch('http://localhost:8090/fetch.js'); diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/README.md b/experimental/packages/opentelemetry-instrumentation-grpc/README.md index e887ef2e429..6d209019b8d 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/README.md +++ b/experimental/packages/opentelemetry-instrumentation-grpc/README.md @@ -31,9 +31,10 @@ const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); const { GrpcInstrumentation } = require('@opentelemetry/instrumentation-grpc'); const { registerInstrumentations } = require('@opentelemetry/instrumentation'); -const provider = new NodeTracerProvider(); +const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); registerInstrumentations({ diff --git a/experimental/packages/opentelemetry-instrumentation-http/README.md b/experimental/packages/opentelemetry-instrumentation-http/README.md index a0c19c8e33c..8237f30d1bc 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/README.md +++ b/experimental/packages/opentelemetry-instrumentation-http/README.md @@ -35,9 +35,10 @@ const { } = require('@opentelemetry/sdk-trace-node'); const { registerInstrumentations } = require('@opentelemetry/instrumentation'); -const provider = new NodeTracerProvider(); +const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); provider.register(); registerInstrumentations({ diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/README.md b/experimental/packages/opentelemetry-instrumentation-xml-http-request/README.md index 8c706ffa61f..e3f0b136064 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/README.md +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/README.md @@ -25,8 +25,9 @@ import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xm import { ZoneContextManager } from '@opentelemetry/context-zone'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const providerWithZone = new WebTracerProvider(); -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const providerWithZone = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); providerWithZone.register({ contextManager: new ZoneContextManager(), diff --git a/experimental/packages/opentelemetry-sdk-node/src/TracerProviderWithEnvExporter.ts b/experimental/packages/opentelemetry-sdk-node/src/TracerProviderWithEnvExporter.ts deleted file mode 100644 index 4db49699391..00000000000 --- a/experimental/packages/opentelemetry-sdk-node/src/TracerProviderWithEnvExporter.ts +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { diag } from '@opentelemetry/api'; -import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core'; -import { - ConsoleSpanExporter, - SpanExporter, - BatchSpanProcessor, - SimpleSpanProcessor, - SDKRegistrationConfig, - SpanProcessor, -} from '@opentelemetry/sdk-trace-base'; -import { - NodeTracerConfig, - NodeTracerProvider, -} from '@opentelemetry/sdk-trace-node'; -import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; -import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; -import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; -import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; -import { filterBlanksAndNulls } from './utils'; - -export class TracerProviderWithEnvExporters extends NodeTracerProvider { - private _configuredExporters: SpanExporter[] = []; - private _spanProcessors: SpanProcessor[] | undefined; - private _hasSpanProcessors: boolean = false; - - static configureOtlp(): SpanExporter { - const protocol = this.getOtlpProtocol(); - - switch (protocol) { - case 'grpc': - return new OTLPGrpcTraceExporter(); - case 'http/json': - return new OTLPHttpTraceExporter(); - case 'http/protobuf': - return new OTLPProtoTraceExporter(); - default: - diag.warn( - `Unsupported OTLP traces protocol: ${protocol}. Using http/protobuf.` - ); - return new OTLPProtoTraceExporter(); - } - } - - static getOtlpProtocol(): string { - const parsedEnvValues = getEnvWithoutDefaults(); - - return ( - parsedEnvValues.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ?? - parsedEnvValues.OTEL_EXPORTER_OTLP_PROTOCOL ?? - getEnv().OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ?? - getEnv().OTEL_EXPORTER_OTLP_PROTOCOL - ); - } - - private static configureJaeger() { - // The JaegerExporter does not support being required in bundled - // environments. By delaying the require statement to here, we only crash when - // the exporter is actually used in such an environment. - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); - return new JaegerExporter(); - } catch (e) { - throw new Error( - `Could not instantiate JaegerExporter. This could be due to the JaegerExporter's lack of support for bundling. If possible, use @opentelemetry/exporter-trace-otlp-proto instead. Original Error: ${e}` - ); - } - } - - protected static override _registeredExporters = new Map< - string, - () => SpanExporter - >([ - ['otlp', () => this.configureOtlp()], - ['zipkin', () => new ZipkinExporter()], - ['jaeger', () => this.configureJaeger()], - ['console', () => new ConsoleSpanExporter()], - ]); - - public constructor(config: NodeTracerConfig = {}) { - super(config); - let traceExportersList = filterBlanksAndNulls( - Array.from(new Set(getEnv().OTEL_TRACES_EXPORTER.split(','))) - ); - - if (traceExportersList[0] === 'none') { - diag.warn( - 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' - ); - } else if (traceExportersList.length === 0) { - diag.warn('OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.'); - - traceExportersList = ['otlp']; - this.createExportersFromList(traceExportersList); - - this._spanProcessors = this.configureSpanProcessors( - this._configuredExporters - ); - this._spanProcessors.forEach(processor => { - this.addSpanProcessor(processor); - }); - } else { - if ( - traceExportersList.length > 1 && - traceExportersList.includes('none') - ) { - diag.warn( - 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' - ); - traceExportersList = ['otlp']; - } - - this.createExportersFromList(traceExportersList); - - if (this._configuredExporters.length > 0) { - this._spanProcessors = this.configureSpanProcessors( - this._configuredExporters - ); - this._spanProcessors.forEach(processor => { - this.addSpanProcessor(processor); - }); - } else { - diag.warn( - 'Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.' - ); - } - } - } - - override addSpanProcessor(spanProcessor: SpanProcessor) { - super.addSpanProcessor(spanProcessor); - this._hasSpanProcessors = true; - } - - override register(config?: SDKRegistrationConfig) { - if (this._hasSpanProcessors) { - super.register(config); - } - } - - private createExportersFromList(exporterList: string[]) { - exporterList.forEach(exporterName => { - const exporter = this._getSpanExporter(exporterName); - if (exporter) { - this._configuredExporters.push(exporter); - } else { - diag.warn(`Unrecognized OTEL_TRACES_EXPORTER value: ${exporterName}.`); - } - }); - } - - private configureSpanProcessors( - exporters: SpanExporter[] - ): (BatchSpanProcessor | SimpleSpanProcessor)[] { - return exporters.map(exporter => { - if (exporter instanceof ConsoleSpanExporter) { - return new SimpleSpanProcessor(exporter); - } else { - return new BatchSpanProcessor(exporter); - } - }); - } -} diff --git a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts index 266f4e4ab82..bd604c760a1 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts @@ -59,9 +59,12 @@ import { } from '@opentelemetry/sdk-trace-node'; import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { NodeSDKConfiguration } from './types'; -import { TracerProviderWithEnvExporters } from './TracerProviderWithEnvExporter'; import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core'; -import { getResourceDetectorsFromEnv, filterBlanksAndNulls } from './utils'; +import { + getResourceDetectorsFromEnv, + getSpanProcessorsFromEnv, + filterBlanksAndNulls, +} from './utils'; /** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */ @@ -100,7 +103,7 @@ export class NodeSDK { private _autoDetectResources: boolean; - private _tracerProvider?: NodeTracerProvider | TracerProviderWithEnvExporters; + private _tracerProvider?: NodeTracerProvider; private _loggerProvider?: LoggerProvider; private _meterProvider?: MeterProvider; private _serviceName?: string; @@ -248,34 +251,29 @@ export class NodeSDK { }) ); - // if there is a tracerProviderConfig (traceExporter/spanProcessor was set manually) or the traceExporter is set manually, use NodeTracerProvider - const Provider = this._tracerProviderConfig - ? NodeTracerProvider - : TracerProviderWithEnvExporters; + const spanProcessors = this._tracerProviderConfig + ? this._tracerProviderConfig.spanProcessors + : getSpanProcessorsFromEnv(); // If the Provider is configured with Env Exporters, we need to check if the SDK had any manual configurations and set them here - const tracerProvider = new Provider({ + this._tracerProvider = new NodeTracerProvider({ ...this._configuration, resource: this._resource, mergeResourceWithDefaults: this._mergeResourceWithDefaults, + spanProcessors, }); - this._tracerProvider = tracerProvider; - - if (this._tracerProviderConfig) { - for (const spanProcessor of this._tracerProviderConfig.spanProcessors) { - tracerProvider.addSpanProcessor(spanProcessor); - } + // Only register if there is a span processor + if (spanProcessors.length > 0) { + this._tracerProvider.register({ + contextManager: + this._tracerProviderConfig?.contextManager ?? + // _tracerProviderConfig may be undefined if trace-specific settings are not provided - fall back to raw config + this._configuration?.contextManager, + propagator: this._tracerProviderConfig?.textMapPropagator, + }); } - tracerProvider.register({ - contextManager: - this._tracerProviderConfig?.contextManager ?? - // _tracerProviderConfig may be undefined if trace-specific settings are not provided - fall back to raw config - this._configuration?.contextManager, - propagator: this._tracerProviderConfig?.textMapPropagator, - }); - if (this._loggerProviderConfig) { const loggerProvider = new LoggerProvider({ resource: this._resource, diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index 293a3e34858..1b654e64e6e 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -15,6 +15,11 @@ */ import { diag } from '@opentelemetry/api'; +import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core'; +import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; +import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; +import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; +import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; import { DetectorSync, envDetectorSync, @@ -23,6 +28,13 @@ import { processDetectorSync, serviceInstanceIdDetectorSync, } from '@opentelemetry/resources'; +import { + BatchSpanProcessor, + ConsoleSpanExporter, + SimpleSpanProcessor, + SpanExporter, + SpanProcessor, +} from '@opentelemetry/sdk-trace-base'; const RESOURCE_DETECTOR_ENVIRONMENT = 'env'; const RESOURCE_DETECTOR_HOST = 'host'; @@ -65,3 +77,106 @@ export function getResourceDetectorsFromEnv(): Array { export function filterBlanksAndNulls(list: string[]): string[] { return list.map(item => item.trim()).filter(s => s !== 'null' && s !== ''); } + +export function getOtlpProtocolFomEnv(): string { + const parsedEnvValues = getEnvWithoutDefaults(); + + return ( + parsedEnvValues.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ?? + parsedEnvValues.OTEL_EXPORTER_OTLP_PROTOCOL ?? + getEnv().OTEL_EXPORTER_OTLP_TRACES_PROTOCOL ?? + getEnv().OTEL_EXPORTER_OTLP_PROTOCOL + ); +} + +function getOtlpExporterFomEnv(): SpanExporter { + const protocol = getOtlpProtocolFomEnv(); + + switch (protocol) { + case 'grpc': + return new OTLPGrpcTraceExporter(); + case 'http/json': + return new OTLPHttpTraceExporter(); + case 'http/protobuf': + return new OTLPProtoTraceExporter(); + default: + diag.warn( + `Unsupported OTLP traces protocol: ${protocol}. Using http/protobuf.` + ); + return new OTLPProtoTraceExporter(); + } +} + +function getJaegerExporter() { + // The JaegerExporter does not support being required in bundled + // environments. By delaying the require statement to here, we only crash when + // the exporter is actually used in such an environment. + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); + return new JaegerExporter(); + } catch (e) { + throw new Error( + `Could not instantiate JaegerExporter. This could be due to the JaegerExporter's lack of support for bundling. If possible, use @opentelemetry/exporter-trace-otlp-proto instead. Original Error: ${e}` + ); + } +} + +export function getSpanProcessorsFromEnv(): SpanProcessor[] { + const exportersMap = new Map SpanExporter>([ + ['otlp', () => getOtlpExporterFomEnv()], + ['zipkin', () => new ZipkinExporter()], + ['console', () => new ConsoleSpanExporter()], + ['jaeger', () => getJaegerExporter()], + ]); + const exporters: SpanExporter[] = []; + const processors: SpanProcessor[] = []; + let traceExportersList = filterBlanksAndNulls( + Array.from(new Set(getEnv().OTEL_TRACES_EXPORTER.split(','))) + ); + + if (traceExportersList[0] === 'none') { + diag.warn( + 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' + ); + return []; + } + + if (traceExportersList.length === 0) { + diag.warn('OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.'); + traceExportersList = ['otlp']; + } else if ( + traceExportersList.length > 1 && + traceExportersList.includes('none') + ) { + diag.warn( + 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' + ); + traceExportersList = ['otlp']; + } + + for (const name of traceExportersList) { + const exporter = exportersMap.get(name)?.(); + if (exporter) { + exporters.push(exporter); + } else { + diag.warn(`Unrecognized OTEL_TRACES_EXPORTER value: ${name}.`); + } + } + + for (const exp of exporters) { + if (exp instanceof ConsoleSpanExporter) { + processors.push(new SimpleSpanProcessor(exp)); + } else { + processors.push(new BatchSpanProcessor(exp)); + } + } + + if (exporters.length === 0) { + diag.warn( + 'Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.' + ); + } + + return processors; +} diff --git a/experimental/packages/opentelemetry-sdk-node/test/TracerProviderWithEnvExporter.test.ts b/experimental/packages/opentelemetry-sdk-node/test/TracerProviderWithEnvExporter.test.ts deleted file mode 100644 index 21a1fa93d79..00000000000 --- a/experimental/packages/opentelemetry-sdk-node/test/TracerProviderWithEnvExporter.test.ts +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { diag } from '@opentelemetry/api'; -import { - ConsoleSpanExporter, - SimpleSpanProcessor, - BatchSpanProcessor, -} from '@opentelemetry/sdk-trace-base'; -import * as assert from 'assert'; -import * as Sinon from 'sinon'; -import { env } from 'process'; -import { - OTLPTraceExporter as OTLPProtoTraceExporter, - OTLPTraceExporter, -} from '@opentelemetry/exporter-trace-otlp-proto'; -import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; -import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; -import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; -import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; -import { TracerProviderWithEnvExporters } from '../src/TracerProviderWithEnvExporter'; - -describe('set up trace exporter with env exporters', () => { - let spyGetOtlpProtocol: Sinon.SinonSpy; - let stubLoggerError: Sinon.SinonStub; - - beforeEach(() => { - spyGetOtlpProtocol = Sinon.spy( - TracerProviderWithEnvExporters, - 'getOtlpProtocol' - ); - stubLoggerError = Sinon.stub(diag, 'warn'); - }); - afterEach(() => { - spyGetOtlpProtocol.restore(); - stubLoggerError.restore(); - }); - describe('setup otlp exporter from env', () => { - it('set up default exporter when user does not define otel trace exporter', async () => { - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('http/protobuf')); - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof OTLPProtoTraceExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - }); - it('use otlp exporter and grpc exporter protocol env value', async () => { - env.OTEL_TRACES_EXPORTER = 'otlp'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; - - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('grpc')); - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof OTLPGrpcTraceExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - it('sdk will ignore protocol defined with no-signal env and use signal specific protocol instead', async () => { - env.OTEL_TRACES_EXPORTER = 'otlp'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/protobuf'; - env.OTEL_EXPORTER_OTLP_PROTOCOL = 'grpc'; - - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('http/protobuf')); - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof OTLPTraceExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_PROTOCOL; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - it('use default otlp exporter when user does not set exporter via env or config', async () => { - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters[0] instanceof OTLPProtoTraceExporter); - assert(listOfExporters.length === 1); - - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - }); - it('use default otlp exporter when empty value is provided for exporter via env', async () => { - env.OTEL_TRACES_EXPORTER = ''; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters[0] instanceof OTLPProtoTraceExporter); - assert(listOfExporters.length === 1); - - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - - env.OTEL_TRACES_EXPORTER = ''; - }); - it('do not use any exporters when none value is only provided', async () => { - env.OTEL_TRACES_EXPORTER = 'none'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.notCalled); - assert(listOfExporters.length === 0); - assert(listOfProcessors === undefined); - delete env.OTEL_TRACES_EXPORTER; - }); - it('log warning that sdk will not be initialized when exporter is set to none', async () => { - env.OTEL_TRACES_EXPORTER = 'none'; - new TracerProviderWithEnvExporters(); - - assert.strictEqual( - stubLoggerError.args[0][0], - 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' - ); - delete env.OTEL_TRACES_EXPORTER; - }); - it('use default exporter when none value is provided with other exports', async () => { - env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters[0] instanceof OTLPProtoTraceExporter); - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof OTLPHttpTraceExporter === false); - assert(listOfExporters[0] instanceof ZipkinExporter === false); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - delete env.OTEL_TRACES_EXPORTER; - }); - it('log warning that default exporter will be used since exporter list contains none with other exports ', async () => { - env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none'; - new TracerProviderWithEnvExporters(); - - assert.strictEqual( - stubLoggerError.args[0][0], - 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' - ); - delete env.OTEL_TRACES_EXPORTER; - }); - it('should warn that exporter is unrecognized and not able to be set up', async () => { - env.OTEL_TRACES_EXPORTER = 'invalid'; - new TracerProviderWithEnvExporters(); - - assert.strictEqual( - stubLoggerError.args[0][0], - 'Unrecognized OTEL_TRACES_EXPORTER value: invalid.' - ); - - assert.strictEqual( - stubLoggerError.args[1][0], - 'Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.' - ); - - delete env.OTEL_TRACES_EXPORTER; - }); - it('should log warning when provided protocol name is not valid', async () => { - env.OTEL_EXPORTER_OTLP_PROTOCOL = 'invalid'; - new TracerProviderWithEnvExporters(); - - assert.strictEqual( - stubLoggerError.args[0][0], - 'OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.' - ); - - assert.strictEqual( - stubLoggerError.args[1][0], - 'Unsupported OTLP traces protocol: invalid. Using http/protobuf.' - ); - delete env.OTEL_EXPORTER_OTLP_PROTOCOL; - }); - }); - describe('setup zipkin exporter from env', () => { - it('use the zipkin exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'zipkin'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof ZipkinExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - delete env.OTEL_TRACES_EXPORTER; - }); - it('setup zipkin exporter and otlp exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'zipkin, otlp'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; - - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('grpc')); - assert(listOfExporters.length === 2); - assert(listOfExporters[0] instanceof ZipkinExporter); - assert(listOfExporters[1] instanceof OTLPGrpcTraceExporter); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - assert(listOfProcessors[1] instanceof BatchSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - }); - describe('setup jaeger exporter from env', () => { - it('use the jaeger exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'jaeger'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof JaegerExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - delete env.OTEL_TRACES_EXPORTER; - }); - it('setup jaeger exporter and otlp exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'jaeger, otlp'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'http/json'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('http/json')); - assert(listOfExporters.length === 2); - assert(listOfExporters[0] instanceof JaegerExporter); - assert(listOfExporters[1] instanceof OTLPHttpTraceExporter); - assert(listOfProcessors.length === 2); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); - assert(listOfProcessors[1] instanceof BatchSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - }); - describe('setup console exporter from env', () => { - it('use the console exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'console'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof ConsoleSpanExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof SimpleSpanProcessor); - delete env.OTEL_TRACES_EXPORTER; - }); - it('ignores the protocol', async () => { - env.OTEL_TRACES_EXPORTER = 'console'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.notCalled); - assert(listOfExporters.length === 1); - assert(listOfExporters[0] instanceof ConsoleSpanExporter); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof SimpleSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - it('setup console exporter and otlp exporter', async () => { - env.OTEL_TRACES_EXPORTER = 'console, otlp'; - env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; - const sdk = new TracerProviderWithEnvExporters(); - const listOfProcessors = sdk['_spanProcessors']!; - const listOfExporters = sdk['_configuredExporters']; - - assert(spyGetOtlpProtocol.returned('grpc')); - assert(listOfExporters.length === 2); - assert(listOfExporters[0] instanceof ConsoleSpanExporter); - assert(listOfExporters[1] instanceof OTLPGrpcTraceExporter); - assert(listOfProcessors.length === 2); - assert(listOfProcessors[0] instanceof SimpleSpanProcessor); - assert(listOfProcessors[1] instanceof BatchSpanProcessor); - - delete env.OTEL_TRACES_EXPORTER; - delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; - }); - }); -}); diff --git a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts index d24fe66b0b0..e5d248889a2 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -29,6 +29,7 @@ import { AsyncLocalStorageContextManager, } from '@opentelemetry/context-async-hooks'; import { CompositePropagator } from '@opentelemetry/core'; +import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; import { AggregationTemporality, ConsoleMetricExporter, @@ -56,7 +57,6 @@ import * as semver from 'semver'; import * as Sinon from 'sinon'; import { NodeSDK } from '../src'; import { env } from 'process'; -import { TracerProviderWithEnvExporters } from '../src/TracerProviderWithEnvExporter'; import { envDetector, envDetectorSync, @@ -77,10 +77,13 @@ import { import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; +import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; import { SEMRESATTRS_HOST_NAME, SEMRESATTRS_PROCESS_PID, } from '@opentelemetry/semantic-conventions'; +import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; const DefaultContextManager = semver.gte(process.version, '14.8.0') ? AsyncLocalStorageContextManager @@ -195,7 +198,7 @@ describe('Node SDK', () => { assert.ok( context['_getContextManager']().constructor.name === - DefaultContextManager.name + AsyncLocalStorageContextManager.name ); assert.ok( propagation['_getGlobalPropagator']() instanceof CompositePropagator @@ -218,7 +221,7 @@ describe('Node SDK', () => { assert.ok( context['_getContextManager']().constructor.name === - DefaultContextManager.name + AsyncLocalStorageContextManager.name ); assert.ok( propagation['_getGlobalPropagator']() instanceof CompositePropagator @@ -1095,32 +1098,28 @@ describe('Node SDK', () => { }); describe('setup exporter from env', () => { - let spyGetOtlpProtocol: Sinon.SinonSpy; let stubLoggerError: Sinon.SinonStub; beforeEach(() => { - spyGetOtlpProtocol = Sinon.spy( - TracerProviderWithEnvExporters, - 'getOtlpProtocol' - ); stubLoggerError = Sinon.stub(diag, 'warn'); }); afterEach(() => { - spyGetOtlpProtocol.restore(); stubLoggerError.restore(); }); - it('use default exporter TracerProviderWithEnvExporters when user does not provide span processor or trace exporter to sdk config', async () => { + + it('should use default exporter when nor env neither SDK config is given', async () => { const sdk = new NodeSDK(); sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPProtoTraceExporter); await sdk.shutdown(); }); - it('ignore env exporter when user provides exporter to sdk config', async () => { + + it('should ignore default env exporter when user provides exporter in sdk config', async () => { const traceExporter = new ConsoleSpanExporter(); const sdk = new NodeSDK({ traceExporter, @@ -1129,15 +1128,13 @@ describe('setup exporter from env', () => { const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert( - sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters === false - ); assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof SimpleSpanProcessor === false); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); await sdk.shutdown(); }); - it('ignores default env exporter when user provides span processor to sdk config', async () => { + + it('should ignore default env exporter when user provides span processor in sdk config', async () => { const traceExporter = new ConsoleSpanExporter(); const spanProcessor = new SimpleSpanProcessor(traceExporter); const sdk = new NodeSDK({ @@ -1147,15 +1144,13 @@ describe('setup exporter from env', () => { const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert( - sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters === false - ); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); - assert(listOfProcessors[0] instanceof BatchSpanProcessor === false); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); await sdk.shutdown(); }); - it('ignores env exporter when user provides tracer exporter to sdk config and sets exporter via env', async () => { + + it('should ignore exporter form env if another is provided in sdk config', async () => { env.OTEL_TRACES_EXPORTER = 'console'; const traceExporter = new OTLPTraceExporter(); const sdk = new NodeSDK({ @@ -1165,15 +1160,13 @@ describe('setup exporter from env', () => { const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert( - sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters === false - ); assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof SimpleSpanProcessor === false); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPTraceExporter); delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); + it('should only create one span processor when configured using env vars and config', async () => { env.OTEL_TRACES_EXPORTER = 'console'; const sdk = new NodeSDK({ @@ -1182,15 +1175,18 @@ describe('setup exporter from env', () => { sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert.ok(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); + assert.ok( sdk['_tracerProvider']!['_config']?.sampler instanceof AlwaysOffSampler ); assert.strictEqual(listOfProcessors.length, 1); + assert(listOfProcessors[0] instanceof SimpleSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); - it('use otlp exporter and defined exporter protocol env value', async () => { + + it('should use otlp exporter and defined exporter protocol env value', async () => { env.OTEL_TRACES_EXPORTER = 'otlp'; env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; const sdk = new NodeSDK(); @@ -1198,90 +1194,91 @@ describe('setup exporter from env', () => { const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); + assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPGrpcTraceExporter); delete env.OTEL_TRACES_EXPORTER; delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; await sdk.shutdown(); }); - it('use noop span processor when user sets env exporter to none', async () => { - env.OTEL_TRACES_EXPORTER = 'none'; + + it('sohuld use exporter and processor from env, signal specific env for protocol takes precedence', async () => { + env.OTEL_TRACES_EXPORTER = 'otlp'; + env.OTEL_EXPORTER_OTLP_PROTOCOL = 'http/protobuf'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; const sdk = new NodeSDK(); sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - const activeProcessor = sdk['_tracerProvider']?.getActiveSpanProcessor(); - assert(listOfProcessors.length === 0); - assert(activeProcessor instanceof NoopSpanProcessor); + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPGrpcTraceExporter); delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; await sdk.shutdown(); }); - it('log warning that sdk will not be initialized when exporter is set to none', async () => { + + it('should use noop span processor when user sets env exporter to none', async () => { env.OTEL_TRACES_EXPORTER = 'none'; const sdk = new NodeSDK(); sdk.start(); + // should warn assert.strictEqual( stubLoggerError.args[0][0], 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' ); - delete env.OTEL_TRACES_EXPORTER; - await sdk.shutdown(); - }); - it('use default otlp exporter when user does not set exporter via env or config', async () => { - const sdk = new NodeSDK(); - sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); - assert(listOfProcessors.length === 1); - assert(listOfProcessors[0] instanceof BatchSpanProcessor); + const activeProcessor = sdk['_tracerProvider']?.getActiveSpanProcessor(); + + assert(listOfProcessors.length === 0); + assert(activeProcessor instanceof NoopSpanProcessor); + delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); - it('use default otlp exporter when empty value is provided for exporter via env', async () => { + + it('should use default otlp exporter when empty value is provided for exporter via env', async () => { env.OTEL_TRACES_EXPORTER = ''; const sdk = new NodeSDK(); sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); + assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPProtoTraceExporter); env.OTEL_TRACES_EXPORTER = ''; await sdk.shutdown(); }); - it('use only default exporter when none value is provided with other exporters', async () => { + it('should use only default exporter when none value is provided with other exporters', async () => { env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none'; const sdk = new NodeSDK(); sdk.start(); + // also it should warn + assert.strictEqual( + stubLoggerError.args[0][0], + 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' + ); + const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); + assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPProtoTraceExporter); delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); - it('log warning that only default exporter will be used since exporter list contains none with other exports ', async () => { - env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none'; - const sdk = new NodeSDK(); - sdk.start(); - assert.strictEqual( - stubLoggerError.args[0][0], - 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' - ); - delete env.OTEL_TRACES_EXPORTER; - await sdk.shutdown(); - }); it('should warn that provided exporter value is unrecognized and not able to be set up', async () => { env.OTEL_TRACES_EXPORTER = 'invalid'; const sdk = new NodeSDK(); @@ -1300,7 +1297,84 @@ describe('setup exporter from env', () => { delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); - it('setup zipkin, jaeger and otlp exporters', async () => { + + it('should be able to setup zipkin exporter', async () => { + env.OTEL_TRACES_EXPORTER = 'zipkin'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ZipkinExporter); + + delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; + await sdk.shutdown(); + }); + + it('should be able to setup zipkin and otlp exporters', async () => { + env.OTEL_TRACES_EXPORTER = 'zipkin, otlp'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 2); + assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ZipkinExporter); + assert(listOfProcessors[1] instanceof BatchSpanProcessor); + assert(listOfProcessors[1]['_exporter'] instanceof OTLPGrpcTraceExporter); + + delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; + await sdk.shutdown(); + }); + + it('should be able to setup jaeger exporter', async () => { + env.OTEL_TRACES_EXPORTER = 'jaeger'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof JaegerExporter); + + delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; + await sdk.shutdown(); + }); + + it('should be able to setup jaeger and otlp exporters', async () => { + env.OTEL_TRACES_EXPORTER = 'otlp, jaeger'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 2); + assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof OTLPGrpcTraceExporter); + assert(listOfProcessors[1] instanceof BatchSpanProcessor); + assert(listOfProcessors[1]['_exporter'] instanceof JaegerExporter); + + delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; + await sdk.shutdown(); + }); + + it('should be able to setup zipkin, jaeger and otlp exporters', async () => { env.OTEL_TRACES_EXPORTER = 'zipkin, otlp, jaeger'; env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; const sdk = new NodeSDK(); @@ -1308,27 +1382,66 @@ describe('setup exporter from env', () => { const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; - assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters); + assert(listOfProcessors.length === 3); assert(listOfProcessors[0] instanceof BatchSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ZipkinExporter); assert(listOfProcessors[1] instanceof BatchSpanProcessor); + assert(listOfProcessors[1]['_exporter'] instanceof OTLPGrpcTraceExporter); assert(listOfProcessors[2] instanceof BatchSpanProcessor); + assert(listOfProcessors[2]['_exporter'] instanceof JaegerExporter); delete env.OTEL_TRACES_EXPORTER; delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; await sdk.shutdown(); }); - it('use the console exporter', async () => { + + it('should be able to use console and otlp exporters', async () => { env.OTEL_TRACES_EXPORTER = 'console, otlp'; const sdk = new NodeSDK(); sdk.start(); const listOfProcessors = sdk['_tracerProvider']!['_registeredSpanProcessors']!; + assert(listOfProcessors.length === 2); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); assert(listOfProcessors[1] instanceof BatchSpanProcessor); + assert(listOfProcessors[1]['_exporter'] instanceof OTLPProtoTraceExporter); delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); + + it('should be able to use console exporter but not http/json exporter', async () => { + env.OTEL_TRACES_EXPORTER = 'console, http/json'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof SimpleSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); + delete env.OTEL_TRACES_EXPORTER; + await sdk.shutdown(); + }); + + it('should ignore the protocol from env when use the console exporter', async () => { + env.OTEL_TRACES_EXPORTER = 'console'; + env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; + const sdk = new NodeSDK(); + sdk.start(); + + const listOfProcessors = + sdk['_tracerProvider']!['_registeredSpanProcessors']!; + + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof SimpleSpanProcessor); + assert(listOfProcessors[0]['_exporter'] instanceof ConsoleSpanExporter); + delete env.OTEL_TRACES_EXPORTER; + delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL; + await sdk.shutdown(); + }); }); diff --git a/packages/opentelemetry-context-zone-peer-dep/README.md b/packages/opentelemetry-context-zone-peer-dep/README.md index a505b9fbdda..da50eeb5fea 100644 --- a/packages/opentelemetry-context-zone-peer-dep/README.md +++ b/packages/opentelemetry-context-zone-peer-dep/README.md @@ -27,8 +27,9 @@ import { } from '@opentelemetry/sdk-trace-web'; import { ZoneContextManager } from '@opentelemetry/context-zone-peer-dep'; -const providerWithZone = new WebTracerProvider(); -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const providerWithZone = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); providerWithZone.register({ contextManager: new ZoneContextManager() }); diff --git a/packages/opentelemetry-context-zone/README.md b/packages/opentelemetry-context-zone/README.md index 0162f9645d1..7b6d094e59b 100644 --- a/packages/opentelemetry-context-zone/README.md +++ b/packages/opentelemetry-context-zone/README.md @@ -24,8 +24,9 @@ import { } from '@opentelemetry/sdk-trace-web'; import { ZoneContextManager } from '@opentelemetry/context-zone'; -const providerWithZone = new WebTracerProvider(); -providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const providerWithZone = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); providerWithZone.register({ contextManager: new ZoneContextManager() }); diff --git a/packages/opentelemetry-exporter-jaeger/README.md b/packages/opentelemetry-exporter-jaeger/README.md index 7e662a345e8..c686af7b29e 100644 --- a/packages/opentelemetry-exporter-jaeger/README.md +++ b/packages/opentelemetry-exporter-jaeger/README.md @@ -84,7 +84,11 @@ const exporter = new JaegerExporter(options); Now, register the exporter. ```js -tracer.addSpanProcessor(new BatchSpanProcessor(exporter)); +const tracerProvider = new NodeTracerProvider({ + spanProcessors: [new BatchSpanProcessor(exporter)] +}) + +const tracer = traceProvider.getTracer('my-tracer') ``` You can use built-in `SimpleSpanProcessor` or `BatchSpanProcessor` or write your own. diff --git a/packages/opentelemetry-exporter-zipkin/README.md b/packages/opentelemetry-exporter-zipkin/README.md index dc9d57ad75c..2d4244ac823 100644 --- a/packages/opentelemetry-exporter-zipkin/README.md +++ b/packages/opentelemetry-exporter-zipkin/README.md @@ -41,7 +41,11 @@ const exporter = new ZipkinExporter(options); Now, register the exporter and start tracing. ```js -tracer.addSpanProcessor(new BatchSpanProcessor(exporter)); +const tracerProvider = new NodeTracerProvider({ + spanProcessors: [new BatchSpanProcessor(exporter)] +}) + +const tracer = traceProvider.getTracer('my-tracer') ``` You can use built-in `SimpleSpanProcessor` or `BatchSpanProcessor` or write your own. diff --git a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts index 0b3174767a5..13cdb8e9b6c 100644 --- a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts @@ -89,12 +89,19 @@ export class BasicTracerProvider implements TracerProvider { resource: this.resource, }); - const defaultExporter = this._buildExporterFromEnv(); - if (defaultExporter !== undefined) { - const batchProcessor = new BatchSpanProcessor(defaultExporter); - this.activeSpanProcessor = batchProcessor; + if (config.spanProcessors?.length) { + this._registeredSpanProcessors = [...config.spanProcessors]; + this.activeSpanProcessor = new MultiSpanProcessor( + this._registeredSpanProcessors + ); } else { - this.activeSpanProcessor = new NoopSpanProcessor(); + const defaultExporter = this._buildExporterFromEnv(); + if (defaultExporter !== undefined) { + const batchProcessor = new BatchSpanProcessor(defaultExporter); + this.activeSpanProcessor = batchProcessor; + } else { + this.activeSpanProcessor = new NoopSpanProcessor(); + } } } @@ -120,6 +127,7 @@ export class BasicTracerProvider implements TracerProvider { } /** + * @deprecated please use {@link TracerConfig} spanProcessors property * Adds a new {@link SpanProcessor} to this tracer. * @param spanProcessor the new SpanProcessor to be added. */ diff --git a/packages/opentelemetry-sdk-trace-base/src/types.ts b/packages/opentelemetry-sdk-trace-base/src/types.ts index 64ae3b206bb..f351c0ce072 100644 --- a/packages/opentelemetry-sdk-trace-base/src/types.ts +++ b/packages/opentelemetry-sdk-trace-base/src/types.ts @@ -18,6 +18,7 @@ import { ContextManager, TextMapPropagator } from '@opentelemetry/api'; import { IResource } from '@opentelemetry/resources'; import { IdGenerator } from './IdGenerator'; import { Sampler } from './Sampler'; +import { SpanProcessor } from './SpanProcessor'; /** * TracerConfig provides an interface for configuring a Basic Tracer. @@ -54,6 +55,11 @@ export interface TracerConfig { * The default value is 30000ms */ forceFlushTimeoutMillis?: number; + + /** + * List of SpanProcessor for the tracer + */ + spanProcessors?: SpanProcessor[]; } /** diff --git a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts index 6108471232b..282331810dc 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts @@ -41,6 +41,8 @@ import { BatchSpanProcessor, AlwaysOnSampler, AlwaysOffSampler, + ConsoleSpanExporter, + SimpleSpanProcessor, } from '../../src'; class DummyPropagator implements TextMapPropagator { @@ -115,6 +117,24 @@ describe('BasicTracerProvider', () => { }); }); + describe('when user sets span processors', () => { + it('should use the span processors defined in the config', () => { + const traceExporter = new ConsoleSpanExporter(); + const spanProcessor = new SimpleSpanProcessor(traceExporter); + + const tracer = new BasicTracerProvider({ + spanProcessors: [spanProcessor], + }); + assert.ok( + tracer['_registeredSpanProcessors'][0] instanceof SimpleSpanProcessor + ); + assert.ok( + tracer['_registeredSpanProcessors'][0]['_exporter'] instanceof + ConsoleSpanExporter + ); + }); + }); + describe('when "sampler" option defined', () => { it('should have an instance with sampler', () => { const tracer = new BasicTracerProvider({ diff --git a/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/BatchSpanProcessor.js b/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/BatchSpanProcessor.js index ccdb82d481c..fc69043ee87 100644 --- a/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/BatchSpanProcessor.js +++ b/packages/opentelemetry-sdk-trace-base/test/performance/benchmark/BatchSpanProcessor.js @@ -47,8 +47,9 @@ function createSpan() { span.end(); } -const tracerProvider = new BasicTracerProvider(); -tracerProvider.addSpanProcessor(new BatchSpanProcessor(new NoopExporter())); +const tracerProvider = new BasicTracerProvider({ + spanProcessors: [new BatchSpanProcessor(new NoopExporter())] +}); const tracer = tracerProvider.getTracer('test') const suite = new Benchmark.Suite('BatchSpanProcessor'); diff --git a/packages/opentelemetry-sdk-trace-web/README.md b/packages/opentelemetry-sdk-trace-web/README.md index 44ed1ffbe0a..92d4e93e020 100644 --- a/packages/opentelemetry-sdk-trace-web/README.md +++ b/packages/opentelemetry-sdk-trace-web/README.md @@ -40,8 +40,9 @@ import { DocumentLoad } from '@opentelemetry/plugin-document-load'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; -const provider = new WebTracerProvider(); -provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +const provider = new WebTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] +}); provider.register({ // Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional diff --git a/selenium-tests/pages/tracing.js b/selenium-tests/pages/tracing.js index 6dd6e5f26f2..f88ce17618a 100644 --- a/selenium-tests/pages/tracing.js +++ b/selenium-tests/pages/tracing.js @@ -11,10 +11,13 @@ import { registerInstrumentations } from '@opentelemetry/instrumentation'; * @return {WebTracerProvider} */ export function loadOtel(instrumentations) { - const provider = new WebTracerProvider(); const memoryExporter = new InMemorySpanExporter(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); - provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); + const provider = new WebTracerProvider({ + spanProcessors: [ + new SimpleSpanProcessor(memoryExporter), + new SimpleSpanProcessor(new ConsoleSpanExporter()), + ] + }); provider.register({ contextManager: new ZoneContextManager(), });