@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.
114 lines • 5.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OTLPAwsSpanExporter = void 0;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto");
const api_1 = require("@opentelemetry/api");
const otlp_transformer_1 = require("@opentelemetry/otlp-transformer");
const utils_1 = require("./utils");
/**
* This exporter extends the functionality of the OTLPProtoTraceExporter to allow spans to be exported
* to the XRay OTLP endpoint https://xray.[AWSRegion].amazonaws.com/v1/traces. Utilizes the aws-sdk
* library to sign and directly inject SigV4 Authentication to the exported request's headers. <a
* href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-OTLPEndpoint.html">...</a>
*
* This only works with version >=16 Node.js environments.
*/
class OTLPAwsSpanExporter extends exporter_trace_otlp_proto_1.OTLPTraceExporter {
constructor(endpoint, config) {
super(OTLPAwsSpanExporter.changeUrlConfig(endpoint, config));
// If the required dependencies are installed then we enable SigV4 signing. Otherwise skip it
this.hasRequiredDependencies = false;
this.initDependencies();
this.region = endpoint.split('.')[1];
this.endpoint = endpoint;
}
/**
* Overrides the upstream implementation of export. All behaviors are the same except if the
* endpoint is an XRay OTLP endpoint, we will sign the request with SigV4 in headers before
* sending it to the endpoint. Otherwise, we will skip signing.
*/
async export(items, resultCallback) {
var _a, _b, _c;
// Only do SigV4 Signing if the required dependencies are installed. Otherwise default to the regular http/protobuf exporter.
if (this.hasRequiredDependencies) {
const url = new URL(this.endpoint);
const serializedSpans = otlp_transformer_1.ProtobufTraceSerializer.serializeRequest(items);
if (serializedSpans === undefined) {
return;
}
/*
This is bad practice but there is no other way to access and inject SigV4 headers
into the request headers before the traces get exported.
*/
const oldHeaders = (_c = (_b = (_a = this['_delegate']._transport) === null || _a === void 0 ? void 0 : _a._transport) === null || _b === void 0 ? void 0 : _b._parameters) === null || _c === void 0 ? void 0 : _c.headers();
if (oldHeaders) {
const request = new this.httpRequest({
method: 'POST',
protocol: 'https',
hostname: url.hostname,
path: url.pathname,
body: serializedSpans,
headers: Object.assign(Object.assign({}, this.removeSigV4Headers(oldHeaders)), { host: url.hostname }),
});
try {
const signer = new this.signatureV4({
credentials: this.defaultProvider(),
region: this.region,
service: OTLPAwsSpanExporter.SERVICE_NAME,
sha256: this.sha256,
});
const signedRequest = await signer.sign(request);
// See type: https://github.com/open-telemetry/opentelemetry-js/blob/experimental/v0.57.1/experimental/packages/otlp-exporter-base/src/transport/http-transport-types.ts#L31
const newHeaders = () => signedRequest.headers;
this['_delegate']._transport._transport._parameters.headers = newHeaders;
}
catch (exception) {
api_1.diag.debug(`Failed to sign/authenticate the given exported Span request to OTLP XRay endpoint with error: ${exception}`);
}
}
}
super.export(items, resultCallback);
}
// Removes Sigv4 headers from old headers to avoid accidentally copying them to the new headers
removeSigV4Headers(headers) {
const newHeaders = {};
const sigV4Headers = ['x-amz-date', 'authorization', 'x-amz-content-sha256', 'x-amz-security-token'];
for (const key in headers) {
if (!sigV4Headers.includes(key.toLowerCase())) {
newHeaders[key] = headers[key];
}
}
return newHeaders;
}
initDependencies() {
if ((0, utils_1.getNodeVersion)() < 16) {
api_1.diag.error('SigV4 signing requires atleast Node major version 16');
return;
}
try {
const awsSdkModule = require('@aws-sdk/credential-provider-node');
const awsCryptoModule = require('@aws-crypto/sha256-js');
const signatureModule = require('@smithy/signature-v4');
const httpModule = require('@smithy/protocol-http');
(this.defaultProvider = awsSdkModule.defaultProvider),
(this.sha256 = awsCryptoModule.Sha256),
(this.signatureV4 = signatureModule.SignatureV4),
(this.httpRequest = httpModule.HttpRequest);
this.hasRequiredDependencies = true;
}
catch (error) {
api_1.diag.error(`Failed to load required AWS dependency for SigV4 Signing: ${error}`);
}
}
static changeUrlConfig(endpoint, config) {
const newConfig = config == null
? { url: endpoint }
: Object.assign(Object.assign({}, config), { url: endpoint });
return newConfig;
}
}
exports.OTLPAwsSpanExporter = OTLPAwsSpanExporter;
OTLPAwsSpanExporter.SERVICE_NAME = 'xray';
//# sourceMappingURL=otlp-aws-span-exporter.js.map