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.

114 lines 5.85 kB
"use strict"; 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