From 558b3f322b68d6963fb0c9b889f06c45cd2c0d1d Mon Sep 17 00:00:00 2001 From: William Armiros Date: Tue, 13 Apr 2021 14:37:39 -0500 Subject: [PATCH 1/8] Revert "Revert PR #386 (#412)" This reverts commit 9e20d2e880d706baa9ef8041ae70989f2f932c04. --- package-lock.json | 295 +++++++++++++----- package.json | 6 + packages/core/README.md | 42 +++ packages/core/lib/aws-xray.d.ts | 2 +- packages/core/lib/aws-xray.js | 9 +- packages/core/lib/patchers/aws3_p.d.ts | 8 + packages/core/lib/patchers/aws3_p.js | 113 +++++++ packages/core/lib/patchers/aws3_p.ts | 171 ++++++++++ .../lib/segments/attributes/subsegment.d.ts | 3 + packages/core/lib/segments/segment.d.ts | 1 + packages/core/package.json | 4 +- .../core/test/unit/patchers/aws3_p.test.js | 214 +++++++++++++ packages/core/tsconfig.json | 11 + packages/express/test-d/index.test-d.ts | 2 +- packages/express/tsconfig.json | 5 + packages/full_sdk/tsconfig.json | 5 + packages/mysql/tsconfig.json | 5 + packages/postgres/tsconfig.json | 5 + packages/restify/tsconfig.json | 5 + 19 files changed, 831 insertions(+), 75 deletions(-) create mode 100644 packages/core/lib/patchers/aws3_p.d.ts create mode 100644 packages/core/lib/patchers/aws3_p.js create mode 100644 packages/core/lib/patchers/aws3_p.ts create mode 100644 packages/core/test/unit/patchers/aws3_p.test.js create mode 100644 packages/core/tsconfig.json create mode 100644 packages/express/tsconfig.json create mode 100644 packages/full_sdk/tsconfig.json create mode 100644 packages/mysql/tsconfig.json create mode 100644 packages/postgres/tsconfig.json create mode 100644 packages/restify/tsconfig.json diff --git a/package-lock.json b/package-lock.json index f13d894a..3aac76a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,119 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@aws-sdk/config-resolver": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.8.0.tgz", + "integrity": "sha512-dtVB+yaT6gEqvzDt/pFS2suESTHb4qMiak3i34emSAcXilLYwOm3avUV/GApc499epQdxv/aRDAupanLVqTA1g==", + "dev": true, + "requires": { + "@aws-sdk/signature-v4": "3.6.1", + "@aws-sdk/types": "3.6.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/is-array-buffer": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.6.1.tgz", + "integrity": "sha512-qm2iDJmCrxlQE2dsFG+TujPe7jw4DF+4RTrsFMhk/e3lOl3MAzQ6Fc2kXtgeUcVrZVFTL8fQvXE1ByYyI6WbCw==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/middleware-stack": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.6.1.tgz", + "integrity": "sha512-EPsIxMi8LtCt7YwTFpWGlVGYJc0q4kwFbOssY02qfqdCnyqi2y5wo089dH7OdxUooQ0D7CPsXM1zTTuzvm+9Fw==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/node-config-provider": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.8.0.tgz", + "integrity": "sha512-VBpFquxACQO9MbdOIz35JgwOH+oJ5JwXpEq2faIhK+0zyM0JqLfJNFnnmHaEH9kBVcdOYJihzDgFje3AnYn7PQ==", + "dev": true, + "requires": { + "@aws-sdk/property-provider": "3.8.0", + "@aws-sdk/shared-ini-file-loader": "3.8.0", + "@aws-sdk/types": "3.6.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/property-provider": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.8.0.tgz", + "integrity": "sha512-9tOvTp6ObNdBgkqxXu5bpEdyzVnStO+aUprTbCH0lUfgCeig4q21xOt6Xsqt616WGtDJCAbMcdCay0XiDLLjAw==", + "dev": true, + "requires": { + "@aws-sdk/types": "3.6.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/service-error-classification": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.6.1.tgz", + "integrity": "sha512-kZ7ZhbrN1f+vrSRkTJvXsu7BlOyZgym058nPA745+1RZ1Rtv4Ax8oknf2RvJyj/1qRUi8LBaAREjzQ3C8tmLBA==" + }, + "@aws-sdk/shared-ini-file-loader": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.8.0.tgz", + "integrity": "sha512-wjywtEcsYPwB+asK5iWGeox9ZI4ycaxIGRKJTahFo+VUK6mByIEEG/IF7HuQclSSeDFTt9Occ7hQpXpJ97zpdA==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/signature-v4": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.6.1.tgz", + "integrity": "sha512-EAR0qGVL4AgzodZv4t+BSuBfyOXhTNxDxom50IFI1MqidR9vI6avNZKcPHhgXbm7XVcsDGThZKbzQ2q7MZ2NTA==", + "dev": true, + "requires": { + "@aws-sdk/is-array-buffer": "3.6.1", + "@aws-sdk/types": "3.6.1", + "@aws-sdk/util-hex-encoding": "3.6.1", + "@aws-sdk/util-uri-escape": "3.6.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/smithy-client": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.6.1.tgz", + "integrity": "sha512-AVpRK4/iUxNeDdAm8UqP0ZgtgJMQeWcagTylijwelhWXyXzHUReY1sgILsWcdWnoy6gq845W7K2VBhBleni8+w==", + "dev": true, + "requires": { + "@aws-sdk/middleware-stack": "3.6.1", + "@aws-sdk/types": "3.6.1", + "tslib": "^1.8.0" + } + }, + "@aws-sdk/types": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.6.1.tgz", + "integrity": "sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==", + "dev": true + }, + "@aws-sdk/util-hex-encoding": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.6.1.tgz", + "integrity": "sha512-pzsGOHtU2eGca4NJgFg94lLaeXDOg8pcS9sVt4f9LmtUGbrqRveeyBv0XlkHeZW2n0IZBssPHipVYQFlk7iaRA==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + } + }, + "@aws-sdk/util-uri-escape": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.6.1.tgz", + "integrity": "sha512-tgABiT71r0ScRJZ1pMX0xO0QPMMiISCtumph50IU5VDyZWYgeIxqkMhIcrL1lX0QbNCMgX0n6rZxGrrbjDNavA==", + "dev": true, + "requires": { + "tslib": "^1.8.0" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -14,30 +127,31 @@ } }, "@babel/compat-data": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", - "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.8.tgz", + "integrity": "sha512-EaI33z19T4qN3xLXsGf48M2cDqa6ei9tPZlfLdb2HC+e/cFtREiRd8hdSqDbwdLB0/+gLwqJmCYASH0z2bUdog==", "dev": true }, "@babel/core": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz", - "integrity": "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.8.tgz", + "integrity": "sha512-oYapIySGw1zGhEFRd6lzWNLWFX2s5dA/jm+Pw/+59ZdXtjyIuwlXbrId22Md0rgZVop+aVoqow2riXhBLNyuQg==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.13", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.15", + "@babel/generator": "^7.13.0", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helpers": "^7.13.0", + "@babel/parser": "^7.13.4", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.15", - "@babel/types": "^7.13.14", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", + "lodash": "^4.17.19", "semver": "^6.3.0", "source-map": "^0.5.0" }, @@ -52,9 +166,9 @@ } }, "@babel/parser": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", - "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", + "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", "dev": true }, "json5": { @@ -86,12 +200,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz", - "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", + "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.12", + "@babel/compat-data": "^7.13.8", "@babel/helper-validator-option": "^7.12.17", "browserslist": "^4.14.5", "semver": "^6.3.0" @@ -126,37 +240,38 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz", + "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.13.0" } }, "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", + "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.12.13" } }, "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz", + "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0", + "lodash": "^4.17.19" } }, "@babel/helper-optimise-call-expression": { @@ -169,24 +284,24 @@ } }, "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz", + "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-member-expression-to-functions": "^7.13.0", "@babel/helper-optimise-call-expression": "^7.12.13", "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" + "@babel/types": "^7.13.0" } }, "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", + "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.12.13" } }, "@babel/helper-split-export-declaration": { @@ -211,9 +326,9 @@ "dev": true }, "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", + "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", "dev": true, "requires": { "@babel/template": "^7.12.13", @@ -274,19 +389,20 @@ } }, "@babel/traverse": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz", - "integrity": "sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz", + "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", + "@babel/generator": "^7.13.0", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.15", - "@babel/types": "^7.13.14", + "@babel/parser": "^7.13.0", + "@babel/types": "^7.13.0", "debug": "^4.1.0", - "globals": "^11.1.0" + "globals": "^11.1.0", + "lodash": "^4.17.19" }, "dependencies": { "@babel/code-frame": { @@ -299,9 +415,9 @@ } }, "@babel/parser": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", - "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", + "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==", "dev": true }, "globals": { @@ -313,9 +429,9 @@ } }, "@babel/types": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", - "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz", + "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3128,6 +3244,7 @@ "aws-xray-sdk-core": { "version": "file:packages/core", "requires": { + "@aws-sdk/service-error-classification": "^3.4.1", "@types/cls-hooked": "^4.2.2", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", @@ -3760,9 +3877,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001208", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz", - "integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==", + "version": "1.0.30001197", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001197.tgz", + "integrity": "sha512-8aE+sqBqtXz4G8g35Eg/XEaFr2N7rd/VQ6eABGBmNtcB8cN6qNJhMi6oSFy4UWWZgqgL3filHT8Nha4meu3tsw==", "dev": true }, "caseless": { @@ -4957,9 +5074,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.712", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.712.tgz", - "integrity": "sha512-3kRVibBeCM4vsgoHHGKHmPocLqtFAGTrebXxxtgKs87hNUzXrX2NuS3jnBys7IozCnw7viQlozxKkmty2KNfrw==", + "version": "1.3.683", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.683.tgz", + "integrity": "sha512-8mFfiAesXdEdE0DhkMKO7W9U6VU/9T3VTWwZ+4g84/YMP4kgwgFtQgUxuu7FUMcvSeKSNhFQNU+WZ68BQTLT5A==", "dev": true }, "emitter-listener": { @@ -7029,6 +7146,14 @@ "requires": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + } } }, "he": { @@ -12606,10 +12731,24 @@ }, "dependencies": { "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } }, "https-proxy-agent": { "version": "4.0.0", @@ -12619,6 +12758,14 @@ "requires": { "agent-base": "5", "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + } } } } @@ -13181,6 +13328,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "dev": true + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", diff --git a/package.json b/package.json index 5dfbc1f0..c7858f32 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,11 @@ "private": true, "license": "Apache-2.0", "devDependencies": { + "@aws-sdk/config-resolver": "^3.3.0", + "@aws-sdk/middleware-stack": "^3.3.0", + "@aws-sdk/node-config-provider": "^3.3.0", + "@aws-sdk/smithy-client": "^3.3.0", + "@aws-sdk/types": "^3.3.0", "@hapi/hapi": "^20.0.0", "@types/chai": "^4.2.12", "@types/koa": "^2.11.3", @@ -41,6 +46,7 @@ "sinon": "^9.0.2", "sinon-chai": "^3.5.0", "tsd": "^0.13.1", + "typescript": "^4.1.3", "upath": "^1.2.0" }, "engines": { diff --git a/packages/core/README.md b/packages/core/README.md index e9091b24..db07bfc9 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -465,6 +465,8 @@ function sendRequest(host, cb) { ### Capture all outgoing AWS requests +This is only available for AWS SDK v2 due to the service-oriented architecture of AWS SDK v3. + ```js var AWS = captureAWS(require('aws-sdk')); @@ -473,6 +475,23 @@ var AWS = captureAWS(require('aws-sdk')); ### Capture outgoing AWS requests on a single client + +AWS SDK v3 + +```js +import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; + +const s3 = AWSXRay.captureAWSv3Client(new S3({})); + +await s3.send(new PutObjectCommand({ + Bucket: bucketName, + Key: keyName, + Body: 'Hello!', +})); +``` + +AWS SDK v2 + ```js var s3 = AWSXRay.captureAWSClient(new AWS.S3()); @@ -623,6 +642,27 @@ function sendRequest(host, cb, subsegment) { ### Capture outgoing AWS requests on a single client +AWS SDK v3 + +You must re-capture the client every time the subsegment is attached +to a new parent. + +```js +import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; + +// subsegment is an optional parameter that is required for manual mode +// and can be omitted in automatic mode (e.g. inside a Lambda function). +const s3 = AWSXRay.captureAWSv3Client(new S3({}), subsegment); + +await s3.send(new PutObjectCommand({ + Bucket: bucketName, + Key: keyName, + Body: 'Hello!', +})); +``` + +AWS SDK v2 + ```js var s3 = AWSXRay.captureAWSClient(new AWS.S3()); var params = { @@ -639,6 +679,8 @@ s3.putObject(params, function(err, data) { ### Capture all outgoing AWS requests +This is only available for AWS SDK v2 due to the service-oriented architecture of AWS SDK v3. + ```js var AWS = captureAWS(require('aws-sdk')); diff --git a/packages/core/lib/aws-xray.d.ts b/packages/core/lib/aws-xray.d.ts index 5347366f..c517d94d 100644 --- a/packages/core/lib/aws-xray.d.ts +++ b/packages/core/lib/aws-xray.d.ts @@ -39,7 +39,7 @@ export { captureAsyncFunc, captureCallbackFunc, captureFunc } from './capture' export { captureAWS, captureAWSClient } from './patchers/aws_p'; -export function captureAWSv3Client(client: T, manualSeg?: SegmentLike): T; +export type { captureAWSClient as captureAWSv3Client } from './patchers/aws3_p'; export { captureHTTPs, captureHTTPsGlobal } from './patchers/http_p'; diff --git a/packages/core/lib/aws-xray.js b/packages/core/lib/aws-xray.js index 7f39e38a..b81364a5 100644 --- a/packages/core/lib/aws-xray.js +++ b/packages/core/lib/aws-xray.js @@ -180,8 +180,15 @@ var AWSXRay = { captureAWSClient: require('./patchers/aws_p').captureAWSClient, + /** + * @param {AWSv3.Service} service - An instance of a AWS SDK v3 service to wrap. + * @param {Segment|Subsegment} segment - Optional segment for manual mode. + * @memberof AWSXRay + * @function + * @see module:aws3_p.captureAWSClient + */ - captureAWSv3Client: (client) => client, + captureAWSv3Client: require('./patchers/aws3_p').captureAWSClient, /** * @param {http|https} module - The built in Node.js HTTP or HTTPS module. diff --git a/packages/core/lib/patchers/aws3_p.d.ts b/packages/core/lib/patchers/aws3_p.d.ts new file mode 100644 index 00000000..68d186af --- /dev/null +++ b/packages/core/lib/patchers/aws3_p.d.ts @@ -0,0 +1,8 @@ +import type { MetadataBearer, Client } from '@aws-sdk/types'; +import type { RegionInputConfig } from '@aws-sdk/config-resolver'; +import { SegmentLike } from '../aws-xray'; +declare type DefaultConfiguration = RegionInputConfig & { + serviceId: string; +}; +export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; +export {}; diff --git a/packages/core/lib/patchers/aws3_p.js b/packages/core/lib/patchers/aws3_p.js new file mode 100644 index 00000000..69d2fde0 --- /dev/null +++ b/packages/core/lib/patchers/aws3_p.js @@ -0,0 +1,113 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.captureAWSClient = void 0; +const service_error_classification_1 = require("@aws-sdk/service-error-classification"); +const aws_1 = __importDefault(require("../segments/attributes/aws")); +const querystring_1 = require("querystring"); +const subsegment_1 = __importDefault(require("../segments/attributes/subsegment")); +var contextUtils = require('../context_utils'); +var logger = require('../logger'); +const utils_1 = require("../utils"); +async function buildAttributesFromMetadata(client, command, metadata) { + const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; + const serviceIdentifier = client.config.serviceId; + let operation = command.constructor.name.slice(0, -7); + const aws = new aws_1.default({ + extendedRequestId, + requestId, + retryCount: attempts, + request: { + operation, + httpRequest: { + region: await client.config.region(), + statusCode, + }, + params: command.input, + }, + }, serviceIdentifier); + const http = { response: { status: statusCode || 0 } }; + return [aws, http]; +} +function addFlags(http, subsegment, err) { + var _a, _b; + if (err && service_error_classification_1.isThrottlingError(err)) { + subsegment.addThrottleFlag(); + } + else if (((_a = http.response) === null || _a === void 0 ? void 0 : _a.status) === 429) { + subsegment.addThrottleFlag(); + } + const cause = utils_1.getCauseTypeFromHttpStatus((_b = http.response) === null || _b === void 0 ? void 0 : _b.status); + if (cause === 'fault') { + subsegment.addFaultFlag(); + } + else if (cause === 'error') { + subsegment.addErrorFlag(); + } +} +function captureAWSClient(client, manualSegment) { + // create local copy so that we can later call it + const send = client.send; + const serviceIdentifier = client.config.serviceId; + client.send = async (...args) => { + const [command] = args; + const segment = manualSegment || contextUtils.resolveSegment(); + let operation = command.constructor.name.slice(0, -7); + if (!segment) { + const output = serviceIdentifier + '.' + operation; + if (!contextUtils.isAutomaticMode()) { + logger.getLogger().info('Call ' + output + ' requires a segment object' + + ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); + } + else { + logger.getLogger().info('Call ' + output + + ' is missing the sub/segment context for automatic mode. Ignoring.'); + } + return send.apply(client, args); + } + const subsegment = segment.addNewSubsegment(serviceIdentifier); + subsegment.addAttribute('namespace', 'aws'); + try { + const res = (await send.apply(client, [command])); + if (!res) + throw new Error('Failed to get response from instrumented AWS Client.'); + const [aws, http] = await buildAttributesFromMetadata(client, command, res.$metadata); + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + addFlags(http, subsegment); + subsegment.close(); + return res; + } + catch (err) { + if (err.$metadata) { + const [aws, http] = await buildAttributesFromMetadata(client, command, err.$metadata); + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + addFlags(http, subsegment, err); + } + const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; + subsegment.close(errObj, true); + throw err; + } + }; + client.middlewareStack.add((next) => async (args) => { + const segment = manualSegment || contextUtils.resolveSegment(); + if (!segment) + return next(args); + const parent = (segment instanceof subsegment_1.default + ? segment.segment + : segment); + args.request.headers['X-Amzn-Trace-Id'] = querystring_1.stringify({ + Root: parent.trace_id, + Parent: segment.id, + Sampled: parent.notTraced ? '0' : '1', + }, ';'); + return next(args); + }, { + step: 'build', + }); + return client; +} +exports.captureAWSClient = captureAWSClient; diff --git a/packages/core/lib/patchers/aws3_p.ts b/packages/core/lib/patchers/aws3_p.ts new file mode 100644 index 00000000..19e377e1 --- /dev/null +++ b/packages/core/lib/patchers/aws3_p.ts @@ -0,0 +1,171 @@ +import type { + MetadataBearer, + ResponseMetadata, + Client, +} from '@aws-sdk/types'; + +import type { RegionInputConfig } from '@aws-sdk/config-resolver'; + +import { isThrottlingError } from '@aws-sdk/service-error-classification'; + +import ServiceSegment from '../segments/attributes/aws'; + +import { stringify } from 'querystring'; + +import Subsegment from '../segments/attributes/subsegment'; + +var contextUtils = require('../context_utils'); + +var logger = require('../logger'); + +import { getCauseTypeFromHttpStatus } from '../utils'; +import { SdkError } from '@aws-sdk/smithy-client'; +import { SegmentLike } from '../aws-xray'; + +type HttpResponse = { response: { status: number } }; + +async function buildAttributesFromMetadata( + client: any, + command: any, + metadata: ResponseMetadata, +): Promise<[ServiceSegment, HttpResponse]> { + const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; + const serviceIdentifier = client.config.serviceId as string; + + let operation: string = command.constructor.name.slice(0, -7); + + const aws = new ServiceSegment( + { + extendedRequestId, + requestId, + retryCount: attempts, + request: { + operation, + httpRequest: { + region: await client.config.region(), + statusCode, + }, + params: command.input, + }, + }, + serviceIdentifier, + ); + + const http = { response: { status: statusCode || 0 } }; + return [aws, http]; +} + +function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): void { + if (err && isThrottlingError(err)) { + subsegment.addThrottleFlag(); + } else if (http.response?.status === 429) { + subsegment.addThrottleFlag(); + } + + const cause = getCauseTypeFromHttpStatus(http.response?.status); + if (cause === 'fault') { + subsegment.addFaultFlag(); + } else if (cause === 'error') { + subsegment.addErrorFlag(); + } +} + +type DefaultConfiguration = RegionInputConfig & { + serviceId: string; +}; + +export function captureAWSClient< + Input extends object, + Output extends MetadataBearer, + Configuration extends DefaultConfiguration +>(client: Client, manualSegment?: SegmentLike): Client { + // create local copy so that we can later call it + const send = client.send; + + const serviceIdentifier = client.config.serviceId; + + client.send = async (...args: Parameters): Promise => { + const [command] = args; + const segment = manualSegment || contextUtils.resolveSegment(); + + let operation: string = command.constructor.name.slice(0, -7); + + if (!segment) { + const output = serviceIdentifier + '.' + operation; + + if (!contextUtils.isAutomaticMode()) { + logger.getLogger().info('Call ' + output + ' requires a segment object' + + ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); + } else { + logger.getLogger().info('Call ' + output + + ' is missing the sub/segment context for automatic mode. Ignoring.'); + } + return send.apply(client, args) as Promise; + } + + const subsegment = segment.addNewSubsegment(serviceIdentifier); + subsegment.addAttribute('namespace', 'aws'); + + try { + const res = (await send.apply(client, [command])) as Output; + + if (!res) throw new Error('Failed to get response from instrumented AWS Client.'); + + const [aws, http] = await buildAttributesFromMetadata( + client, + command, + res.$metadata, + ); + + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + + addFlags(http, subsegment); + subsegment.close(); + return res; + } catch (err) { + if (err.$metadata) { + const [aws, http] = await buildAttributesFromMetadata( + client, + command, + err.$metadata, + ); + + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + addFlags(http, subsegment, err); + } + + const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; + + subsegment.close(errObj, true); + throw err; + } + }; + + client.middlewareStack.add( + (next) => async (args: any) => { + const segment = manualSegment || contextUtils.resolveSegment(); + if (!segment) return next(args); + + const parent = (segment instanceof Subsegment + ? segment.segment + : segment); + + args.request.headers['X-Amzn-Trace-Id'] = stringify( + { + Root: parent.trace_id, + Parent: segment.id, + Sampled: parent.notTraced ? '0' : '1', + }, + ';', + ); + return next(args); + }, + { + step: 'build', + }, + ); + + return client; +} diff --git a/packages/core/lib/segments/attributes/subsegment.d.ts b/packages/core/lib/segments/attributes/subsegment.d.ts index f37b0c75..022b1063 100644 --- a/packages/core/lib/segments/attributes/subsegment.d.ts +++ b/packages/core/lib/segments/attributes/subsegment.d.ts @@ -1,4 +1,5 @@ import * as http from 'http'; +import { Segment, SegmentLike } from '../../aws-xray'; declare class Subsegment { id: string; @@ -6,6 +7,8 @@ declare class Subsegment { start_time: number; in_progress?: boolean; subsegments?: Array; + parent: SegmentLike; + segment: Segment; constructor(name: string); diff --git a/packages/core/lib/segments/segment.d.ts b/packages/core/lib/segments/segment.d.ts index c689eb40..f83de01e 100644 --- a/packages/core/lib/segments/segment.d.ts +++ b/packages/core/lib/segments/segment.d.ts @@ -11,6 +11,7 @@ declare class Segment { parent_id?: string; origin?: string; subsegments?: Array; + notTraced?: boolean; constructor(name: string, rootId?: string | null, parentId?: string | null); diff --git a/packages/core/package.json b/packages/core/package.json index 8e529bf9..46a9818d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -5,7 +5,8 @@ "author": "Amazon Web Services", "contributors": [ "Sandra McMullen ", - "William Armiros " + "William Armiros ", + "Moritz Onken " ], "main": "lib/index.js", "types": "lib/index.d.ts", @@ -17,6 +18,7 @@ }, "//": "@types/cls-hooked is exposed in API so must be in dependencies, not devDependencies", "dependencies": { + "@aws-sdk/service-error-classification": "^3.4.1", "@types/cls-hooked": "^4.2.2", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", diff --git a/packages/core/test/unit/patchers/aws3_p.test.js b/packages/core/test/unit/patchers/aws3_p.test.js new file mode 100644 index 00000000..d7c6bac5 --- /dev/null +++ b/packages/core/test/unit/patchers/aws3_p.test.js @@ -0,0 +1,214 @@ +var assert = require('chai').assert; +var chai = require('chai'); +var sinon = require('sinon'); +var sinonChai = require('sinon-chai'); + +var Aws = require('../../../lib/segments/attributes/aws'); +var awsPatcher = require('../../../lib/patchers/aws3_p'); +var contextUtils = require('../../../lib/context_utils'); +var Segment = require('../../../lib/segments/segment'); +var Utils = require('../../../lib/utils'); + +var { constructStack } = require('@aws-sdk/middleware-stack'); + +var logger = require('../../../lib/logger').getLogger(); + +chai.should(); +chai.use(sinonChai); + +var traceId = '1-57fbe041-2c7ad569f5d6ff149137be86'; + +describe('AWS v3 patcher', function() { + describe('#captureAWSClient', function() { + var customStub, sandbox, addMiddleware; + + var awsClient = { + send: function() {}, + config: { + serviceId: 's3', + }, + middlewareStack: constructStack(), + }; + + beforeEach(function() { + sandbox = sinon.createSandbox(); + customStub = sandbox.stub(awsClient, 'send'); + addMiddleware = sandbox.stub(awsClient.middlewareStack, 'add'); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it('should call middlewareStack.add and return the service', function() { + var patched = awsPatcher.captureAWSClient(awsClient); + addMiddleware.should.have.been.calledOnce; + assert.equal(patched, awsClient); + }); + }); + + describe('#captureAWSRequest', function() { + var awsClient, awsRequest, sandbox, segment, stubResolve, stubResolveManual, addNewSubsegmentStub, sub; + + before(function() { + awsClient = { + send: async (req) => { + const handler = awsClient.middlewareStack.resolve((args) => args); + await handler(req); + const error = req.response.error; + if (error) { + const err = new Error(error.message); + err.name = error.code; + err.$metadata = req.response.$metadata; + throw err; + } + return req.response; + }, + config: { + serviceId: 's3', + region: async () => 'us-east-1', + }, + middlewareStack: constructStack(), + }; + awsClient = awsPatcher.captureAWSClient(awsClient); + }); + + beforeEach(function() { + sandbox = sinon.createSandbox(); + + awsRequest = new (class ListBucketsCommand { + constructor() { + this.request = { + method: 'GET', + url: '/', + connection: { + remoteAddress: 'localhost' + }, + headers: {} + }; + this.response = { + $metadata: {} + }; + } + })(); + + segment = new Segment('testSegment', traceId); + sub = segment.addNewSubsegment('subseg'); + + stubResolveManual = sandbox.stub(contextUtils, 'resolveManualSegmentParams'); + stubResolve = sandbox.stub(contextUtils, 'resolveSegment').returns(segment); + addNewSubsegmentStub = sandbox.stub(segment, 'addNewSubsegment').returns(sub); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it.skip('should call to resolve any manual params', function() { + awsClient.send(awsRequest); + + stubResolveManual.should.have.been.calledWith(awsRequest.params); + }); + + it('should log an info statement and exit if parent is not found on the context or on the call params', function(done) { + stubResolve.returns(); + var logStub = sandbox.stub(logger, 'info'); + + awsClient.send(awsRequest); + + setTimeout(function() { + logStub.should.have.been.calledOnce; + done(); + }, 50); + }); + + it('should inject the tracing headers', async function() { + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + + awsClient.middlewareStack.add((next) => (args) => { + stubResolve.returns(sub); + next(args); + stubResolve.returns(segment); + }, { step: 'build', priority: 'high' }); + + await awsClient.send(awsRequest); + + assert.isTrue(addNewSubsegmentStub.calledWith('s3')); + + var expected = new RegExp('^Root=' + traceId + ';Parent=' + sub.id + ';Sampled=1$'); + assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected); + }); + + it('should close on complete with no errors when code 200 is seen', async function() { + var closeStub = sandbox.stub(sub, 'close').returns(); + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + awsRequest.response = { + $metadata: { httpStatusCode: 200 }, + }; + + await awsClient.send(awsRequest); + + closeStub.should.have.been.calledWithExactly(); + }); + + it('should mark the subsegment as throttled and error if code 429 is seen', async function() { + var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + awsRequest.response = { + error: { message: 'throttling', code: 'ThrottlingError' }, + $metadata: { httpStatusCode: 429 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); + + it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { + var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + awsRequest.response = { + error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, + $metadata: { httpStatusCode: 400 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); + + it('should capture an error on the response and mark exception as remote', async function() { + var closeStub = sandbox.stub(sub, 'close').returns(); + var getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); + + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + var error = { message: 'big error', code: 'Error' }; + + awsRequest.response = { + error, + $metadata: { httpStatusCode: 500 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + getCauseStub.should.have.been.calledWithExactly(500); + closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true); + }); + }); +}); diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 00000000..1a7a2de1 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2019", + "strict": true, + "strictNullChecks": true, + "declaration": true, + "esModuleInterop": true + }, + "files": ["lib/patchers/aws3_p.ts"] +} diff --git a/packages/express/test-d/index.test-d.ts b/packages/express/test-d/index.test-d.ts index 9720c4c3..d965afd4 100644 --- a/packages/express/test-d/index.test-d.ts +++ b/packages/express/test-d/index.test-d.ts @@ -1,5 +1,5 @@ import * as AWSXRay from 'aws-xray-sdk-core'; -import * as express from 'express'; +import express from 'express'; import { expectType } from 'tsd'; import * as xrayExpress from '../lib'; diff --git a/packages/express/tsconfig.json b/packages/express/tsconfig.json new file mode 100644 index 00000000..2f980427 --- /dev/null +++ b/packages/express/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/packages/full_sdk/tsconfig.json b/packages/full_sdk/tsconfig.json new file mode 100644 index 00000000..2f980427 --- /dev/null +++ b/packages/full_sdk/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/packages/mysql/tsconfig.json b/packages/mysql/tsconfig.json new file mode 100644 index 00000000..2f980427 --- /dev/null +++ b/packages/mysql/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/packages/postgres/tsconfig.json b/packages/postgres/tsconfig.json new file mode 100644 index 00000000..2f980427 --- /dev/null +++ b/packages/postgres/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/packages/restify/tsconfig.json b/packages/restify/tsconfig.json new file mode 100644 index 00000000..2f980427 --- /dev/null +++ b/packages/restify/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "esModuleInterop": true + } +} From cf247544b8162224a2282086331bc9dc26a17df7 Mon Sep 17 00:00:00 2001 From: William Armiros <54150514+willarmiros@users.noreply.github.com> Date: Fri, 7 May 2021 14:51:18 -0600 Subject: [PATCH 2/8] Add proper TypeScript build logic (#417) * build core files to dist directory * fixed unit tests * updated workflows and readme * try to fix windows * fix ls * slashes * no more ls * zstd decompress * see what bin has * removed rsync * fixes * added sh * try xargs instead * cleanups * fixed publishing logic --- .github/workflows/pr-build.yml | 4 +++- .github/workflows/release.yml | 1 + .gitignore | 1 + README.md | 8 ++++++-- packages/core/lib/aws-xray.js | 2 +- packages/core/package.json | 18 ++++++++++++++---- ...nt_maintained_across_shared_promise.test.js | 2 +- packages/core/test/unit/aws-xray.test.js | 13 +++++-------- packages/core/test/unit/env/aws_lambda.test.js | 2 +- .../segment_maintained_across_awaited.test.js | 2 +- packages/core/tsconfig.json | 11 ++++++++--- scripts/cp-with-structure.sh | 13 +++++++++++++ 12 files changed, 55 insertions(+), 22 deletions(-) create mode 100755 scripts/cp-with-structure.sh diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index c52a1dcf..5b12c0e5 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -4,7 +4,7 @@ on: push: branches: [master] pull_request: - branches: [master] + branches: [master, aws-v3-support] jobs: build: @@ -44,6 +44,7 @@ jobs: if: '!matrix.coverage' run: | npx lerna bootstrap --hoist + npx lerna run compile npx lerna run test shell: bash env: @@ -55,6 +56,7 @@ jobs: if: matrix.coverage run: | npx lerna bootstrap --hoist + npx lerna run compile npx lerna run testcov npx lerna run reportcov echo test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4a6e4245..88e97eb0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,7 @@ jobs: - name: Execute tests with Lerna run: | npx lerna bootstrap --hoist + npx lerna run compile npx lerna run test - name: Publish package to npm diff --git a/.gitignore b/.gitignore index 4ffe12ad..e351405e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ docs .idea/ .nyc_output/ *.lcov +dist diff --git a/README.md b/README.md index f1f64b59..6bb2fda7 100644 --- a/README.md +++ b/README.md @@ -89,14 +89,18 @@ AWS will not: ## Testing from Source -This repo uses [Lerna](https://lernajs.io) to manage multiple packages. To install Lerna: +This repo uses [Lerna](https://lernajs.io) to manage multiple packages. To install Lerna as a CLI: ``` -npm install lerna +npm install -g lerna ``` To install devDependencies and peerDependencies for all packages: ``` lerna bootstrap --hoist ``` +This repo has a combination of TypeScript and JavaScript source files. To transpile the TypeScript files for testing, run: +``` +lerna run compile +``` To run tests for all packages: ``` lerna run test diff --git a/packages/core/lib/aws-xray.js b/packages/core/lib/aws-xray.js index b81364a5..e491dcb2 100644 --- a/packages/core/lib/aws-xray.js +++ b/packages/core/lib/aws-xray.js @@ -9,7 +9,7 @@ var LambdaEnv = require('./env/aws_lambda'); // pkginfo as an empty object var pkginfo = {} try { - pkginfo = require('../package.json'); + pkginfo = require('../../package.json'); } catch (err) { logging.getLogger().debug('Failed to load SDK data:', err); } diff --git a/packages/core/package.json b/packages/core/package.json index 46a9818d..0000bee9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -8,8 +8,13 @@ "William Armiros ", "Moritz Onken " ], - "main": "lib/index.js", - "types": "lib/index.d.ts", + "files": [ + "dist/lib/**/*", + "LICENSE", + "README.md" + ], + "main": "dist/lib/index.js", + "types": "dist/lib/index.d.ts", "engines": { "node": ">= 10.x" }, @@ -25,9 +30,14 @@ "semver": "^5.3.0" }, "scripts": { - "test": "mocha --recursive ./test/ -R spec && tsd && mocha --recursive ./test_async/ -R spec", + "prepare": "npm run compile", + "compile": "tsc && npm run copy-lib && npm run copy-test", + "copy-lib": "find lib -type f \\( -name '*.d.ts' -o -name '*.json' \\) | xargs -I % ../../scripts/cp-with-structure.sh % dist", + "copy-test": "find test -name '*.json' | xargs -I % ../../scripts/cp-with-structure.sh % dist", + "test": "mocha --recursive ./dist/test/ -R spec && tsd && mocha --recursive ./dist/test_async/ -R spec", "test-d": "tsd", - "test-async": "mocha --recursive ./test_async/ -R spec", + "test-async": "mocha --recursive ./dist/test_async/ -R spec", + "clean": "rm -rf dist && rm -rf node_modules", "testcov": "nyc npm run test", "reportcov": "nyc report --reporter=text-lcov > coverage.lcov && codecov" }, diff --git a/packages/core/test/integration/segment_maintained_across_shared_promise.test.js b/packages/core/test/integration/segment_maintained_across_shared_promise.test.js index 25a58c10..e43f0fe9 100644 --- a/packages/core/test/integration/segment_maintained_across_shared_promise.test.js +++ b/packages/core/test/integration/segment_maintained_across_shared_promise.test.js @@ -7,7 +7,7 @@ if (!global.Promise) { var assert = require('chai').assert; var http = require('http'); -var AWSXRay = require('../../'); +var AWSXRay = require('../../lib'); var Segment = AWSXRay.Segment; AWSXRay.capturePromise(); diff --git a/packages/core/test/unit/aws-xray.test.js b/packages/core/test/unit/aws-xray.test.js index 6ca9f375..9dd1f80f 100644 --- a/packages/core/test/unit/aws-xray.test.js +++ b/packages/core/test/unit/aws-xray.test.js @@ -2,7 +2,6 @@ var assert = require('chai').assert; var chai = require('chai'); var sinon = require('sinon'); var sinonChai = require('sinon-chai'); -var upath = require('upath'); var segmentUtils = require('../../lib/segments/segment_utils'); @@ -30,14 +29,12 @@ describe('AWSXRay', function() { // This test requires both index.js and aws-xray.js are first time required. // We should always clear the require cache for these two files so this test // could run independently. - Object.keys(require.cache).forEach(function(key) { - var normalisedPath = upath.toUnix(key); - if(normalisedPath.includes('core/lib/index.js') || normalisedPath.includes('core/lib/aws-xray.js')) { - delete require.cache[key]; - } - }); + const indexPath = '../../lib/index'; + const xrayPath = '../../lib/aws-xray'; + delete require.cache[require.resolve(indexPath)]; + delete require.cache[require.resolve(xrayPath)]; - AWSXRay = require('../../lib/index'); + AWSXRay = require(indexPath); setSDKDataStub.should.have.been.calledWithExactly(sinon.match.object); setServiceDataStub.should.have.been.calledWithExactly(sinon.match.object); diff --git a/packages/core/test/unit/env/aws_lambda.test.js b/packages/core/test/unit/env/aws_lambda.test.js index ceb19f1f..ddb1f2ec 100644 --- a/packages/core/test/unit/env/aws_lambda.test.js +++ b/packages/core/test/unit/env/aws_lambda.test.js @@ -41,7 +41,7 @@ describe('AWSLambda', function() { }); describe('#init', function() { - var disableReusableSocketStub, populateStub, sandbox, setSegmentStub, validateStub; + var disableReusableSocketStub, disableCentralizedSamplingStub, populateStub, sandbox, setSegmentStub, validateStub; beforeEach(function() { sandbox = sinon.createSandbox(); diff --git a/packages/core/test_async/integration/segment_maintained_across_awaited.test.js b/packages/core/test_async/integration/segment_maintained_across_awaited.test.js index 479ffab8..f844a4bf 100644 --- a/packages/core/test_async/integration/segment_maintained_across_awaited.test.js +++ b/packages/core/test_async/integration/segment_maintained_across_awaited.test.js @@ -1,6 +1,6 @@ var assert = require('chai').assert; var http = require('http'); -var AWSXRay = require('../../'); +var AWSXRay = require('../../lib'); var Segment = AWSXRay.Segment; AWSXRay.enableAutomaticMode(); diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 1a7a2de1..93199148 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,8 +4,13 @@ "target": "es2019", "strict": true, "strictNullChecks": true, - "declaration": true, - "esModuleInterop": true + "declaration": false, + "esModuleInterop": true, + "skipLibCheck": true, + "allowJs": true, + "checkJs": false, + "outDir": "dist", }, - "files": ["lib/patchers/aws3_p.ts"] + "include": ["lib", "test", "test_async"], + "exclude": ["dist", "node_modules"] } diff --git a/scripts/cp-with-structure.sh b/scripts/cp-with-structure.sh new file mode 100755 index 00000000..1a9b046d --- /dev/null +++ b/scripts/cp-with-structure.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +## This script copies a file provided as the first parameter into the destination directory +## provided by the second parameter, while maintaining the directory structure of the source +## file. It is similar to 'cp --parents' on Linux, but usable cross-platform +src=(${*: 1}) +dest=${*: -1:1} +for filename in $src; do + [ -e "$filename" ] || continue + dirPath=$(dirname "${filename}") + mkdir -p $dest/$dirPath + cp -a $filename $dest/$dirPath +done From 2a474f175aefa0bfb23bf33b6e84a906b37e4a61 Mon Sep 17 00:00:00 2001 From: William Armiros <54150514+willarmiros@users.noreply.github.com> Date: Tue, 11 May 2021 01:48:20 -0600 Subject: [PATCH 3/8] Redesign AWS SDK V3 instrumentation to use middleware (#416) * updated deps and type file * removed type keyword added deps * remove changes to js * updated versions * finished redesign of aws sdk v3 instrumentation * refactored buildAttributes signature * add compile back to workflow * bumped tsd version instead Co-authored-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> --- .github/workflows/pr-build.yml | 1 - package-lock.json | 288 ++++++------------ package.json | 6 +- packages/core/lib/aws-xray.d.ts | 2 +- packages/core/lib/patchers/aws3_p.d.ts | 17 +- packages/core/lib/patchers/aws3_p.js | 113 ------- packages/core/lib/patchers/aws3_p.ts | 234 +++++++------- packages/core/lib/segments/attributes/aws.js | 10 +- packages/core/package.json | 10 +- .../core/test/unit/patchers/aws3_p.test.js | 227 ++++++++------ 10 files changed, 374 insertions(+), 534 deletions(-) delete mode 100644 packages/core/lib/patchers/aws3_p.js diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 5b12c0e5..4f58bac6 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -56,7 +56,6 @@ jobs: if: matrix.coverage run: | npx lerna bootstrap --hoist - npx lerna run compile npx lerna run testcov npx lerna run reportcov echo test diff --git a/package-lock.json b/package-lock.json index 3aac76a9..51203470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,21 +5,19 @@ "requires": true, "dependencies": { "@aws-sdk/config-resolver": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.8.0.tgz", - "integrity": "sha512-dtVB+yaT6gEqvzDt/pFS2suESTHb4qMiak3i34emSAcXilLYwOm3avUV/GApc499epQdxv/aRDAupanLVqTA1g==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.12.0.tgz", + "integrity": "sha512-xx4LcuJqgrT3fZ1FY45nIDCTzAh/pWfLM4Bh5rb1V8mT/ROAuSdG+NHYOVSOUOt7RN6X+cbvhZmztya3LxqL8g==", "requires": { - "@aws-sdk/signature-v4": "3.6.1", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/signature-v4": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/is-array-buffer": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.6.1.tgz", - "integrity": "sha512-qm2iDJmCrxlQE2dsFG+TujPe7jw4DF+4RTrsFMhk/e3lOl3MAzQ6Fc2kXtgeUcVrZVFTL8fQvXE1ByYyI6WbCw==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.12.0.tgz", + "integrity": "sha512-JtrxC2ZinhiL2GIfMoPYkmd7A5ykpYw4Bf4/uMHJ9d3NcFpsT84ipw4eZhclR+mSR9RUYSP0ObgcDLdjW3xm1w==", "requires": { "tslib": "^1.8.0" } @@ -34,24 +32,22 @@ } }, "@aws-sdk/node-config-provider": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.8.0.tgz", - "integrity": "sha512-VBpFquxACQO9MbdOIz35JgwOH+oJ5JwXpEq2faIhK+0zyM0JqLfJNFnnmHaEH9kBVcdOYJihzDgFje3AnYn7PQ==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.12.0.tgz", + "integrity": "sha512-eJAjQ5PN+cwd0AC4QOUjOjrmCAASkCmovDsNndjWmFjNumJkcUvTezAjOC6TLiEop9M1cT0zkhPBEDGjzDnjZQ==", "requires": { - "@aws-sdk/property-provider": "3.8.0", - "@aws-sdk/shared-ini-file-loader": "3.8.0", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/property-provider": "3.12.0", + "@aws-sdk/shared-ini-file-loader": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/property-provider": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.8.0.tgz", - "integrity": "sha512-9tOvTp6ObNdBgkqxXu5bpEdyzVnStO+aUprTbCH0lUfgCeig4q21xOt6Xsqt616WGtDJCAbMcdCay0XiDLLjAw==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.12.0.tgz", + "integrity": "sha512-4x9S0mtpehp++g+KWx12ZnYa396qCxJXB/n/njppXlWjUz7am527IN24YVTpFoP2CpNo4uZb9Xi8fW6veZSTJg==", "requires": { - "@aws-sdk/types": "3.6.1", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, @@ -61,58 +57,62 @@ "integrity": "sha512-kZ7ZhbrN1f+vrSRkTJvXsu7BlOyZgym058nPA745+1RZ1Rtv4Ax8oknf2RvJyj/1qRUi8LBaAREjzQ3C8tmLBA==" }, "@aws-sdk/shared-ini-file-loader": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.8.0.tgz", - "integrity": "sha512-wjywtEcsYPwB+asK5iWGeox9ZI4ycaxIGRKJTahFo+VUK6mByIEEG/IF7HuQclSSeDFTt9Occ7hQpXpJ97zpdA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.12.0.tgz", + "integrity": "sha512-vmd0gIZ0bc5hgyEDYufKfMsDKIPHV1ZXc8UzICV3BAsVf1eXhY8j+19OcxqlB+jWtLnnd2L28XslfRCYK9gduw==", "requires": { "tslib": "^1.8.0" } }, "@aws-sdk/signature-v4": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.6.1.tgz", - "integrity": "sha512-EAR0qGVL4AgzodZv4t+BSuBfyOXhTNxDxom50IFI1MqidR9vI6avNZKcPHhgXbm7XVcsDGThZKbzQ2q7MZ2NTA==", - "dev": true, - "requires": { - "@aws-sdk/is-array-buffer": "3.6.1", - "@aws-sdk/types": "3.6.1", - "@aws-sdk/util-hex-encoding": "3.6.1", - "@aws-sdk/util-uri-escape": "3.6.1", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.12.0.tgz", + "integrity": "sha512-11ZwHj8GjzsQNmebAaxhFcqSOgK6+5fUcrUDRu+R9HMvdKIuiLpawqCZELupbg4uqhka953rAldjbHjYhUaLuw==", + "requires": { + "@aws-sdk/is-array-buffer": "3.12.0", + "@aws-sdk/types": "3.12.0", + "@aws-sdk/util-hex-encoding": "3.12.0", + "@aws-sdk/util-uri-escape": "3.12.0", "tslib": "^1.8.0" } }, "@aws-sdk/smithy-client": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.6.1.tgz", - "integrity": "sha512-AVpRK4/iUxNeDdAm8UqP0ZgtgJMQeWcagTylijwelhWXyXzHUReY1sgILsWcdWnoy6gq845W7K2VBhBleni8+w==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.12.0.tgz", + "integrity": "sha512-bAPUYEP7UeuECSRVpo3Il09uWO2tE931zQm2ZL446Vv0GJtayYWtX4ZwB7V5ADHtTeCsRtjOcUmnNXJ5M0hGSQ==", "requires": { - "@aws-sdk/middleware-stack": "3.6.1", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/middleware-stack": "3.12.0", + "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" + }, + "dependencies": { + "@aws-sdk/middleware-stack": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.12.0.tgz", + "integrity": "sha512-X4TmWGLzY8ma99HQ+9vL4PoykfPtxdZ7QK/ZZ51I+i2vCKLz8tlml6y5rVR31TavJrg8qeAp+mQwttniSjmxYQ==", + "requires": { + "tslib": "^1.8.0" + } + } } }, "@aws-sdk/types": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.6.1.tgz", - "integrity": "sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==", - "dev": true + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.12.0.tgz", + "integrity": "sha512-7vnVBV0IdNQ+yyCQFkyLkRohvr7PHj//nGcth9RXG+VmQfp4+8CgBlMuXoeEWvDntrRgdh5lzDO0CliVRquxkw==" }, "@aws-sdk/util-hex-encoding": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.6.1.tgz", - "integrity": "sha512-pzsGOHtU2eGca4NJgFg94lLaeXDOg8pcS9sVt4f9LmtUGbrqRveeyBv0XlkHeZW2n0IZBssPHipVYQFlk7iaRA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.12.0.tgz", + "integrity": "sha512-hXzhCmPU8Q2U8QkSmMtPhT1sUtXbeFrEtFPyTbWr9p7AccWM3cOCZilOcUtV04cx9RgKNyhY/O1NOdByvSY1lQ==", "requires": { "tslib": "^1.8.0" } }, "@aws-sdk/util-uri-escape": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.6.1.tgz", - "integrity": "sha512-tgABiT71r0ScRJZ1pMX0xO0QPMMiISCtumph50IU5VDyZWYgeIxqkMhIcrL1lX0QbNCMgX0n6rZxGrrbjDNavA==", - "dev": true, + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.12.0.tgz", + "integrity": "sha512-ZkiGtqsE+Krr4ARweq/AV7llrEqLDMR3/R9gvwDcurYSBt1V1hNGTdGNUCSKeKmmeMxneAZXmp+xM3FYZoIjIw==", "requires": { "tslib": "^1.8.0" } @@ -3244,11 +3244,22 @@ "aws-xray-sdk-core": { "version": "file:packages/core", "requires": { + "@aws-sdk/config-resolver": "^3.4.1", + "@aws-sdk/node-config-provider": "^3.4.1", "@aws-sdk/service-error-classification": "^3.4.1", - "@types/cls-hooked": "^4.2.2", + "@aws-sdk/smithy-client": "^3.4.1", + "@aws-sdk/types": "3.6.1", + "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", "semver": "^5.3.0" + }, + "dependencies": { + "@aws-sdk/types": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.6.1.tgz", + "integrity": "sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==" + } } }, "aws-xray-sdk-express": { @@ -3782,12 +3793,6 @@ "pump": "^3.0.0" } }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -4343,12 +4348,6 @@ "is-obj": "^2.0.0" } }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5328,18 +5327,18 @@ }, "dependencies": { "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" } }, "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true } } @@ -5516,9 +5515,9 @@ "dev": true }, "eslint-rule-docs": { - "version": "1.1.221", - "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.221.tgz", - "integrity": "sha512-9vxNL90AmYii4Wy99MLQ3KfGyyfDixLurp9NlxB6tF3tqatL8YuAvjhm6vxRXKEEeMUh5Jc7lT49kiOWY/FhSQ==", + "version": "1.1.226", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.226.tgz", + "integrity": "sha512-Wnn0ETzE2v2UT0OdRCcdMNPkQtbzyZr3pPPXnkreP0l6ZJaKqnl88dL1DqZ6nCCZZwDGBAnN0Y+nCvGxxLPQLQ==", "dev": true }, "eslint-scope": { @@ -7601,9 +7600,9 @@ "dev": true }, "irregular-plurals": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.2.0.tgz", - "integrity": "sha512-YqTdPLfwP7YFN0SsD3QUVCkm9ZG2VzOXv3DOrw5G5mkMbVwptTwVcFv7/C0vOpBmgTxAeTG19XpUs1E522LW9Q==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", + "integrity": "sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==", "dev": true }, "is-absolute": { @@ -7820,9 +7819,9 @@ "dev": true }, "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "is-plain-obj": { @@ -12621,9 +12620,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -12995,9 +12994,9 @@ } }, "tsd": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.13.1.tgz", - "integrity": "sha512-+UYM8LRG/M4H8ISTg2ow8SWi65PS7Os+4DUnyiQLbJysXBp2DEmws9SMgBH+m8zHcJZqUJQ+mtDWJXP1IAvB2A==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.15.1.tgz", + "integrity": "sha512-8ADO2rPntfNiJV4KiqJiiiitfkXLxCbKEFN672JgwNiaEIuiyurTc1+w3InZ+0DqBz73B6Z3UflZcNGw5xMaDA==", "dev": true, "requires": { "eslint-formatter-pretty": "^4.0.0", @@ -13008,59 +13007,6 @@ "update-notifier": "^4.1.0" }, "dependencies": { - "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -13071,32 +13017,6 @@ "path-exists": "^4.0.0" } }, - "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -13125,16 +13045,6 @@ "yargs-parser": "^18.1.3" } }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -13177,12 +13087,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -13222,21 +13126,6 @@ } } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -13258,8 +13147,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsscmp": { "version": "1.0.6", diff --git a/package.json b/package.json index c7858f32..d17ffa8b 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,7 @@ "private": true, "license": "Apache-2.0", "devDependencies": { - "@aws-sdk/config-resolver": "^3.3.0", "@aws-sdk/middleware-stack": "^3.3.0", - "@aws-sdk/node-config-provider": "^3.3.0", - "@aws-sdk/smithy-client": "^3.3.0", - "@aws-sdk/types": "^3.3.0", "@hapi/hapi": "^20.0.0", "@types/chai": "^4.2.12", "@types/koa": "^2.11.3", @@ -45,7 +41,7 @@ "rewire": "^4.0.1", "sinon": "^9.0.2", "sinon-chai": "^3.5.0", - "tsd": "^0.13.1", + "tsd": "^0.15.1", "typescript": "^4.1.3", "upath": "^1.2.0" }, diff --git a/packages/core/lib/aws-xray.d.ts b/packages/core/lib/aws-xray.d.ts index c517d94d..bdba9865 100644 --- a/packages/core/lib/aws-xray.d.ts +++ b/packages/core/lib/aws-xray.d.ts @@ -39,7 +39,7 @@ export { captureAsyncFunc, captureCallbackFunc, captureFunc } from './capture' export { captureAWS, captureAWSClient } from './patchers/aws_p'; -export type { captureAWSClient as captureAWSv3Client } from './patchers/aws3_p'; +export { captureAWSClient as captureAWSv3Client } from './patchers/aws3_p'; export { captureHTTPs, captureHTTPsGlobal } from './patchers/http_p'; diff --git a/packages/core/lib/patchers/aws3_p.d.ts b/packages/core/lib/patchers/aws3_p.d.ts index 68d186af..304abbb0 100644 --- a/packages/core/lib/patchers/aws3_p.d.ts +++ b/packages/core/lib/patchers/aws3_p.d.ts @@ -1,8 +1,11 @@ -import type { MetadataBearer, Client } from '@aws-sdk/types'; -import type { RegionInputConfig } from '@aws-sdk/config-resolver'; +import { Client, MetadataBearer } from '@aws-sdk/types'; +import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; import { SegmentLike } from '../aws-xray'; -declare type DefaultConfiguration = RegionInputConfig & { - serviceId: string; -}; -export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; -export {}; +/** + * Instruments AWS SDK V3 clients with X-Ray via middleware. + * + * @param client - AWS SDK V3 client to instrument + * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users + * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack + */ +export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; diff --git a/packages/core/lib/patchers/aws3_p.js b/packages/core/lib/patchers/aws3_p.js deleted file mode 100644 index 69d2fde0..00000000 --- a/packages/core/lib/patchers/aws3_p.js +++ /dev/null @@ -1,113 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.captureAWSClient = void 0; -const service_error_classification_1 = require("@aws-sdk/service-error-classification"); -const aws_1 = __importDefault(require("../segments/attributes/aws")); -const querystring_1 = require("querystring"); -const subsegment_1 = __importDefault(require("../segments/attributes/subsegment")); -var contextUtils = require('../context_utils'); -var logger = require('../logger'); -const utils_1 = require("../utils"); -async function buildAttributesFromMetadata(client, command, metadata) { - const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; - const serviceIdentifier = client.config.serviceId; - let operation = command.constructor.name.slice(0, -7); - const aws = new aws_1.default({ - extendedRequestId, - requestId, - retryCount: attempts, - request: { - operation, - httpRequest: { - region: await client.config.region(), - statusCode, - }, - params: command.input, - }, - }, serviceIdentifier); - const http = { response: { status: statusCode || 0 } }; - return [aws, http]; -} -function addFlags(http, subsegment, err) { - var _a, _b; - if (err && service_error_classification_1.isThrottlingError(err)) { - subsegment.addThrottleFlag(); - } - else if (((_a = http.response) === null || _a === void 0 ? void 0 : _a.status) === 429) { - subsegment.addThrottleFlag(); - } - const cause = utils_1.getCauseTypeFromHttpStatus((_b = http.response) === null || _b === void 0 ? void 0 : _b.status); - if (cause === 'fault') { - subsegment.addFaultFlag(); - } - else if (cause === 'error') { - subsegment.addErrorFlag(); - } -} -function captureAWSClient(client, manualSegment) { - // create local copy so that we can later call it - const send = client.send; - const serviceIdentifier = client.config.serviceId; - client.send = async (...args) => { - const [command] = args; - const segment = manualSegment || contextUtils.resolveSegment(); - let operation = command.constructor.name.slice(0, -7); - if (!segment) { - const output = serviceIdentifier + '.' + operation; - if (!contextUtils.isAutomaticMode()) { - logger.getLogger().info('Call ' + output + ' requires a segment object' + - ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); - } - else { - logger.getLogger().info('Call ' + output + - ' is missing the sub/segment context for automatic mode. Ignoring.'); - } - return send.apply(client, args); - } - const subsegment = segment.addNewSubsegment(serviceIdentifier); - subsegment.addAttribute('namespace', 'aws'); - try { - const res = (await send.apply(client, [command])); - if (!res) - throw new Error('Failed to get response from instrumented AWS Client.'); - const [aws, http] = await buildAttributesFromMetadata(client, command, res.$metadata); - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment); - subsegment.close(); - return res; - } - catch (err) { - if (err.$metadata) { - const [aws, http] = await buildAttributesFromMetadata(client, command, err.$metadata); - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment, err); - } - const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; - subsegment.close(errObj, true); - throw err; - } - }; - client.middlewareStack.add((next) => async (args) => { - const segment = manualSegment || contextUtils.resolveSegment(); - if (!segment) - return next(args); - const parent = (segment instanceof subsegment_1.default - ? segment.segment - : segment); - args.request.headers['X-Amzn-Trace-Id'] = querystring_1.stringify({ - Root: parent.trace_id, - Parent: segment.id, - Sampled: parent.notTraced ? '0' : '1', - }, ';'); - return next(args); - }, { - step: 'build', - }); - return client; -} -exports.captureAWSClient = captureAWSClient; diff --git a/packages/core/lib/patchers/aws3_p.ts b/packages/core/lib/patchers/aws3_p.ts index 19e377e1..dc240bd5 100644 --- a/packages/core/lib/patchers/aws3_p.ts +++ b/packages/core/lib/patchers/aws3_p.ts @@ -1,10 +1,13 @@ -import type { - MetadataBearer, - ResponseMetadata, +import { + Pluggable, Client, + MetadataBearer, + BuildMiddleware, + MiddlewareStack, + BuildHandlerOptions, } from '@aws-sdk/types'; -import type { RegionInputConfig } from '@aws-sdk/config-resolver'; +import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; import { isThrottlingError } from '@aws-sdk/service-error-classification'; @@ -14,25 +17,33 @@ import { stringify } from 'querystring'; import Subsegment from '../segments/attributes/subsegment'; -var contextUtils = require('../context_utils'); +const contextUtils = require('../context_utils'); + +const logger = require('../logger'); -var logger = require('../logger'); +const { safeParseInt } = require('../utils'); import { getCauseTypeFromHttpStatus } from '../utils'; import { SdkError } from '@aws-sdk/smithy-client'; import { SegmentLike } from '../aws-xray'; -type HttpResponse = { response: { status: number } }; +const XRAY_PLUGIN_NAME: string = 'XRaySDKInstrumentation'; -async function buildAttributesFromMetadata( - client: any, - command: any, - metadata: ResponseMetadata, -): Promise<[ServiceSegment, HttpResponse]> { - const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = metadata; - const serviceIdentifier = client.config.serviceId as string; +interface HttpResponse { + response?: { + status?: number, + content_length?: number + } +}; - let operation: string = command.constructor.name.slice(0, -7); +const buildAttributesFromMetadata = async ( + service: string, + operation: string, + region: string, + res: any | null, + error: SdkError | null, +): Promise<[ServiceSegment, HttpResponse]> => { + const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = res?.output?.$metadata || error?.$metadata; const aws = new ServiceSegment( { @@ -42,16 +53,26 @@ async function buildAttributesFromMetadata( request: { operation, httpRequest: { - region: await client.config.region(), + region, statusCode, }, - params: command.input, }, }, - serviceIdentifier, + service, ); - const http = { response: { status: statusCode || 0 } }; + const http: HttpResponse = {}; + + if (statusCode) { + http.response = {}; + http.response.status = statusCode; + } + if (res?.response?.headers && res?.response?.headers['content-length'] !== undefined) { + if (!http.response) { + http.response = {}; + } + http.response.content_length = safeParseInt(res.response.headers['content-length']); + } return [aws, http]; } @@ -62,110 +83,111 @@ function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): v subsegment.addThrottleFlag(); } - const cause = getCauseTypeFromHttpStatus(http.response?.status); + const cause = getCauseTypeFromHttpStatus(safeParseInt(http.response?.status)); if (cause === 'fault') { subsegment.addFaultFlag(); } else if (cause === 'error') { subsegment.addErrorFlag(); } -} - -type DefaultConfiguration = RegionInputConfig & { - serviceId: string; }; -export function captureAWSClient< - Input extends object, - Output extends MetadataBearer, - Configuration extends DefaultConfiguration ->(client: Client, manualSegment?: SegmentLike): Client { - // create local copy so that we can later call it - const send = client.send; - - const serviceIdentifier = client.config.serviceId; - - client.send = async (...args: Parameters): Promise => { - const [command] = args; - const segment = manualSegment || contextUtils.resolveSegment(); - - let operation: string = command.constructor.name.slice(0, -7); - - if (!segment) { - const output = serviceIdentifier + '.' + operation; - - if (!contextUtils.isAutomaticMode()) { - logger.getLogger().info('Call ' + output + ' requires a segment object' + - ' on the request params as "XRaySegment" for tracing in manual mode. Ignoring.'); - } else { - logger.getLogger().info('Call ' + output + - ' is missing the sub/segment context for automatic mode. Ignoring.'); - } - return send.apply(client, args) as Promise; +const getXRayMiddleware = (config: RegionResolvedConfig, manualSegment?: SegmentLike): BuildMiddleware => (next: any, context: any) => async (args: any) => { + const segment = contextUtils.isAutomaticMode() ? contextUtils.resolveSegment() : manualSegment; + const {clientName, commandName} = context; + const operation: string = commandName.slice(0, -7); // Strip trailing "Command" string + const service: string = clientName.slice(0, -6); // Strip trailing "Client" string + + if (!segment) { + const output = service + '.' + operation.charAt(0).toLowerCase() + operation.slice(1); + + if (!contextUtils.isAutomaticMode()) { + logger.getLogger().info('Call ' + output + ' requires a segment object' + + ' passed to captureAWSv3Client for tracing in manual mode. Ignoring.'); + } else { + logger.getLogger().info('Call ' + output + + ' is missing the sub/segment context for automatic mode. Ignoring.'); } + return next(args); + } - const subsegment = segment.addNewSubsegment(serviceIdentifier); - subsegment.addAttribute('namespace', 'aws'); - - try { - const res = (await send.apply(client, [command])) as Output; + const subsegment: Subsegment = segment.addNewSubsegment(service); + subsegment.addAttribute('namespace', 'aws'); + const parent = (segment instanceof Subsegment ? segment.segment : segment); - if (!res) throw new Error('Failed to get response from instrumented AWS Client.'); + args.request.headers['X-Amzn-Trace-Id'] = stringify( + { + Root: parent.trace_id, + Parent: subsegment.id, + Sampled: parent.notTraced ? '0' : '1', + }, + ';', + ); + let res; + try { + res = await next(args); + if (!res) throw new Error('Failed to get response from instrumented AWS Client.'); + + const [aws, http] = await buildAttributesFromMetadata( + service, + operation, + await config.region(), + res, + null, + ); + + subsegment.addAttribute('aws', aws); + subsegment.addAttribute('http', http); + + addFlags(http, subsegment); + subsegment.close(); + return res; + } catch (err) { + if (err.$metadata) { const [aws, http] = await buildAttributesFromMetadata( - client, - command, - res.$metadata, + service, + operation, + await config.region(), + null, + err, ); subsegment.addAttribute('aws', aws); subsegment.addAttribute('http', http); - - addFlags(http, subsegment); - subsegment.close(); - return res; - } catch (err) { - if (err.$metadata) { - const [aws, http] = await buildAttributesFromMetadata( - client, - command, - err.$metadata, - ); - - subsegment.addAttribute('aws', aws); - subsegment.addAttribute('http', http); - addFlags(http, subsegment, err); - } - - const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; - - subsegment.close(errObj, true); - throw err; + addFlags(http, subsegment, err); } - }; - - client.middlewareStack.add( - (next) => async (args: any) => { - const segment = manualSegment || contextUtils.resolveSegment(); - if (!segment) return next(args); - - const parent = (segment instanceof Subsegment - ? segment.segment - : segment); - - args.request.headers['X-Amzn-Trace-Id'] = stringify( - { - Root: parent.trace_id, - Parent: segment.id, - Sampled: parent.notTraced ? '0' : '1', - }, - ';', - ); - return next(args); - }, - { - step: 'build', - }, - ); + const errObj = { message: err.message, name: err.name, stack: err.stack || new Error().stack }; + subsegment.close(errObj, true); + throw err; + } +}; + +const xRayMiddlewareOptions: BuildHandlerOptions = { + name: XRAY_PLUGIN_NAME, + step: 'build', +}; + +const getXRayPlugin = (config: RegionResolvedConfig, manualSegment?: SegmentLike): Pluggable => ({ + applyToStack: (stack: MiddlewareStack) => { + stack.add(getXRayMiddleware(config, manualSegment), xRayMiddlewareOptions); + }, +}); + +/** + * Instruments AWS SDK V3 clients with X-Ray via middleware. + * + * @param client - AWS SDK V3 client to instrument + * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users + * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack + */ +export function captureAWSClient< + Input extends object, + Output extends MetadataBearer, + Configuration extends RegionResolvedConfig, +> (client: Client, manualSegment?: SegmentLike): Client { + // Remove existing middleware to ensure operation is idempotent + client.middlewareStack.remove(XRAY_PLUGIN_NAME); + client.middlewareStack.use(getXRayPlugin(client.config, manualSegment)); return client; } diff --git a/packages/core/lib/segments/attributes/aws.js b/packages/core/lib/segments/attributes/aws.js index 66f071f4..be463337 100644 --- a/packages/core/lib/segments/attributes/aws.js +++ b/packages/core/lib/segments/attributes/aws.js @@ -19,11 +19,15 @@ function Aws(res, serviceName) { Aws.prototype.init = function init(res, serviceName) { //TODO: account ID this.operation = formatOperation(res.request.operation) || ''; - this.region = res.request.httpRequest.region || ''; - this.request_id = res.requestId || ''; + if (res && res.request && res.request.httpRequest && res.request.httpRequest.region) { + this.region = res.request.httpRequest.region; + } + if (res && res.requestId) { + this.request_id = res.requestId; + } this.retries = res.retryCount || 0; - if (res.extendedRequestId && serviceName === 's3') + if (res.extendedRequestId && serviceName && serviceName.toLowerCase() === 's3') this.id_2 = res.extendedRequestId; this.addData(capturer.capture(serviceName, res)); diff --git a/packages/core/package.json b/packages/core/package.json index 0000bee9..df178704 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -24,7 +24,11 @@ "//": "@types/cls-hooked is exposed in API so must be in dependencies, not devDependencies", "dependencies": { "@aws-sdk/service-error-classification": "^3.4.1", - "@types/cls-hooked": "^4.2.2", + "@aws-sdk/node-config-provider": "^3.4.1", + "@aws-sdk/config-resolver": "^3.4.1", + "@aws-sdk/smithy-client": "^3.4.1", + "@aws-sdk/types": "^3.4.1", + "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", "semver": "^5.3.0" @@ -34,9 +38,9 @@ "compile": "tsc && npm run copy-lib && npm run copy-test", "copy-lib": "find lib -type f \\( -name '*.d.ts' -o -name '*.json' \\) | xargs -I % ../../scripts/cp-with-structure.sh % dist", "copy-test": "find test -name '*.json' | xargs -I % ../../scripts/cp-with-structure.sh % dist", - "test": "mocha --recursive ./dist/test/ -R spec && tsd && mocha --recursive ./dist/test_async/ -R spec", + "test": "npm run compile && mocha --recursive ./dist/test/ -R spec && tsd && mocha --recursive ./dist/test_async/ -R spec", "test-d": "tsd", - "test-async": "mocha --recursive ./dist/test_async/ -R spec", + "test-async": "npm run compile && mocha --recursive ./dist/test_async/ -R spec", "clean": "rm -rf dist && rm -rf node_modules", "testcov": "nyc npm run test", "reportcov": "nyc report --reporter=text-lcov > coverage.lcov && codecov" diff --git a/packages/core/test/unit/patchers/aws3_p.test.js b/packages/core/test/unit/patchers/aws3_p.test.js index d7c6bac5..fe953530 100644 --- a/packages/core/test/unit/patchers/aws3_p.test.js +++ b/packages/core/test/unit/patchers/aws3_p.test.js @@ -20,7 +20,7 @@ var traceId = '1-57fbe041-2c7ad569f5d6ff149137be86'; describe('AWS v3 patcher', function() { describe('#captureAWSClient', function() { - var customStub, sandbox, addMiddleware; + var customStub, sandbox, useMiddleware; var awsClient = { send: function() {}, @@ -33,44 +33,48 @@ describe('AWS v3 patcher', function() { beforeEach(function() { sandbox = sinon.createSandbox(); customStub = sandbox.stub(awsClient, 'send'); - addMiddleware = sandbox.stub(awsClient.middlewareStack, 'add'); + useMiddleware = sandbox.stub(awsClient.middlewareStack, 'use'); }); afterEach(function() { sandbox.restore(); }); - it('should call middlewareStack.add and return the service', function() { - var patched = awsPatcher.captureAWSClient(awsClient); - addMiddleware.should.have.been.calledOnce; + it('should call middlewareStack.use and return the service', function() { + const patched = awsPatcher.captureAWSClient(awsClient); + useMiddleware.should.have.been.calledOnce; assert.equal(patched, awsClient); }); }); describe('#captureAWSRequest', function() { - var awsClient, awsRequest, sandbox, segment, stubResolve, stubResolveManual, addNewSubsegmentStub, sub; + var awsClient, awsRequest, sandbox, segment, stubResolve, addNewSubsegmentStub, sub; before(function() { awsClient = { send: async (req) => { - const handler = awsClient.middlewareStack.resolve((args) => args); + const context = { + clientName: 'S3Client', + commandName: 'ListBucketsCommand', + }; + const handler = awsClient.middlewareStack.resolve((args) => { + const error = req.response.error; + if (error) { + const err = new Error(error.message); + err.name = error.code; + err.$metadata = req.response.$metadata; + throw err; + } + return args; + }, context); await handler(req); - const error = req.response.error; - if (error) { - const err = new Error(error.message); - err.name = error.code; - err.$metadata = req.response.$metadata; - throw err; - } return req.response; }, config: { - serviceId: 's3', region: async () => 'us-east-1', }, middlewareStack: constructStack(), }; - awsClient = awsPatcher.captureAWSClient(awsClient); }); beforeEach(function() { @@ -86,16 +90,18 @@ describe('AWS v3 patcher', function() { }, headers: {} }; - this.response = { - $metadata: {} + this.response = {}; + this.output = { + $metadata: { + requestId: '123', + extendedRequestId: '456', + } }; } })(); segment = new Segment('testSegment', traceId); sub = segment.addNewSubsegment('subseg'); - - stubResolveManual = sandbox.stub(contextUtils, 'resolveManualSegmentParams'); stubResolve = sandbox.stub(contextUtils, 'resolveSegment').returns(segment); addNewSubsegmentStub = sandbox.stub(segment, 'addNewSubsegment').returns(sub); }); @@ -104,111 +110,142 @@ describe('AWS v3 patcher', function() { sandbox.restore(); }); - it.skip('should call to resolve any manual params', function() { - awsClient.send(awsRequest); + describe('#automaticMode', () => { + beforeEach(() => { + sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + }); - stubResolveManual.should.have.been.calledWith(awsRequest.params); - }); + before(() => { + awsClient = awsPatcher.captureAWSClient(awsClient); + }); - it('should log an info statement and exit if parent is not found on the context or on the call params', function(done) { - stubResolve.returns(); - var logStub = sandbox.stub(logger, 'info'); + it('should log an info statement and exit if parent is not found in the context for automatic mode', (done) => { + stubResolve.returns(); + const logStub = sandbox.stub(logger, 'info'); - awsClient.send(awsRequest); + awsClient.send(awsRequest); - setTimeout(function() { - logStub.should.have.been.calledOnce; - done(); - }, 50); - }); + setTimeout(function() { + logStub.should.have.been.calledOnce; + done(); + }, 50); + }); - it('should inject the tracing headers', async function() { - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); + it('should inject the tracing headers', async function() { + await awsClient.send(awsRequest); - awsClient.middlewareStack.add((next) => (args) => { - stubResolve.returns(sub); - next(args); - stubResolve.returns(segment); - }, { step: 'build', priority: 'high' }); + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); - await awsClient.send(awsRequest); + const expected = new RegExp('^Root=' + traceId + ';Parent=' + sub.id + ';Sampled=1$'); + assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected); + }); - assert.isTrue(addNewSubsegmentStub.calledWith('s3')); + it('should close on complete with no errors when code 200 is seen', async function() { + const closeStub = sandbox.stub(sub, 'close').returns(); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - var expected = new RegExp('^Root=' + traceId + ';Parent=' + sub.id + ';Sampled=1$'); - assert.match(awsRequest.request.headers['X-Amzn-Trace-Id'], expected); - }); + awsRequest.response = { + $metadata: { httpStatusCode: 200 }, + }; - it('should close on complete with no errors when code 200 is seen', async function() { - var closeStub = sandbox.stub(sub, 'close').returns(); - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest); - awsRequest.response = { - $metadata: { httpStatusCode: 200 }, - }; + closeStub.should.have.been.calledWithExactly(); + }); - await awsClient.send(awsRequest); + it('should mark the subsegment as throttled and error if code 429 is seen', async function() { + const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); - closeStub.should.have.been.calledWithExactly(); - }); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - it('should mark the subsegment as throttled and error if code 429 is seen', async function() { - var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + awsRequest.response = { + error: { message: 'throttling', code: 'ThrottlingError' }, + $metadata: { httpStatusCode: 429 }, + }; - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest).catch(() => null); - awsRequest.response = { - error: { message: 'throttling', code: 'ThrottlingError' }, - $metadata: { httpStatusCode: 429 }, - }; + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); - await awsClient.send(awsRequest).catch(() => null); + it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { + const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); - throttleStub.should.have.been.calledOnce; - assert.isTrue(sub.error); - }); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); - it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { - var throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + awsRequest.response = { + error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, + $metadata: { httpStatusCode: 400 }, + }; - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + await awsClient.send(awsRequest).catch(() => null); - awsRequest.response = { - error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, - $metadata: { httpStatusCode: 400 }, - }; + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); - await awsClient.send(awsRequest).catch(() => null); + it('should capture an error on the response and mark exception as remote', async function() { + const closeStub = sandbox.stub(sub, 'close').returns(); + const getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); - throttleStub.should.have.been.calledOnce; - assert.isTrue(sub.error); + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + const error = { message: 'big error', code: 'Error' }; + + awsRequest.response = { + error, + $metadata: { httpStatusCode: 500 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + getCauseStub.should.have.been.calledWithExactly(500); + closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true); + }); }); - it('should capture an error on the response and mark exception as remote', async function() { - var closeStub = sandbox.stub(sub, 'close').returns(); - var getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); + describe('#manualMode', () => { + beforeEach(() => { + sandbox.stub(contextUtils, 'isAutomaticMode').returns(false); + }); - sandbox.stub(contextUtils, 'isAutomaticMode').returns(true); - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); + it('should log an info statement and exit if parent is not found in the context for manual mode', (done) => { + awsClient = awsPatcher.captureAWSClient(awsClient); + var logStub = sandbox.stub(logger, 'info'); - var error = { message: 'big error', code: 'Error' }; + awsClient.send(awsRequest); - awsRequest.response = { - error, - $metadata: { httpStatusCode: 500 }, - }; + setTimeout(function() { + logStub.should.have.been.calledOnce; + done(); + }, 50); + }); + + it('should use the provided parent segment', () => { + awsClient = awsPatcher.captureAWSClient(awsClient, segment); + + awsClient.send(awsRequest); + + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); + }); + + it('should handle several calls to capture', () => { + const otherSeg = new Segment('otherTest'); + const otherAddNewStub = sandbox.stub(otherSeg, 'addNewSubsegment'); - await awsClient.send(awsRequest).catch(() => null); + awsClient = awsPatcher.captureAWSClient(awsClient, segment); + awsClient.send(awsRequest); + assert.isTrue(addNewSubsegmentStub.calledWith('S3')); - getCauseStub.should.have.been.calledWithExactly(500); - closeStub.should.have.been.calledWithExactly(sinon.match({ message: error.message, name: error.code}), true); + awsClient = awsPatcher.captureAWSClient(awsClient, otherSeg); + awsClient.send(awsRequest); + assert.isTrue(otherAddNewStub.calledWith('S3')); + }); }); }); }); From e9d8353cff27b3eddfbdf6ede7945c83b9e97ca9 Mon Sep 17 00:00:00 2001 From: William Armiros Date: Tue, 11 May 2021 09:39:26 -0700 Subject: [PATCH 4/8] removed dependencies and added docs --- package-lock.json | 29 +--------------- packages/core/README.md | 33 +++++++++++++++++-- packages/core/lib/patchers/aws3_p.ts | 11 +++---- packages/core/package.json | 2 -- .../core/test/unit/patchers/aws3_p.test.js | 17 ---------- 5 files changed, 36 insertions(+), 56 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51203470..a2107045 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,11 +51,6 @@ "tslib": "^1.8.0" } }, - "@aws-sdk/service-error-classification": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.6.1.tgz", - "integrity": "sha512-kZ7ZhbrN1f+vrSRkTJvXsu7BlOyZgym058nPA745+1RZ1Rtv4Ax8oknf2RvJyj/1qRUi8LBaAREjzQ3C8tmLBA==" - }, "@aws-sdk/shared-ini-file-loader": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.12.0.tgz", @@ -76,26 +71,6 @@ "tslib": "^1.8.0" } }, - "@aws-sdk/smithy-client": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.12.0.tgz", - "integrity": "sha512-bAPUYEP7UeuECSRVpo3Il09uWO2tE931zQm2ZL446Vv0GJtayYWtX4ZwB7V5ADHtTeCsRtjOcUmnNXJ5M0hGSQ==", - "requires": { - "@aws-sdk/middleware-stack": "3.12.0", - "@aws-sdk/types": "3.12.0", - "tslib": "^1.8.0" - }, - "dependencies": { - "@aws-sdk/middleware-stack": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.12.0.tgz", - "integrity": "sha512-X4TmWGLzY8ma99HQ+9vL4PoykfPtxdZ7QK/ZZ51I+i2vCKLz8tlml6y5rVR31TavJrg8qeAp+mQwttniSjmxYQ==", - "requires": { - "tslib": "^1.8.0" - } - } - } - }, "@aws-sdk/types": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.12.0.tgz", @@ -3246,9 +3221,7 @@ "requires": { "@aws-sdk/config-resolver": "^3.4.1", "@aws-sdk/node-config-provider": "^3.4.1", - "@aws-sdk/service-error-classification": "^3.4.1", - "@aws-sdk/smithy-client": "^3.4.1", - "@aws-sdk/types": "3.6.1", + "@aws-sdk/types": "^3.4.1", "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", diff --git a/packages/core/README.md b/packages/core/README.md index db07bfc9..8f3182f1 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -490,6 +490,21 @@ await s3.send(new PutObjectCommand({ })); ``` +Note that some TypeScript users may have to cast their clients to `any` when patching to avoid type errors. This is just for compatibility with the patcher, and will not impact the end client type if captured as shown below. + +```ts +import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; + +const s3 = new S3({}); +AWSXRay.captureAWSv3Client(s3 as any); + +await s3.send(new PutObjectCommand({ + Bucket: bucketName, + Key: keyName, + Body: 'Hello!', +})); +``` + AWS SDK v2 ```js @@ -644,8 +659,7 @@ function sendRequest(host, cb, subsegment) { AWS SDK v3 -You must re-capture the client every time the subsegment is attached -to a new parent. +You must re-capture the client every time the subsegment is attached to a new parent. ```js import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; @@ -661,6 +675,21 @@ await s3.send(new PutObjectCommand({ })); ``` +Note that some TypeScript users may have to cast their clients to `any` when patching to avoid type errors. This is just for compatibility with the patcher, and will not impact the end client type if captured as shown below. + +```ts +import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; + +const s3 = new S3({}); +AWSXRay.captureAWSv3Client(s3 as any, subsegment); + +await s3.send(new PutObjectCommand({ + Bucket: bucketName, + Key: keyName, + Body: 'Hello!', +})); +``` + AWS SDK v2 ```js diff --git a/packages/core/lib/patchers/aws3_p.ts b/packages/core/lib/patchers/aws3_p.ts index dc240bd5..5ca4c25e 100644 --- a/packages/core/lib/patchers/aws3_p.ts +++ b/packages/core/lib/patchers/aws3_p.ts @@ -9,8 +9,6 @@ import { import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; -import { isThrottlingError } from '@aws-sdk/service-error-classification'; - import ServiceSegment from '../segments/attributes/aws'; import { stringify } from 'querystring'; @@ -24,7 +22,6 @@ const logger = require('../logger'); const { safeParseInt } = require('../utils'); import { getCauseTypeFromHttpStatus } from '../utils'; -import { SdkError } from '@aws-sdk/smithy-client'; import { SegmentLike } from '../aws-xray'; const XRAY_PLUGIN_NAME: string = 'XRaySDKInstrumentation'; @@ -41,7 +38,7 @@ const buildAttributesFromMetadata = async ( operation: string, region: string, res: any | null, - error: SdkError | null, + error: MetadataBearer | null, ): Promise<[ServiceSegment, HttpResponse]> => { const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = res?.output?.$metadata || error?.$metadata; @@ -76,10 +73,10 @@ const buildAttributesFromMetadata = async ( return [aws, http]; } -function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): void { - if (err && isThrottlingError(err)) { +function addFlags(http: HttpResponse, subsegment: Subsegment, err?: MetadataBearer): void { + if (safeParseInt(err?.$metadata?.httpStatusCode) === 429) { subsegment.addThrottleFlag(); - } else if (http.response?.status === 429) { + } else if (safeParseInt(http.response?.status) === 429) { subsegment.addThrottleFlag(); } diff --git a/packages/core/package.json b/packages/core/package.json index df178704..532221cc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -23,10 +23,8 @@ }, "//": "@types/cls-hooked is exposed in API so must be in dependencies, not devDependencies", "dependencies": { - "@aws-sdk/service-error-classification": "^3.4.1", "@aws-sdk/node-config-provider": "^3.4.1", "@aws-sdk/config-resolver": "^3.4.1", - "@aws-sdk/smithy-client": "^3.4.1", "@aws-sdk/types": "^3.4.1", "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", diff --git a/packages/core/test/unit/patchers/aws3_p.test.js b/packages/core/test/unit/patchers/aws3_p.test.js index fe953530..56311c18 100644 --- a/packages/core/test/unit/patchers/aws3_p.test.js +++ b/packages/core/test/unit/patchers/aws3_p.test.js @@ -171,23 +171,6 @@ describe('AWS v3 patcher', function() { assert.isTrue(sub.error); }); - it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { - const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); - - sandbox.stub(sub, 'addAttribute').returns(); - sandbox.stub(Aws.prototype, 'init').returns(); - - awsRequest.response = { - error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, - $metadata: { httpStatusCode: 400 }, - }; - - await awsClient.send(awsRequest).catch(() => null); - - throttleStub.should.have.been.calledOnce; - assert.isTrue(sub.error); - }); - it('should capture an error on the response and mark exception as remote', async function() { const closeStub = sandbox.stub(sub, 'close').returns(); const getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); From 8dfe05461d51da4b6c68727459f6ca26b67417e8 Mon Sep 17 00:00:00 2001 From: William Armiros Date: Tue, 11 May 2021 10:43:00 -0700 Subject: [PATCH 5/8] add back most changes, update types --- package-lock.json | 56 +++++++++++++++++-- package.json | 3 + packages/core/README.md | 30 ---------- packages/core/lib/patchers/aws3_p.d.ts | 5 +- packages/core/lib/patchers/aws3_p.ts | 18 +++--- packages/core/package.json | 3 +- .../core/test/unit/patchers/aws3_p.test.js | 17 ++++++ 7 files changed, 84 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2107045..75883b32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.12.0.tgz", "integrity": "sha512-xx4LcuJqgrT3fZ1FY45nIDCTzAh/pWfLM4Bh5rb1V8mT/ROAuSdG+NHYOVSOUOt7RN6X+cbvhZmztya3LxqL8g==", + "dev": true, "requires": { "@aws-sdk/signature-v4": "3.12.0", "@aws-sdk/types": "3.12.0", @@ -18,6 +19,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.12.0.tgz", "integrity": "sha512-JtrxC2ZinhiL2GIfMoPYkmd7A5ykpYw4Bf4/uMHJ9d3NcFpsT84ipw4eZhclR+mSR9RUYSP0ObgcDLdjW3xm1w==", + "dev": true, "requires": { "tslib": "^1.8.0" } @@ -35,6 +37,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.12.0.tgz", "integrity": "sha512-eJAjQ5PN+cwd0AC4QOUjOjrmCAASkCmovDsNndjWmFjNumJkcUvTezAjOC6TLiEop9M1cT0zkhPBEDGjzDnjZQ==", + "dev": true, "requires": { "@aws-sdk/property-provider": "3.12.0", "@aws-sdk/shared-ini-file-loader": "3.12.0", @@ -46,15 +49,22 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.12.0.tgz", "integrity": "sha512-4x9S0mtpehp++g+KWx12ZnYa396qCxJXB/n/njppXlWjUz7am527IN24YVTpFoP2CpNo4uZb9Xi8fW6veZSTJg==", + "dev": true, "requires": { "@aws-sdk/types": "3.12.0", "tslib": "^1.8.0" } }, + "@aws-sdk/service-error-classification": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.15.0.tgz", + "integrity": "sha512-ay7l8AgtGM3NvvUhsW8cKmTcDX460fGZZLUXUEbdtO274RzHLU3jKSLj0jg74b2212ZFRIMwh2OQHiy8brLu8Q==" + }, "@aws-sdk/shared-ini-file-loader": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.12.0.tgz", "integrity": "sha512-vmd0gIZ0bc5hgyEDYufKfMsDKIPHV1ZXc8UzICV3BAsVf1eXhY8j+19OcxqlB+jWtLnnd2L28XslfRCYK9gduw==", + "dev": true, "requires": { "tslib": "^1.8.0" } @@ -63,6 +73,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.12.0.tgz", "integrity": "sha512-11ZwHj8GjzsQNmebAaxhFcqSOgK6+5fUcrUDRu+R9HMvdKIuiLpawqCZELupbg4uqhka953rAldjbHjYhUaLuw==", + "dev": true, "requires": { "@aws-sdk/is-array-buffer": "3.12.0", "@aws-sdk/types": "3.12.0", @@ -71,15 +82,51 @@ "tslib": "^1.8.0" } }, + "@aws-sdk/smithy-client": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.15.0.tgz", + "integrity": "sha512-i25agLm/8+pSSTVGFxSKiCNVN9EqT2UuwKtxHk2qOBQAVUhn7Rd6BLbmaGRM1yOvTIEAv4DW5hYJsxyLWg+3vw==", + "dev": true, + "requires": { + "@aws-sdk/middleware-stack": "3.15.0", + "@aws-sdk/types": "3.15.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "@aws-sdk/middleware-stack": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.15.0.tgz", + "integrity": "sha512-UjTI3K2TcfK3CpLKc7lp4/Bh0UzKR86vb7smLwFGt/3r/VvLxrN7XyU69+BFOk9vOGFro0H2LbGT7355aTQlfw==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + } + }, + "@aws-sdk/types": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.15.0.tgz", + "integrity": "sha512-hRfp40av3/dwxUH7KAgfLL3D02ohc7NYs/R0xFgYWEpAieB9/BHKuJPFGOSetqWw+Z6NOLiKKva8+/CcVOqzJQ==", + "dev": true + }, + "tslib": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "dev": true + } + } + }, "@aws-sdk/types": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.12.0.tgz", - "integrity": "sha512-7vnVBV0IdNQ+yyCQFkyLkRohvr7PHj//nGcth9RXG+VmQfp4+8CgBlMuXoeEWvDntrRgdh5lzDO0CliVRquxkw==" + "integrity": "sha512-7vnVBV0IdNQ+yyCQFkyLkRohvr7PHj//nGcth9RXG+VmQfp4+8CgBlMuXoeEWvDntrRgdh5lzDO0CliVRquxkw==", + "dev": true }, "@aws-sdk/util-hex-encoding": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.12.0.tgz", "integrity": "sha512-hXzhCmPU8Q2U8QkSmMtPhT1sUtXbeFrEtFPyTbWr9p7AccWM3cOCZilOcUtV04cx9RgKNyhY/O1NOdByvSY1lQ==", + "dev": true, "requires": { "tslib": "^1.8.0" } @@ -88,6 +135,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.12.0.tgz", "integrity": "sha512-ZkiGtqsE+Krr4ARweq/AV7llrEqLDMR3/R9gvwDcurYSBt1V1hNGTdGNUCSKeKmmeMxneAZXmp+xM3FYZoIjIw==", + "dev": true, "requires": { "tslib": "^1.8.0" } @@ -3219,8 +3267,7 @@ "aws-xray-sdk-core": { "version": "file:packages/core", "requires": { - "@aws-sdk/config-resolver": "^3.4.1", - "@aws-sdk/node-config-provider": "^3.4.1", + "@aws-sdk/service-error-classification": "^3.4.1", "@aws-sdk/types": "^3.4.1", "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", @@ -13120,7 +13167,8 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "tsscmp": { "version": "1.0.6", diff --git a/package.json b/package.json index d17ffa8b..ff8d3389 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "license": "Apache-2.0", "devDependencies": { "@aws-sdk/middleware-stack": "^3.3.0", + "@aws-sdk/node-config-provider": "^3.4.1", + "@aws-sdk/config-resolver": "^3.4.1", + "@aws-sdk/smithy-client": "^3.4.1", "@hapi/hapi": "^20.0.0", "@types/chai": "^4.2.12", "@types/koa": "^2.11.3", diff --git a/packages/core/README.md b/packages/core/README.md index 8f3182f1..26522512 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -490,21 +490,6 @@ await s3.send(new PutObjectCommand({ })); ``` -Note that some TypeScript users may have to cast their clients to `any` when patching to avoid type errors. This is just for compatibility with the patcher, and will not impact the end client type if captured as shown below. - -```ts -import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; - -const s3 = new S3({}); -AWSXRay.captureAWSv3Client(s3 as any); - -await s3.send(new PutObjectCommand({ - Bucket: bucketName, - Key: keyName, - Body: 'Hello!', -})); -``` - AWS SDK v2 ```js @@ -675,21 +660,6 @@ await s3.send(new PutObjectCommand({ })); ``` -Note that some TypeScript users may have to cast their clients to `any` when patching to avoid type errors. This is just for compatibility with the patcher, and will not impact the end client type if captured as shown below. - -```ts -import { S3, PutObjectCommand } from '@aws-sdk/client-s3'; - -const s3 = new S3({}); -AWSXRay.captureAWSv3Client(s3 as any, subsegment); - -await s3.send(new PutObjectCommand({ - Bucket: bucketName, - Key: keyName, - Body: 'Hello!', -})); -``` - AWS SDK v2 ```js diff --git a/packages/core/lib/patchers/aws3_p.d.ts b/packages/core/lib/patchers/aws3_p.d.ts index 304abbb0..6a5d5b94 100644 --- a/packages/core/lib/patchers/aws3_p.d.ts +++ b/packages/core/lib/patchers/aws3_p.d.ts @@ -1,5 +1,4 @@ -import { Client, MetadataBearer } from '@aws-sdk/types'; -import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; +import { Client } from '@aws-sdk/types'; import { SegmentLike } from '../aws-xray'; /** * Instruments AWS SDK V3 clients with X-Ray via middleware. @@ -8,4 +7,4 @@ import { SegmentLike } from '../aws-xray'; * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack */ -export declare function captureAWSClient(client: Client, manualSegment?: SegmentLike): Client; +export declare function captureAWSClient>(client: T, manualSegment?: SegmentLike): T diff --git a/packages/core/lib/patchers/aws3_p.ts b/packages/core/lib/patchers/aws3_p.ts index 5ca4c25e..7a6e8613 100644 --- a/packages/core/lib/patchers/aws3_p.ts +++ b/packages/core/lib/patchers/aws3_p.ts @@ -9,6 +9,10 @@ import { import { RegionResolvedConfig } from '@aws-sdk/config-resolver'; +import { isThrottlingError } from '@aws-sdk/service-error-classification'; + +import { SdkError } from '@aws-sdk/smithy-client'; + import ServiceSegment from '../segments/attributes/aws'; import { stringify } from 'querystring'; @@ -38,7 +42,7 @@ const buildAttributesFromMetadata = async ( operation: string, region: string, res: any | null, - error: MetadataBearer | null, + error: SdkError | null, ): Promise<[ServiceSegment, HttpResponse]> => { const { extendedRequestId, requestId, httpStatusCode: statusCode, attempts } = res?.output?.$metadata || error?.$metadata; @@ -73,10 +77,10 @@ const buildAttributesFromMetadata = async ( return [aws, http]; } -function addFlags(http: HttpResponse, subsegment: Subsegment, err?: MetadataBearer): void { - if (safeParseInt(err?.$metadata?.httpStatusCode) === 429) { +function addFlags(http: HttpResponse, subsegment: Subsegment, err?: SdkError): void { + if (err && isThrottlingError(err)) { subsegment.addThrottleFlag(); - } else if (safeParseInt(http.response?.status) === 429) { + } else if (safeParseInt(http.response?.status) === 429 || safeParseInt(err?.$metadata?.httpStatusCode) === 429) { subsegment.addThrottleFlag(); } @@ -178,11 +182,7 @@ const getXRayPlugin = (config: RegionResolvedConfig, manualSegment?: SegmentLike * @param manualSegment - Parent segment or subsegment that is passed in for manual mode users * @returns - the client with the X-Ray instrumentation middleware added to its middleware stack */ -export function captureAWSClient< - Input extends object, - Output extends MetadataBearer, - Configuration extends RegionResolvedConfig, -> (client: Client, manualSegment?: SegmentLike): Client { +export function captureAWSClient>(client: T, manualSegment?: SegmentLike): T { // Remove existing middleware to ensure operation is idempotent client.middlewareStack.remove(XRAY_PLUGIN_NAME); client.middlewareStack.use(getXRayPlugin(client.config, manualSegment)); diff --git a/packages/core/package.json b/packages/core/package.json index 532221cc..4bd520a1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -23,9 +23,8 @@ }, "//": "@types/cls-hooked is exposed in API so must be in dependencies, not devDependencies", "dependencies": { - "@aws-sdk/node-config-provider": "^3.4.1", - "@aws-sdk/config-resolver": "^3.4.1", "@aws-sdk/types": "^3.4.1", + "@aws-sdk/service-error-classification": "^3.4.1", "@types/cls-hooked": "^4.3.3", "atomic-batcher": "^1.0.2", "cls-hooked": "^4.2.2", diff --git a/packages/core/test/unit/patchers/aws3_p.test.js b/packages/core/test/unit/patchers/aws3_p.test.js index 56311c18..fe953530 100644 --- a/packages/core/test/unit/patchers/aws3_p.test.js +++ b/packages/core/test/unit/patchers/aws3_p.test.js @@ -171,6 +171,23 @@ describe('AWS v3 patcher', function() { assert.isTrue(sub.error); }); + it('should mark the subsegment as throttled and error if code service.throttledError returns true, regardless of status code', async function() { + const throttleStub = sandbox.stub(sub, 'addThrottleFlag').returns(); + + sandbox.stub(sub, 'addAttribute').returns(); + sandbox.stub(Aws.prototype, 'init').returns(); + + awsRequest.response = { + error: { message: 'throttling', code: 'ProvisionedThroughputExceededException' }, + $metadata: { httpStatusCode: 400 }, + }; + + await awsClient.send(awsRequest).catch(() => null); + + throttleStub.should.have.been.calledOnce; + assert.isTrue(sub.error); + }); + it('should capture an error on the response and mark exception as remote', async function() { const closeStub = sandbox.stub(sub, 'close').returns(); const getCauseStub = sandbox.stub(Utils, 'getCauseTypeFromHttpStatus').returns(); From 3a82f71cd9df4377c04c930db0f5cb2a25790453 Mon Sep 17 00:00:00 2001 From: William Armiros Date: Tue, 11 May 2021 10:56:37 -0700 Subject: [PATCH 6/8] removed aws-v3 branch from CI --- .github/workflows/pr-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 4f58bac6..f7a7d669 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -4,7 +4,7 @@ on: push: branches: [master] pull_request: - branches: [master, aws-v3-support] + branches: [master] jobs: build: From ba29b138450bfd3824074d6b8a8ca02c6e334120 Mon Sep 17 00:00:00 2001 From: William Armiros Date: Tue, 11 May 2021 11:43:39 -0700 Subject: [PATCH 7/8] fixed codecov to use dist directory --- .nycrc.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.nycrc.json b/.nycrc.json index 27a3d3bc..0cbcf40d 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -1,12 +1,14 @@ { "all": true, + "include": [ + "**/dist/lib/**/*.js" + ], "exclude": [ - "**/Gruntfile.js", - "**/.prettierrc.js", "**/*.d.ts", "**/sample/**", "**/test/**", "**/test-d/**", - "**/test_async/**" + "**/test_async/**", + "**/docs/**" ] } From d5c735490138d081e4a413993fa559cd1d8be625 Mon Sep 17 00:00:00 2001 From: William Armiros Date: Wed, 12 May 2021 12:08:09 -0700 Subject: [PATCH 8/8] added blog post link --- packages/core/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index 26522512..9ee6aae0 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -465,7 +465,7 @@ function sendRequest(host, cb) { ### Capture all outgoing AWS requests -This is only available for AWS SDK v2 due to the service-oriented architecture of AWS SDK v3. +This is only available for AWS SDK v2 due to the modular architecture of AWS SDK v3. For more details on the difference between AWS SDK v2 and v3, see this [blog post](https://aws.amazon.com/blogs/developer/modular-aws-sdk-for-javascript-is-now-generally-available/). ```js var AWS = captureAWS(require('aws-sdk')); @@ -678,7 +678,7 @@ s3.putObject(params, function(err, data) { ### Capture all outgoing AWS requests -This is only available for AWS SDK v2 due to the service-oriented architecture of AWS SDK v3. +This is only available for AWS SDK v2 due to the modular architecture of AWS SDK v3. For more details on the difference between AWS SDK v2 and v3, see this [blog post](https://aws.amazon.com/blogs/developer/modular-aws-sdk-for-javascript-is-now-generally-available/). ```js var AWS = captureAWS(require('aws-sdk'));