UNPKG

@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
"use strict"; // 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