@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.
105 lines • 5.59 kB
JavaScript
;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsMetricAttributesSpanExporter = void 0;
const aws_attribute_keys_1 = require("./aws-attribute-keys");
const aws_span_processing_util_1 = require("./aws-span-processing-util");
const metric_attribute_generator_1 = require("./metric-attribute-generator");
/**
* This exporter will update a span with metric attributes before exporting. It depends on a
* {@link SpanExporter} being provided on instantiation, which the AwsMetricAttributesSpanExporter will
* delegate export to. Also, a {@link MetricAttributeGenerator} must be provided, which will provide a
* means to determine attributes which should be applied to the span. Finally, a {@link Resource} must
* be provided, which is used to generate metric attributes.
*
* <p>This exporter should be coupled with the {@link AwsSpanMetricsProcessor} using the same
* {@link MetricAttributeGenerator}. This will result in metrics and spans being produced with
* common attributes.
*/
class AwsMetricAttributesSpanExporter {
/** Use {@link AwsMetricAttributesSpanExporterBuilder} to construct this exporter. */
static create(delegate, generator, resource) {
return new AwsMetricAttributesSpanExporter(delegate, generator, resource);
}
constructor(delegate, generator, resource) {
this.delegate = delegate;
this.generator = generator;
this.resource = resource;
}
export(spans, resultCallback) {
const modifiedSpans = this.addMetricAttributes(spans);
this.delegate.export(modifiedSpans, resultCallback);
}
shutdown() {
return this.delegate.shutdown();
}
forceFlush() {
if (this.delegate.forceFlush !== undefined) {
return this.delegate.forceFlush();
}
return Promise.resolve();
}
addMetricAttributes(spans) {
const modifiedSpans = [];
spans.forEach((span) => {
// If the map has no items, no modifications are required. If there is one item, it means the
// span either produces Service or Dependency metric attributes, and in either case we want to
// modify the span with them. If there are two items, the span produces both Service and
// Dependency metric attributes indicating the span is a local dependency root. The Service
// Attributes must be a subset of the Dependency, with the exception of AWS_SPAN_KIND. The
// knowledge that the span is a local root is more important that knowing that it is a
// Dependency metric, so we take all the Dependency metrics but replace AWS_SPAN_KIND with
// LOCAL_ROOT.
const attributeMap = this.generator.generateMetricAttributeMapFromSpan(span, this.resource);
let attributes = {};
const generatesServiceMetrics = aws_span_processing_util_1.AwsSpanProcessingUtil.shouldGenerateServiceMetricAttributes(span);
const generatesDependencyMetrics = aws_span_processing_util_1.AwsSpanProcessingUtil.shouldGenerateDependencyMetricAttributes(span);
if (generatesServiceMetrics && generatesDependencyMetrics) {
attributes = this.copyAttributesWithLocalRoot(attributeMap[metric_attribute_generator_1.DEPENDENCY_METRIC]);
}
else if (generatesServiceMetrics) {
attributes = attributeMap[metric_attribute_generator_1.SERVICE_METRIC];
}
else if (generatesDependencyMetrics) {
attributes = attributeMap[metric_attribute_generator_1.DEPENDENCY_METRIC];
}
if (attributes !== undefined && Object.keys(attributes).length > 0) {
span = AwsMetricAttributesSpanExporter.wrapSpanWithAttributes(span, attributes);
}
modifiedSpans.push(span);
});
return modifiedSpans;
}
copyAttributesWithLocalRoot(attributes) {
const updatedAttributes = Object.assign({}, attributes);
delete updatedAttributes[aws_attribute_keys_1.AWS_ATTRIBUTE_KEYS.AWS_SPAN_KIND];
updatedAttributes[aws_attribute_keys_1.AWS_ATTRIBUTE_KEYS.AWS_SPAN_KIND] = aws_span_processing_util_1.AwsSpanProcessingUtil.LOCAL_ROOT;
return updatedAttributes;
}
/**
* {@link export} works with a {@link ReadableSpan}, which does not permit modification. However, we
* need to add derived metric attributes to the span. However, we are still able to modify the
* attributes in the span (the attributes itself is readonly, so it cannot be outright replaced).
* This may be risky.
*
* <p>See https://github.com/open-telemetry/opentelemetry-specification/issues/1089 for more
* context on this approach.
*/
static wrapSpanWithAttributes(span, attributes) {
const originalAttributes = span.attributes;
const updateAttributes = {};
for (const key in originalAttributes) {
updateAttributes[key] = originalAttributes[key];
}
for (const key in attributes) {
updateAttributes[key] = attributes[key];
}
// Bypass `readonly` restriction of ReadableSpan's attributes.
const mutableSpan = span;
mutableSpan.attributes = updateAttributes;
return span;
}
}
exports.AwsMetricAttributesSpanExporter = AwsMetricAttributesSpanExporter;
//# sourceMappingURL=aws-metric-attributes-span-exporter.js.map