feat(sdk-trace-base): add `spanProcessors` property in `TracerConfig` interface (#5138)

This commit is contained in:
David Luna 2024-11-12 16:48:00 +01:00 committed by GitHub
parent f1ef5960ae
commit db14633cc4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 540 additions and 738 deletions

View File

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

View File

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

View File

@ -6,18 +6,19 @@ const { SEMRESATTRS_SERVICE_NAME } = require('@opentelemetry/semantic-convention
const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const provider = new BasicTracerProvider({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'basic-service',
}),
});
// 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()));
const provider = new BasicTracerProvider({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: 'basic-service',
}),
spanProcessors: [
new SimpleSpanProcessor(exporter),
new SimpleSpanProcessor(new ConsoleSpanExporter()),
]
});
/**
* Initialize the OpenTelemetry APIs to use the BasicTracerProvider bindings.

View File

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

View File

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

View File

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

View File

@ -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(),

View File

@ -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(),

View File

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

View File

@ -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(),

View File

@ -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(),

View File

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

View File

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

View File

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

View File

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

View File

@ -33,9 +33,10 @@ const collectorOptions = {
url: 'http://<collector-hostname>:<port>',
};
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 => {

View File

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

View File

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

View File

@ -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(),

View File

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

View File

@ -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({

View File

@ -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({

View File

@ -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(),

View File

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

View File

@ -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,

View File

@ -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<DetectorSync> {
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<string, () => 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;
}

View File

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

View File

@ -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,18 +1194,44 @@ 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 () => {
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']!;
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('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.'
);
const listOfProcessors =
sdk['_tracerProvider']!['_registeredSpanProcessors']!;
const activeProcessor = sdk['_tracerProvider']?.getActiveSpanProcessor();
@ -1219,69 +1241,44 @@ describe('setup exporter from env', () => {
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('log warning that sdk will not be initialized when exporter is set to none', async () => {
env.OTEL_TRACES_EXPORTER = 'none';
const sdk = new NodeSDK();
sdk.start();
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);
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 () => {
env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none';
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);
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 () => {
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(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
assert(listOfProcessors[0]['_exporter'] instanceof OTLPProtoTraceExporter);
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();
});
});

View File

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

View File

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

View File

@ -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.

View File

@ -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.

View File

@ -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.
*/

View File

@ -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[];
}
/**

View File

@ -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({

View File

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

View File

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

View File

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