@aws/aws-distro-opentelemetry-node-autoinstrumentation
Version:
This package provides Amazon Web Services distribution of the OpenTelemetry Node Instrumentation, which allows for auto-instrumentation of NodeJS applications.
557 lines • 32.1 kB
JavaScript
;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Modifications Copyright The OpenTelemetry Authors. Licensed under the Apache License 2.0 License.
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isLambdaEnvironment = exports.buildSamplerFromEnv = exports.AwsSpanProcessorProvider = exports.ApplicationSignalsExporterProvider = exports.customBuildSamplerFromEnv = exports.AwsOpentelemetryConfigurator = exports.AWS_LAMBDA_FUNCTION_NAME_CONFIG = void 0;
const api_1 = require("@opentelemetry/api");
const auto_configuration_propagators_1 = require("@opentelemetry/auto-configuration-propagators");
const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
const core_1 = require("@opentelemetry/core");
const exporter_metrics_otlp_grpc_1 = require("@opentelemetry/exporter-metrics-otlp-grpc");
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
const exporter_trace_otlp_grpc_1 = require("@opentelemetry/exporter-trace-otlp-grpc");
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto");
const exporter_zipkin_1 = require("@opentelemetry/exporter-zipkin");
const id_generator_aws_xray_1 = require("@opentelemetry/id-generator-aws-xray");
const resource_detector_aws_1 = require("@opentelemetry/resource-detector-aws");
const resources_1 = require("@opentelemetry/resources");
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
const always_record_sampler_1 = require("./always-record-sampler");
const attribute_propagating_span_processor_builder_1 = require("./attribute-propagating-span-processor-builder");
const aws_batch_unsampled_span_processor_1 = require("./aws-batch-unsampled-span-processor");
const aws_metric_attributes_span_exporter_builder_1 = require("./aws-metric-attributes-span-exporter-builder");
const aws_span_metrics_processor_builder_1 = require("./aws-span-metrics-processor-builder");
const otlp_aws_span_exporter_1 = require("./otlp-aws-span-exporter");
const otlp_udp_exporter_1 = require("./otlp-udp-exporter");
const aws_xray_remote_sampler_1 = require("./sampler/aws-xray-remote-sampler");
// This file is generated via `npm run compile`
const version_1 = require("./version");
const XRAY_OTLP_ENDPOINT_PATTERN = '^https://xray\\.([a-z0-9-]+)\\.amazonaws\\.com/v1/traces$';
const APPLICATION_SIGNALS_ENABLED_CONFIG = 'OTEL_AWS_APPLICATION_SIGNALS_ENABLED';
const APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG = 'OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT';
const METRIC_EXPORT_INTERVAL_CONFIG = 'OTEL_METRIC_EXPORT_INTERVAL';
const DEFAULT_METRIC_EXPORT_INTERVAL_MILLIS = 60000;
exports.AWS_LAMBDA_FUNCTION_NAME_CONFIG = 'AWS_LAMBDA_FUNCTION_NAME';
const AWS_XRAY_DAEMON_ADDRESS_CONFIG = 'AWS_XRAY_DAEMON_ADDRESS';
const FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX = 'T1S';
const FORMAT_OTEL_UNSAMPLED_TRACES_BINARY_PREFIX = 'T1U';
// Follow Python SDK Impl to set the max span batch size
// which will reduce the chance of UDP package size is larger than 64KB
const LAMBDA_SPAN_EXPORT_BATCH_SIZE = 10;
/**
* Aws Application Signals Config Provider creates a configuration object that can be provided to
* the OTel NodeJS SDK for Auto Instrumentation with Application Signals Functionality.
*
* The config includes:
* - Use AlwaysRecordSampler (wraps around a specified Sampler) to record all spans.
* - Add SpanMetricsProcessor to create metrics.
* - Add AttributePropagatingSpanProcessor to propagate span attributes from parent to child spans.
* - Add AwsMetricAttributesSpanExporter to add more attributes to all spans.
*
* You can control when these customizations are applied using the environment variable
* OTEL_AWS_APPLICATION_SIGNALS_ENABLED. This flag is disabled by default.
*/
class AwsOpentelemetryConfigurator {
/**
* The constructor will setup the AwsOpentelemetryConfigurator object to be able to provide a
* configuration for ADOT JavaScript Auto-Instrumentation.
*
* The `instrumentations` are the desired Node auto-instrumentations to be used when using ADOT JavaScript.
* The auto-Instrumentions are usually populated from OTel's `getNodeAutoInstrumentations()` method from the
* `@opentelemetry/auto-instrumentations-node` NPM package, and may have instrumentation patching applied.
*
* @constructor
* @param {Instrumentation[]} instrumentations - Auto-Instrumentations to be added to the ADOT Config
*/
constructor(instrumentations, useXraySampler = false) {
/*
* Set and Detect Resources via Resource Detectors
*
* The configurator must create and detect resources in order to populate any detected
* resources into the Resource that is provided to the processors, exporters, and samplers
* that are instantiated in the configurator. Otherwise, if only OTel handles resource
* detection in the SDK, the AWS processors/exporters/samplers will lack such detected
* resources in their respective resources.
*/
let autoResource = new resources_1.Resource({});
autoResource = this.customizeVersions(autoResource);
// The following if/else block is based on upstream's logic
// https://github.com/open-telemetry/opentelemetry-js/blob/95edbd9992434f31f50532fedb3c7e8db5164479/experimental/packages/opentelemetry-sdk-node/src/sdk.ts#L125-L129
// In all cases, we want to include the Env Detector (Sync) and the AWS Resource Detectors
let defaultDetectors = [];
if (process.env.OTEL_NODE_RESOURCE_DETECTORS != null) {
defaultDetectors = (0, auto_instrumentations_node_1.getResourceDetectors)();
// Add Env/AWS Resource Detectors if not present
const resourceDetectorsFromEnv = process.env.OTEL_NODE_RESOURCE_DETECTORS.split(',');
if (!resourceDetectorsFromEnv.includes('aws')) {
defaultDetectors.push(resource_detector_aws_1.awsEc2DetectorSync, resource_detector_aws_1.awsEcsDetectorSync, resource_detector_aws_1.awsEksDetectorSync);
}
if (!resourceDetectorsFromEnv.includes('env')) {
defaultDetectors.push(resources_1.envDetectorSync);
}
}
else if (isLambdaEnvironment()) {
// If in Lambda environment, only keep env detector as default
defaultDetectors.push(resources_1.envDetectorSync);
}
else {
/*
* envDetectorSync is used as opposed to envDetector (async), so it is guaranteed that the
* resource is populated with configured OTEL_RESOURCE_ATTRIBUTES or OTEL_SERVICE_NAME env
* var values by the time that this class provides a configuration to the OTel SDK.
*
* envDetectorSync needs to be last so it can override any conflicting resource attributes.
*/
defaultDetectors = [
resources_1.processDetector,
resources_1.hostDetector,
resource_detector_aws_1.awsEc2DetectorSync,
resource_detector_aws_1.awsEcsDetectorSync,
resource_detector_aws_1.awsEksDetectorSync,
resources_1.envDetectorSync,
];
}
const internalConfig = {
detectors: defaultDetectors,
};
autoResource = autoResource.merge((0, resources_1.detectResourcesSync)(internalConfig));
this.resource = autoResource;
this.instrumentations = instrumentations;
this.propagator = (0, auto_configuration_propagators_1.getPropagator)();
// TODO: Consider removing AWSXRayIdGenerator as it is not needed
// Similarly to Java, always use AWS X-Ray Id Generator
// https://github.com/aws-observability/aws-otel-java-instrumentation/blob/a011b8cc29ee32b7f668c04ccfdf64cd30de467c/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsTracerCustomizerProvider.java#L36
this.idGenerator = new id_generator_aws_xray_1.AWSXRayIdGenerator();
this.sampler = AwsOpentelemetryConfigurator.customizeSampler(customBuildSamplerFromEnv(this.resource, useXraySampler));
// default SpanProcessors with Span Exporters wrapped inside AwsMetricAttributesSpanExporter
const awsSpanProcessorProvider = new AwsSpanProcessorProvider(this.resource);
this.spanProcessors = awsSpanProcessorProvider.getSpanProcessors();
AwsOpentelemetryConfigurator.customizeSpanProcessors(this.spanProcessors, this.resource);
}
customizeVersions(autoResource) {
// eslint-disable-next-line @typescript-eslint/typedef
const DISTRO_VERSION = version_1.LIB_VERSION;
autoResource.attributes[semantic_conventions_1.SEMRESATTRS_TELEMETRY_AUTO_VERSION] = DISTRO_VERSION + '-aws';
api_1.diag.debug(`@aws/aws-distro-opentelemetry-node-autoinstrumentation - version: ${autoResource.attributes[semantic_conventions_1.SEMRESATTRS_TELEMETRY_AUTO_VERSION]}`);
return autoResource;
}
configure() {
// config.autoDetectResources is set to False, as the resources are detected and added to the
// resource ahead of time. The resource is needed to be populated ahead of time instead of letting
// the OTel Node SDK do the population work because the constructed resource was required to build
// the sampler (if using XRay sampler) and the AwsMetricAttributesSpanExporter and AwsSpanMetricsProcessor
const config = {
instrumentations: this.instrumentations,
resource: this.resource,
idGenerator: this.idGenerator,
sampler: this.sampler,
// Error message 'Exporter "otlp" requested through environment variable is unavailable.'
// will appear from BasicTracerProvider that is used in the OTel JS SDK, even though the
// span processors are specified
// https://github.com/open-telemetry/opentelemetry-js/issues/3449
spanProcessors: this.spanProcessors,
autoDetectResources: false,
textMapPropagator: this.propagator,
};
return config;
}
static isApplicationSignalsEnabled() {
const isApplicationSignalsEnabled = process.env[APPLICATION_SIGNALS_ENABLED_CONFIG];
if (isApplicationSignalsEnabled === undefined) {
return false;
}
return isApplicationSignalsEnabled.toLowerCase() === 'true';
}
static customizeSpanProcessors(spanProcessors, resource) {
if (!AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()) {
return;
}
api_1.diag.info('AWS Application Signals enabled.');
let exportIntervalMillis = Number(process.env[METRIC_EXPORT_INTERVAL_CONFIG]);
api_1.diag.debug(`AWS Application Signals Metrics export interval: ${exportIntervalMillis}`);
if (isNaN(exportIntervalMillis) || exportIntervalMillis.valueOf() > DEFAULT_METRIC_EXPORT_INTERVAL_MILLIS) {
exportIntervalMillis = DEFAULT_METRIC_EXPORT_INTERVAL_MILLIS;
api_1.diag.info(`AWS Application Signals metrics export interval capped to ${exportIntervalMillis}`);
}
spanProcessors.push(attribute_propagating_span_processor_builder_1.AttributePropagatingSpanProcessorBuilder.create().build());
if (isXrayOtlpEndpoint(process.env['OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'])) {
return;
}
const applicationSignalsMetricExporter = ApplicationSignalsExporterProvider.Instance.createExporter();
const periodicExportingMetricReader = new sdk_metrics_1.PeriodicExportingMetricReader({
exporter: applicationSignalsMetricExporter,
exportIntervalMillis: exportIntervalMillis,
});
// Register BatchUnsampledSpanProcessor to export unsampled traces in Lambda
// when Application Signals enabled
if (isLambdaEnvironment() && !hasCustomOtlpTraceEndpoint()) {
const udpSpanExporter = new otlp_udp_exporter_1.OTLPUdpSpanExporter(getXrayDaemonEndpoint(), FORMAT_OTEL_UNSAMPLED_TRACES_BINARY_PREFIX);
const configuredExporter = aws_metric_attributes_span_exporter_builder_1.AwsMetricAttributesSpanExporterBuilder.create(udpSpanExporter, resource).build();
spanProcessors.push(new aws_batch_unsampled_span_processor_1.AwsBatchUnsampledSpanProcessor(configuredExporter, {
maxExportBatchSize: getSpanExportBatchSize(),
}));
api_1.diag.info('Enabled batch unsampled span processor for Lambda environment.');
}
// Disable Application Metrics for Lambda environment
if (!isLambdaEnvironment()) {
const meterProvider = new sdk_metrics_1.MeterProvider({
/** Resource associated with metric telemetry */
resource: resource,
readers: [periodicExportingMetricReader],
});
spanProcessors.push(aws_span_metrics_processor_builder_1.AwsSpanMetricsProcessorBuilder.create(meterProvider, resource, meterProvider.forceFlush.bind(meterProvider)).build());
}
}
static customizeSampler(sampler) {
if (AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()) {
return always_record_sampler_1.AlwaysRecordSampler.create(sampler);
}
return sampler;
}
}
exports.AwsOpentelemetryConfigurator = AwsOpentelemetryConfigurator;
function customBuildSamplerFromEnv(resource, useXraySampler = false) {
if (useXraySampler || process.env.OTEL_TRACES_SAMPLER === 'xray') {
const samplerArgumentEnv = process.env.OTEL_TRACES_SAMPLER_ARG;
let endpoint = undefined;
let pollingInterval = undefined;
if (samplerArgumentEnv !== undefined) {
const args = samplerArgumentEnv.split(',');
for (const arg of args) {
const equalIndex = arg.indexOf('=');
if (equalIndex === -1) {
continue;
}
const keyValue = [arg.substring(0, equalIndex), arg.substring(equalIndex + 1)];
if (keyValue[0] === 'endpoint') {
endpoint = keyValue[1];
}
else if (keyValue[0] === 'polling_interval') {
pollingInterval = Number(keyValue[1]);
if (isNaN(pollingInterval)) {
pollingInterval = undefined;
api_1.diag.error('polling_interval in OTEL_TRACES_SAMPLER_ARG must be a valid number');
}
}
}
}
api_1.diag.info('AWS XRay Sampler enabled');
api_1.diag.debug(`XRay Sampler Endpoint: ${endpoint}`);
api_1.diag.debug(`XRay Sampler Polling Interval: ${pollingInterval}`);
return new aws_xray_remote_sampler_1.AwsXRayRemoteSampler({ resource: resource, endpoint: endpoint, pollingInterval: pollingInterval });
}
return buildSamplerFromEnv();
}
exports.customBuildSamplerFromEnv = customBuildSamplerFromEnv;
class ApplicationSignalsExporterProvider {
constructor() {
this.aggregationSelector = (instrumentType) => {
switch (instrumentType) {
case sdk_metrics_1.InstrumentType.HISTOGRAM: {
return sdk_metrics_1.Aggregation.ExponentialHistogram();
}
}
return sdk_metrics_1.Aggregation.Default();
};
}
static get Instance() {
return this._instance || (this._instance = new this());
}
createExporter() {
let protocol = process.env['OTEL_EXPORTER_OTLP_METRICS_PROTOCOL'];
if (protocol === undefined) {
protocol = process.env['OTEL_EXPORTER_OTLP_PROTOCOL'];
}
if (protocol === undefined) {
protocol = 'grpc';
}
api_1.diag.debug(`AWS Application Signals export protocol: ${protocol}`);
const temporalityPreference = exporter_metrics_otlp_http_1.AggregationTemporalityPreference.DELTA;
const aggregationPreference = this.aggregationSelector;
if (protocol === 'http/protobuf') {
let applicationSignalsEndpoint = process.env[APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG];
if (applicationSignalsEndpoint === undefined) {
applicationSignalsEndpoint = 'http://localhost:4316/v1/metrics';
}
api_1.diag.debug(`AWS Application Signals export endpoint: ${applicationSignalsEndpoint}`);
return new exporter_metrics_otlp_http_1.OTLPMetricExporter({
url: applicationSignalsEndpoint,
temporalityPreference: temporalityPreference,
aggregationPreference: aggregationPreference,
});
}
if (protocol === 'grpc') {
let applicationSignalsEndpoint = process.env[APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG];
if (applicationSignalsEndpoint === undefined) {
applicationSignalsEndpoint = 'http://localhost:4315';
}
api_1.diag.debug(`AWS Application Signals export endpoint: ${applicationSignalsEndpoint}`);
return new exporter_metrics_otlp_grpc_1.OTLPMetricExporter({
url: applicationSignalsEndpoint,
temporalityPreference: temporalityPreference,
aggregationPreference: aggregationPreference,
});
}
throw new Error(`Unsupported AWS Application Signals export protocol: ${protocol}`);
}
}
exports.ApplicationSignalsExporterProvider = ApplicationSignalsExporterProvider;
// The OpenTelemetry Authors code
//
// ADOT JS needs the logic to (1) get the SpanExporters from Env and then (2) wrap the SpanExporters with AwsMetricAttributesSpanExporter
// However, the logic to perform (1) is only in the `TracerProviderWithEnvExporters` class, which is not exported publicly.
// `TracerProviderWithEnvExporters` is also responsible for (3) wrapping the SpanExporters inside the Simple/Batch SpanProcessors
// which must happen after (2). Thus in order to perform (1), (2), and (3), we need to add these non-exported methods here.
//
// https://github.com/open-telemetry/opentelemetry-js/blob/01cea7caeb130142cc017f77ea74834a35d0e8d6/experimental/packages/opentelemetry-sdk-node/src/TracerProviderWithEnvExporter.ts
//
// This class is a modified version of TracerProviderWithEnvExporters (extends NodeTracerProvider), without
// any of the TracerProvider functionalities. The AwsSpanProcessorProvider retains the functionality to
// only create the default span processors with exporters specified in `OTEL_TRACES_EXPORTER`. These span
// exporters are wrapped with AwsMetricAttributesSpanExporter when configuring the configureSpanProcessors
//
// Unlike `TracerProviderWithEnvExporters`, `AwsSpanProcessorProvider` does not extend `NodeTracerProvider`.
// The following class member variables are unmodified:
// - _configuredExporters
// - _spanProcessors
// The following class member variables are modified:
// - _hasSpanProcessors (removed)
// - resource (new)
// The following methods are unmodified:
// - configureOtlp(), getOtlpProtocol(), configureJaeger(), createExportersFromList(), _getSpanExporter(), filterBlanksAndNulls()
// The following methods are modified:
// - constructor() (modified)
// - removed usage of `this.addSpanProcessor(...)`, which calls `super.addSpanProcessor(...)`
// to register it to the BasicTracerProvider, which should be done later by the OTel JS SDK
// - configureSpanProcessors(exporters) (modified)
// - wrap exporters with customizeSpanExporter()
// - customizeSpanExporter() (new)
// - getSpanProcessors() (new)
// - override addSpanProcessor() (removed)
// - override register() (removed)
//
// TODO: `TracerProviderWithEnvExporters` is not exported, thus its useful static methods that
// provides some default SpanExporter configurations are unavailable. Ideally, we could contribute
// to upstream to export `TracerProviderWithEnvExporters`
class AwsSpanProcessorProvider {
constructor(resource) {
this._configuredExporters = [];
this._spanProcessors = [];
this.resource = resource;
// eslint-disable-next-line @typescript-eslint/typedef
let traceExportersList = this.filterBlanksAndNulls(Array.from(new Set((0, core_1.getEnv)().OTEL_TRACES_EXPORTER.split(','))));
if (traceExportersList[0] === 'none') {
api_1.diag.warn('OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.');
}
else if (traceExportersList.length === 0) {
api_1.diag.warn('OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.');
traceExportersList = ['otlp'];
this.createExportersFromList(traceExportersList);
this._spanProcessors = this.configureSpanProcessors(this._configuredExporters);
}
else {
if (traceExportersList.length > 1 && traceExportersList.includes('none')) {
api_1.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);
}
else {
api_1.diag.warn('Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.');
}
}
}
static configureOtlp() {
const otlp_exporter_traces_endpoint = process.env['OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'];
// eslint-disable-next-line @typescript-eslint/typedef
let protocol = this.getOtlpProtocol();
// If `isLambdaEnvironment` is true, we will default to exporting OTel spans via `udp_exporter` to Fluxpump,
// regardless of whether `AppSignals` is true or false.
// However, if the customer has explicitly set the `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`,
// we will continue using the `otlp_exporter` to send OTel traces to the specified endpoint.
if (!hasCustomOtlpTraceEndpoint() && isLambdaEnvironment()) {
protocol = 'udp';
}
switch (protocol) {
case 'grpc':
return new exporter_trace_otlp_grpc_1.OTLPTraceExporter();
case 'http/json':
return new exporter_trace_otlp_http_1.OTLPTraceExporter();
case 'http/protobuf':
if (otlp_exporter_traces_endpoint && isXrayOtlpEndpoint(otlp_exporter_traces_endpoint)) {
api_1.diag.debug('Detected XRay OTLP Traces endpoint. Switching exporter to OtlpAwsSpanExporter');
return new otlp_aws_span_exporter_1.OTLPAwsSpanExporter(otlp_exporter_traces_endpoint);
}
return new exporter_trace_otlp_proto_1.OTLPTraceExporter();
case 'udp':
api_1.diag.debug('Detected AWS Lambda environment and enabling UDPSpanExporter');
return new otlp_udp_exporter_1.OTLPUdpSpanExporter(getXrayDaemonEndpoint(), FORMAT_OTEL_SAMPLED_TRACES_BINARY_PREFIX);
default:
api_1.diag.warn(`Unsupported OTLP traces protocol: ${protocol}. Using http/protobuf.`);
if (otlp_exporter_traces_endpoint && isXrayOtlpEndpoint(otlp_exporter_traces_endpoint)) {
api_1.diag.debug('Detected XRay OTLP Traces endpoint. Switching exporter to OtlpAwsSpanExporter');
return new otlp_aws_span_exporter_1.OTLPAwsSpanExporter(otlp_exporter_traces_endpoint);
}
return new exporter_trace_otlp_proto_1.OTLPTraceExporter();
}
}
static getOtlpProtocol() {
var _b, _c, _d;
// eslint-disable-next-line @typescript-eslint/typedef
const parsedEnvValues = (0, core_1.getEnvWithoutDefaults)();
return ((_d = (_c = (_b = parsedEnvValues.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL) !== null && _b !== void 0 ? _b : parsedEnvValues.OTEL_EXPORTER_OTLP_PROTOCOL) !== null && _c !== void 0 ? _c : (0, core_1.getEnv)().OTEL_EXPORTER_OTLP_TRACES_PROTOCOL) !== null && _d !== void 0 ? _d : (0, core_1.getEnv)().OTEL_EXPORTER_OTLP_PROTOCOL);
}
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}`);
}
}
createExportersFromList(exporterList) {
exporterList.forEach(exporterName => {
// eslint-disable-next-line @typescript-eslint/typedef
const exporter = this._getSpanExporter(exporterName);
if (exporter) {
this._configuredExporters.push(exporter);
}
else {
api_1.diag.warn(`Unrecognized OTEL_TRACES_EXPORTER value: ${exporterName}.`);
}
});
}
_getSpanExporter(name) {
var _b;
return (_b = AwsSpanProcessorProvider._registeredExporters.get(name)) === null || _b === void 0 ? void 0 : _b();
}
configureSpanProcessors(exporters) {
return exporters.map(exporter => {
const configuredExporter = AwsSpanProcessorProvider.customizeSpanExporter(exporter, this.resource);
if (exporter instanceof sdk_trace_base_1.ConsoleSpanExporter) {
return new sdk_trace_base_1.SimpleSpanProcessor(configuredExporter);
}
else {
return new sdk_trace_base_1.BatchSpanProcessor(configuredExporter, {
maxExportBatchSize: getSpanExportBatchSize(),
});
}
});
}
filterBlanksAndNulls(list) {
return list.map(item => item.trim()).filter(s => s !== 'null' && s !== '');
}
static customizeSpanExporter(spanExporter, resource) {
if (AwsOpentelemetryConfigurator.isApplicationSignalsEnabled()) {
return aws_metric_attributes_span_exporter_builder_1.AwsMetricAttributesSpanExporterBuilder.create(spanExporter, resource).build();
}
return spanExporter;
}
getSpanProcessors() {
return this._spanProcessors;
}
}
exports.AwsSpanProcessorProvider = AwsSpanProcessorProvider;
_a = AwsSpanProcessorProvider;
AwsSpanProcessorProvider._registeredExporters = new Map([
['otlp', () => _a.configureOtlp()],
['zipkin', () => new exporter_zipkin_1.ZipkinExporter()],
['jaeger', () => _a.configureJaeger()],
['console', () => new sdk_trace_base_1.ConsoleSpanExporter()],
]);
// END The OpenTelemetry Authors code
// The OpenTelemetry Authors code
//
// We need the logic to build the Sampler from user-defined Environment variables in order
// to wrap the Sampler with an AlwaysRecord sampler. However, this logic is not exported
// in an `index.ts` file, so the portion of code that does this is added here.
//
// TODO: Ideally, upstream's `buildSamplerFromEnv()` method should be exported
// https://github.com/open-telemetry/opentelemetry-js/blob/f047db9da20a7d4394169f812b2d255d934883f1/packages/opentelemetry-sdk-trace-base/src/config.ts#L62
//
// An alternative method is to instantiate a new OTel JS Tracer with an empty config, which
// would also have the (private+readonly) sampler from the `buildSamplerFromEnv()` method.
// https://github.com/open-telemetry/opentelemetry-js/blob/01cea7caeb130142cc017f77ea74834a35d0e8d6/packages/opentelemetry-sdk-trace-base/src/Tracer.ts#L36-L53
const FALLBACK_OTEL_TRACES_SAMPLER = core_1.TracesSamplerValues.AlwaysOn;
const DEFAULT_RATIO = 1;
/**
* Based on environment, builds a sampler, complies with specification.
* @param environment optional, by default uses getEnv(), but allows passing a value to reuse parsed environment
*/
function buildSamplerFromEnv(environment = (0, core_1.getEnv)()) {
switch (environment.OTEL_TRACES_SAMPLER) {
case core_1.TracesSamplerValues.AlwaysOn:
return new sdk_trace_base_1.AlwaysOnSampler();
case core_1.TracesSamplerValues.AlwaysOff:
return new sdk_trace_base_1.AlwaysOffSampler();
case core_1.TracesSamplerValues.ParentBasedAlwaysOn:
return new sdk_trace_base_1.ParentBasedSampler({
root: new sdk_trace_base_1.AlwaysOnSampler(),
});
case core_1.TracesSamplerValues.ParentBasedAlwaysOff:
return new sdk_trace_base_1.ParentBasedSampler({
root: new sdk_trace_base_1.AlwaysOffSampler(),
});
case core_1.TracesSamplerValues.TraceIdRatio:
return new sdk_trace_base_1.TraceIdRatioBasedSampler(getSamplerProbabilityFromEnv(environment));
case core_1.TracesSamplerValues.ParentBasedTraceIdRatio:
return new sdk_trace_base_1.ParentBasedSampler({
root: new sdk_trace_base_1.TraceIdRatioBasedSampler(getSamplerProbabilityFromEnv(environment)),
});
default:
api_1.diag.error(`OTEL_TRACES_SAMPLER value "${environment.OTEL_TRACES_SAMPLER} invalid, defaulting to ${FALLBACK_OTEL_TRACES_SAMPLER}".`);
return new sdk_trace_base_1.AlwaysOnSampler();
}
}
exports.buildSamplerFromEnv = buildSamplerFromEnv;
function getSamplerProbabilityFromEnv(environment) {
if (environment.OTEL_TRACES_SAMPLER_ARG === undefined || environment.OTEL_TRACES_SAMPLER_ARG === '') {
api_1.diag.error(`OTEL_TRACES_SAMPLER_ARG is blank, defaulting to ${DEFAULT_RATIO}.`);
return DEFAULT_RATIO;
}
// eslint-disable-next-line @typescript-eslint/typedef
const probability = Number(environment.OTEL_TRACES_SAMPLER_ARG);
if (isNaN(probability)) {
api_1.diag.error(`OTEL_TRACES_SAMPLER_ARG=${environment.OTEL_TRACES_SAMPLER_ARG} was given, but it is invalid, defaulting to ${DEFAULT_RATIO}.`);
return DEFAULT_RATIO;
}
if (probability < 0 || probability > 1) {
api_1.diag.error(`OTEL_TRACES_SAMPLER_ARG=${environment.OTEL_TRACES_SAMPLER_ARG} was given, but it is out of range ([0..1]), defaulting to ${DEFAULT_RATIO}.`);
return DEFAULT_RATIO;
}
return probability;
}
function getSpanExportBatchSize() {
if (isLambdaEnvironment()) {
return LAMBDA_SPAN_EXPORT_BATCH_SIZE;
}
return undefined;
}
function isLambdaEnvironment() {
// detect if running in AWS Lambda environment
return process.env[exports.AWS_LAMBDA_FUNCTION_NAME_CONFIG] !== undefined;
}
exports.isLambdaEnvironment = isLambdaEnvironment;
function hasCustomOtlpTraceEndpoint() {
return process.env['OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'] !== undefined;
}
function getXrayDaemonEndpoint() {
return process.env[AWS_XRAY_DAEMON_ADDRESS_CONFIG];
}
function isXrayOtlpEndpoint(otlpEndpoint) {
return otlpEndpoint && new RegExp(XRAY_OTLP_ENDPOINT_PATTERN).test(otlpEndpoint.toLowerCase());
}
// END The OpenTelemetry Authors code
//# sourceMappingURL=aws-opentelemetry-configurator.js.map