UNPKG

enhanced-adot-node-autoinstrumentation

Version:

This package provides Amazon Web Services distribution of the OpenTelemetry Node Instrumentation, which allows for auto-instrumentation of NodeJS applications.

117 lines 7.32 kB
"use strict"; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.AttributePropagatingSpanProcessor = void 0; const api_1 = require("@opentelemetry/api"); const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base"); const aws_attribute_keys_1 = require("./aws-attribute-keys"); const aws_span_processing_util_1 = require("./aws-span-processing-util"); const semantic_conventions_1 = require("@opentelemetry/semantic-conventions"); /** * AttributePropagatingSpanProcessor handles the propagation of attributes from parent spans to * child spans, specified in {@link attributesKeysToPropagate}. AttributePropagatingSpanProcessor * also propagates configurable data from parent spans to child spans, as a new attribute specified * by {@link propagationDataKey}. Propagated data can be configured via the {@link propagationDataExtractor}. * Span data propagation only starts from local root server/consumer spans, but from there will * be propagated to any descendant spans. If the span is a CONSUMER PROCESS with the parent also * a CONSUMER, it will set attribute AWS_CONSUMER_PARENT_SPAN_KIND as CONSUMER to indicate that * dependency metrics should not be generated for this span. */ class AttributePropagatingSpanProcessor { constructor(propagationDataExtractor, propagationDataKey, attributesKeysToPropagate) { this.propagationDataExtractor = propagationDataExtractor; this.propagationDataKey = propagationDataKey; this.attributesKeysToPropagate = attributesKeysToPropagate; } static create(propagationDataExtractor, propagationDataKey, attributesKeysToPropagate) { return new AttributePropagatingSpanProcessor(propagationDataExtractor, propagationDataKey, attributesKeysToPropagate); } onStart(span, parentContext) { // Divergence from Java/Python // Workaround implemented in TypeScript. Calculation of isLocalRoot is not possible // in `AwsSpanProcessingUtil.isLocalRoot` because the parent context is not accessible // from a span. Therefore we pre-calculate its value here as an attribute. aws_span_processing_util_1.AwsSpanProcessingUtil.setIsLocalRootInformation(span, parentContext); const parentSpan = api_1.trace.getSpan(parentContext); let parentReadableSpan = undefined; // In Python and Java, the check is "parentSpan is an instance of ReadableSpan" is not possible // in TypeScript because the check is not allowed for TypeScript interfaces (such as ReadableSpan). // This is because JavaScript doesn't support interfaces, which is what TypeScript will compile to. // `Span` is the only class that implements ReadableSpan, so check for instance of Span. if (parentSpan instanceof sdk_trace_base_1.Span) { parentReadableSpan = parentSpan; // Add the AWS_SDK_DESCENDANT attribute to the immediate child spans of AWS SDK span. // This attribute helps the backend differentiate between SDK spans and their immediate // children. // It's assumed that the HTTP spans are immediate children of the AWS SDK span // TODO: we should have a contract test to check the immediate children are HTTP span if (aws_span_processing_util_1.AwsSpanProcessingUtil.isAwsSDKSpan(parentReadableSpan)) { span.setAttribute(aws_attribute_keys_1.AWS_ATTRIBUTE_KEYS.AWS_SDK_DESCENDANT, 'true'); } if (api_1.SpanKind.INTERNAL === parentReadableSpan.kind) { for (const keyToPropagate of this.attributesKeysToPropagate) { const valueToPropagate = parentReadableSpan.attributes[keyToPropagate]; if (valueToPropagate !== undefined) { span.setAttribute(keyToPropagate, valueToPropagate); } } } // We cannot guarantee that messaging.operation is set onStart, it could be set after the fact. // To work around this, add the AWS_CONSUMER_PARENT_SPAN_KIND attribute if parent and child are // both CONSUMER then check later if a metric should be generated. if (this.isConsumerKind(span) && this.isConsumerKind(parentReadableSpan)) { span.setAttribute(aws_attribute_keys_1.AWS_ATTRIBUTE_KEYS.AWS_CONSUMER_PARENT_SPAN_KIND, api_1.SpanKind[parentReadableSpan.kind]); } // If parent span contains "cloud.resource_id" or "faas.id" but not in child span, child span will be // propagated with one of these attribute from parent. "cloud.resource_id" takes priority if it exists const parentResourceId = aws_span_processing_util_1.AwsSpanProcessingUtil.getResourceId(parentSpan); const resourceId = aws_span_processing_util_1.AwsSpanProcessingUtil.getResourceId(span); if (!resourceId && parentResourceId) { if (aws_span_processing_util_1.AwsSpanProcessingUtil.isKeyPresent(parentSpan, aws_span_processing_util_1.AwsSpanProcessingUtil.CLOUD_RESOURCE_ID)) { span.setAttribute(aws_span_processing_util_1.AwsSpanProcessingUtil.CLOUD_RESOURCE_ID, parentResourceId); } else { span.setAttribute(semantic_conventions_1.SEMRESATTRS_FAAS_ID, parentResourceId); } } } let propagationData = undefined; if (aws_span_processing_util_1.AwsSpanProcessingUtil.isLocalRoot(span)) { if (!this.isServerKind(span)) { propagationData = this.propagationDataExtractor(span); } } else if (parentReadableSpan !== undefined && this.isServerKind(parentReadableSpan)) { // In TypeScript, perform `parentReadableSpan !== undefined` check // This should be done in Python and Java as well, but is not as of now // If parentReadableSpan is not defined, the first `if statement` should occur, // so that is why it is not a problem for Java/Python... propagationData = this.propagationDataExtractor(parentReadableSpan); } else { // In TypeScript, perform `parentReadableSpan?` check (returns undefined if undefined) // This should be done in Python and Java as well, but is not as of now propagationData = parentReadableSpan === null || parentReadableSpan === void 0 ? void 0 : parentReadableSpan.attributes[this.propagationDataKey]; } if (propagationData !== undefined) { span.setAttribute(this.propagationDataKey, propagationData); } } isConsumerKind(span) { return api_1.SpanKind.CONSUMER === span.kind; } isServerKind(span) { return api_1.SpanKind.SERVER === span.kind; } // eslint-disable-next-line @typescript-eslint/no-unused-vars onEnd(span) { } shutdown() { return this.forceFlush(); } forceFlush() { return Promise.resolve(); } } exports.AttributePropagatingSpanProcessor = AttributePropagatingSpanProcessor; //# sourceMappingURL=attribute-propagating-span-processor.js.map