@instana/aws-lambda
Advanced tools
+422
-10
@@ -6,23 +6,435 @@ # Change Log | ||
| # [5.0.0](https://github.com/instana/nodejs/compare/v3.21.0...v5.0.0) (2024-10-23) | ||
| ## [5.0.1](https://github.com/instana/nodejs/compare/v5.0.0...v5.0.1) (2025-12-16) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [5.0.0](https://github.com/instana/nodejs/compare/v4.31.0...v5.0.0) (2025-12-16) | ||
| ### Bug Fixes | ||
| - dropped support for lambda runtimes v14 and v16 ([#1352](https://github.com/instana/nodejs/issues/1352)) ([4d28d6b](https://github.com/instana/nodejs/commit/4d28d6b13b0299570b8b59c3f095fd76484e6f8b)) | ||
| - dropped support for node v14 and v16 ([#1348](https://github.com/instana/nodejs/issues/1348)) ([aaa9ad4](https://github.com/instana/nodejs/commit/aaa9ad41ebf82b11eedcf913afc31d3addd53868)) | ||
| * enforced Node.js 18.19 as the minimum supported version ([#2151](https://github.com/instana/nodejs/issues/2151)) ([5d688e2](https://github.com/instana/nodejs/commit/5d688e22ff03a6e4721a0363011002801a1ee045)) | ||
| * removed deprecated config options for disabling tracing ([#2145](https://github.com/instana/nodejs/issues/2145)) ([efe07ed](https://github.com/instana/nodejs/commit/efe07ed7c5b09fa66869f8305ce9a829638c1e0c)) | ||
| ### BREAKING CHANGES | ||
| * Dropped support for Node.js versions below 18.19 | ||
| * The following environment variables and configuration options, previously used to disable tracing, have been removed: | ||
| - INSTANA_DISABLED_TRACERS | ||
| - INSTANA_DISABLE_TRACING | ||
| - tracing.disabledTracers | ||
| Migration Recommendations: | ||
| Replace INSTANA_DISABLED_TRACERS and INSTANA_DISABLE_TRACING with INSTANA_TRACING_DISABLE. | ||
| Replace tracing.disabledTracers with tracing.disable. | ||
| # [4.31.0](https://github.com/instana/nodejs/compare/v4.30.1...v4.31.0) (2025-12-08) | ||
| ### Bug Fixes | ||
| * **aws-lambda-auto-wrap:** stopped publishing to npm ([#2185](https://github.com/instana/nodejs/issues/2185)) ([3e83397](https://github.com/instana/nodejs/commit/3e83397fdb7e7c03f90be95ce2d629c1ebeb0c3b)) | ||
| * **serverless:** resolved TypeError when agent key is not available ([#2197](https://github.com/instana/nodejs/issues/2197)) ([d24e759](https://github.com/instana/nodejs/commit/d24e759cd220dfb92975d88fd845cd3de5b99ad2)) | ||
| ### Features | ||
| * **aws-lambda:** added support for Node v24 runtime ([#2174](https://github.com/instana/nodejs/issues/2174)) ([71e11fb](https://github.com/instana/nodejs/commit/71e11fbee4008ea3a3fda209805f0e6f03e01413)) | ||
| * **iaws-lambda:** added runtime-aware handler support for Node.js 24 compatibility ([#2195](https://github.com/instana/nodejs/issues/2195)) ([35a7fbc](https://github.com/instana/nodejs/commit/35a7fbc9ede5119a7c48d15823f390f407889311)) | ||
| ## [4.30.1](https://github.com/instana/nodejs/compare/v4.30.0...v4.30.1) (2025-11-18) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.30.0](https://github.com/instana/nodejs/compare/v4.29.0...v4.30.0) (2025-11-17) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.29.0](https://github.com/instana/nodejs/compare/v4.28.0...v4.29.0) (2025-11-07) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.28.0](https://github.com/instana/nodejs/compare/v4.27.1...v4.28.0) (2025-11-06) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.27.1](https://github.com/instana/nodejs/compare/v4.27.0...v4.27.1) (2025-11-03) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.27.0](https://github.com/instana/nodejs/compare/v4.26.4...v4.27.0) (2025-10-23) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.26.4](https://github.com/instana/nodejs/compare/v4.26.3...v4.26.4) (2025-10-21) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.26.3](https://github.com/instana/nodejs/compare/v4.26.2...v4.26.3) (2025-10-21) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.26.2](https://github.com/instana/nodejs/compare/v4.26.1...v4.26.2) (2025-10-15) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.26.1](https://github.com/instana/nodejs/compare/v4.26.0...v4.26.1) (2025-10-13) | ||
| ### Bug Fixes | ||
| * **aws-lambda:** resolved timeout when INSTANA_AGENT_KEY is not provided ([#2058](https://github.com/instana/nodejs/issues/2058)) ([cba173a](https://github.com/instana/nodejs/commit/cba173a5d9d5867eb9c81fafbb91951f28d071e6)) | ||
| # [4.26.0](https://github.com/instana/nodejs/compare/v4.25.0...v4.26.0) (2025-10-08) | ||
| ### Bug Fixes | ||
| * **aws-lambda:** reduced lambda extension binary size ([#2044](https://github.com/instana/nodejs/issues/2044)) ([8bbed42](https://github.com/instana/nodejs/commit/8bbed4288259602e233946d70a6d54abca06fa81)) | ||
| # [4.25.0](https://github.com/instana/nodejs/compare/v4.24.1...v4.25.0) (2025-09-23) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.24.1](https://github.com/instana/nodejs/compare/v4.24.0...v4.24.1) (2025-09-18) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.24.0](https://github.com/instana/nodejs/compare/v4.23.1...v4.24.0) (2025-09-11) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.23.1](https://github.com/instana/nodejs/compare/v4.23.0...v4.23.1) (2025-09-01) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.23.0](https://github.com/instana/nodejs/compare/v4.22.0...v4.23.0) (2025-08-25) | ||
| ### Bug Fixes | ||
| * **aws-lambda:** updated brace-expansion in icr.io/instana/aws-lambda-nodejs image ([#1944](https://github.com/instana/nodejs/issues/1944)) ([4665738](https://github.com/instana/nodejs/commit/46657386b6aef1500d9747cdeaee3ff802510416)) | ||
| # [4.22.0](https://github.com/instana/nodejs/compare/v4.21.3...v4.22.0) (2025-08-13) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.21.3](https://github.com/instana/nodejs/compare/v4.21.2...v4.21.3) (2025-08-07) | ||
| ### Bug Fixes | ||
| * **aws-lambda:** improved coldstarts ([#1933](https://github.com/instana/nodejs/issues/1933)) ([cfede29](https://github.com/instana/nodejs/commit/cfede297893f4535b6a53602a8737c07cb4c7f5a)) | ||
| ## [4.21.2](https://github.com/instana/nodejs/compare/v4.21.1...v4.21.2) (2025-08-05) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.21.1](https://github.com/instana/nodejs/compare/v4.21.0...v4.21.1) (2025-08-05) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.21.0](https://github.com/instana/nodejs/compare/v4.20.0...v4.21.0) (2025-07-31) | ||
| ### Features | ||
| * **aws-lambda:** improved overhaul performance ([#1315](https://github.com/instana/nodejs/issues/1315)) ([4620113](https://github.com/instana/nodejs/commit/46201132dac6a73e7719d085c4edaa5c5a5ae526)) | ||
| # [4.20.0](https://github.com/instana/nodejs/compare/v4.19.1...v4.20.0) (2025-07-30) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.19.1](https://github.com/instana/nodejs/compare/v4.19.0...v4.19.1) (2025-07-25) | ||
| ### Bug Fixes | ||
| * **serverless:** resolved maximum call stack error ([#1877](https://github.com/instana/nodejs/issues/1877)) ([985b3c1](https://github.com/instana/nodejs/commit/985b3c165b0533a068e9e37c1e0b99a1fbfb4da0)) | ||
| # [4.19.0](https://github.com/instana/nodejs/compare/v4.18.1...v4.19.0) (2025-07-24) | ||
| ### Bug Fixes | ||
| * **serverless:** removed trailing slashes from instana endpoint url ([#1862](https://github.com/instana/nodejs/issues/1862)) ([305f2b2](https://github.com/instana/nodejs/commit/305f2b249900d6e5e0ffb7b305b486fd1cf2621a)) | ||
| ## [4.18.1](https://github.com/instana/nodejs/compare/v4.18.0...v4.18.1) (2025-07-14) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.18.0](https://github.com/instana/nodejs/compare/v4.17.0...v4.18.0) (2025-07-10) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.17.0](https://github.com/instana/nodejs/compare/v4.16.0...v4.17.0) (2025-06-30) | ||
| ### Bug Fixes | ||
| * depreacted INSTANA_DISABLE_TRACING env variable ([#1796](https://github.com/instana/nodejs/issues/1796)) ([4559cb8](https://github.com/instana/nodejs/commit/4559cb82ae955d77d10e991f544bdf2c1d17fe62)) | ||
| # [4.16.0](https://github.com/instana/nodejs/compare/v4.15.3...v4.16.0) (2025-06-24) | ||
| ### Bug Fixes | ||
| * **collector:** optimized flushing spans before application dies ([#1765](https://github.com/instana/nodejs/issues/1765)) ([3507599](https://github.com/instana/nodejs/commit/35075996e879734a7bb9437c1ce375b9d979fe3a)), closes [#1315](https://github.com/instana/nodejs/issues/1315) | ||
| ## [4.15.3](https://github.com/instana/nodejs/compare/v4.15.2...v4.15.3) (2025-06-11) | ||
| ### Bug Fixes | ||
| - **aws-lambda:** resolved x86_64 build ([#1763](https://github.com/instana/nodejs/issues/1763)) ([de7769f](https://github.com/instana/nodejs/commit/de7769ff49562df42ceffa9e689dac1bfa04d1cc)) | ||
| ## [4.15.2](https://github.com/instana/nodejs/compare/v4.15.1...v4.15.2) (2025-06-11) | ||
| ### Bug Fixes | ||
| - **aws-lambda:** upgraded go version to 1.24.0 ([#1761](https://github.com/instana/nodejs/issues/1761)) ([87dc123](https://github.com/instana/nodejs/commit/87dc12338f94a657cad883bd78b8a6598d362213)) | ||
| ## [4.15.1](https://github.com/instana/nodejs/compare/v4.15.0...v4.15.1) (2025-06-09) | ||
| ### Bug Fixes | ||
| - **aws-lambda:** gracefully handled non-string path values ([#1750](https://github.com/instana/nodejs/issues/1750)) ([8625634](https://github.com/instana/nodejs/commit/86256346600ae4bffa5f982fe79dff898f4d4588)) | ||
| # [4.15.0](https://github.com/instana/nodejs/compare/v4.14.0...v4.15.0) (2025-05-27) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.14.0](https://github.com/instana/nodejs/compare/v4.13.0...v4.14.0) (2025-05-13) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.13.0](https://github.com/instana/nodejs/compare/v4.12.0...v4.13.0) (2025-05-08) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.12.0](https://github.com/instana/nodejs/compare/v4.11.1...v4.12.0) (2025-05-06) | ||
| ### Bug Fixes | ||
| - **aws-lambda:** resolved TypeError when memory is too low ([#1715](https://github.com/instana/nodejs/issues/1715)) ([03a8eb3](https://github.com/instana/nodejs/commit/03a8eb39f386af44f98c5405d668369b3736bff0)) | ||
| ## [4.11.1](https://github.com/instana/nodejs/compare/v4.11.0...v4.11.1) (2025-04-24) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.11.0](https://github.com/instana/nodejs/compare/v4.10.0...v4.11.0) (2025-04-22) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.10.0](https://github.com/instana/nodejs/compare/v4.9.0...v4.10.0) (2025-04-01) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.9.0](https://github.com/instana/nodejs/compare/v4.8.0...v4.9.0) (2025-03-20) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.8.0](https://github.com/instana/nodejs/compare/v4.7.0...v4.8.0) (2025-03-19) | ||
| ### Features | ||
| - **serverless:** added request id to instana debug logs ([#1623](https://github.com/instana/nodejs/issues/1623)) ([c5a1b69](https://github.com/instana/nodejs/commit/c5a1b691ed9f01363bbc76bc262f985a4901744e)) | ||
| # [4.7.0](https://github.com/instana/nodejs/compare/v4.6.3...v4.7.0) (2025-03-11) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.6.3](https://github.com/instana/nodejs/compare/v4.6.2...v4.6.3) (2025-03-05) | ||
| ### Bug Fixes | ||
| - **aws-lambda:** ensured tracer is properly disabled when configured ([#1593](https://github.com/instana/nodejs/issues/1593)) ([a1db8b4](https://github.com/instana/nodejs/commit/a1db8b4b79cddbe2be871cdbd81290b9879937f2)), closes [#1315](https://github.com/instana/nodejs/issues/1315) | ||
| ## [4.6.2](https://github.com/instana/nodejs/compare/v4.6.1...v4.6.2) (2025-02-24) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.6.1](https://github.com/instana/nodejs/compare/v4.6.0...v4.6.1) (2025-01-29) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.6.0](https://github.com/instana/nodejs/compare/v4.5.3...v4.6.0) (2025-01-18) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| ## [4.5.3](https://github.com/instana/nodejs/compare/v4.5.2...v4.5.3) (2025-01-14) | ||
| ### Bug Fixes | ||
| - resolved more logging objects structure ([#1510](https://github.com/instana/nodejs/issues/1510)) ([bd4c9bb](https://github.com/instana/nodejs/commit/bd4c9bbda2c82aee7f6c59fcca03ac5588566839)) | ||
| ## [4.5.2](https://github.com/instana/nodejs/compare/v4.5.1...v4.5.2) (2025-01-13) | ||
| ### Bug Fixes | ||
| - resolved logging objects being undefined or missing ([#1509](https://github.com/instana/nodejs/issues/1509)) ([7715fed](https://github.com/instana/nodejs/commit/7715fed5843716a6e49d79f221efcec33a9a1c9d)) | ||
| ## [4.5.1](https://github.com/instana/nodejs/compare/v4.5.0...v4.5.1) (2025-01-13) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.5.0](https://github.com/instana/nodejs/compare/v4.4.0...v4.5.0) (2024-12-16) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.4.0](https://github.com/instana/nodejs/compare/v4.3.0...v4.4.0) (2024-12-12) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.3.0](https://github.com/instana/nodejs/compare/v4.2.0...v4.3.0) (2024-12-10) | ||
| **Note:** Version bump only for package @instana/aws-lambda | ||
| # [4.2.0](https://github.com/instana/nodejs/compare/v4.1.0...v4.2.0) (2024-11-22) | ||
| ### Features | ||
| - **aws-lambda:** added support for Node v22 runtime ([#1456](https://github.com/instana/nodejs/issues/1456)) ([8b53e06](https://github.com/instana/nodejs/commit/8b53e06529517ec19067c7c49915f54b7e124e6c)) | ||
| # [4.1.0](https://github.com/instana/nodejs/compare/v4.0.1...v4.1.0) (2024-11-19) | ||
| ### Reverts | ||
| - Revert "ci: skipping the chinese regions from publishing lambda layers" ([8475d69](https://github.com/instana/nodejs/commit/8475d6967311308bd36cc4ce4331bcb232beb031)) | ||
| - Revert "test: updated test for aws lambda running in v24 prerelease" ([66e1d10](https://github.com/instana/nodejs/commit/66e1d10dd78f7874e33137c4c3bfaa376643a6e6)) | ||
| - Revert "ci: removed chinese regions from publishing aws lambda layer" ([d44b619](https://github.com/instana/nodejs/commit/d44b6196ed10c272aa0e5186508bb70f7faee1c5)) | ||
| ### BREAKING CHANGES | ||
| ## [4.0.1](https://github.com/instana/nodejs/compare/v4.0.0...v4.0.1) (2024-10-28) | ||
| - - Dropped support for Node.js versions 14 and 16. | ||
| ### Bug Fixes | ||
| * Reason: These versions have reached their end of life. | ||
| * More info: https://github.com/nodejs/Release?tab=readme-ov-file#end-of-life-releases | ||
| - **aws-lambda:** fixed error caused by missing aws-sdk during agent key retrieval from SSM ([#1402](https://github.com/instana/nodejs/issues/1402)) ([6329c66](https://github.com/instana/nodejs/commit/6329c6623e99d1f7eee5570dd9ebfa72bb953917)) | ||
| - - Node.js Lambda runtimes v14 and v16 are no longer supported. | ||
| ### Reverts | ||
| * Refer to the Lambda deprecation policy here: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-support-policy | ||
| - Revert "ci: skipped all other regions and only china region with debug" ([71f4643](https://github.com/instana/nodejs/commit/71f46431791c80af82e927361de9c9f5dd10e222)) | ||
| - Revert "ci: skipping the Chinese regions from publishing lambda layers" ([1099189](https://github.com/instana/nodejs/commit/1099189dbce7840d0bebcae7a881a32d58c8fb27)) | ||
@@ -29,0 +441,0 @@ # [4.0.0](https://github.com/instana/nodejs/compare/v3.21.0...v4.0.0) (2024-10-23) |
+12
-11
| { | ||
| "name": "@instana/aws-lambda", | ||
| "version": "5.0.0", | ||
| "version": "5.0.1", | ||
| "description": "Instana tracing and monitoring for Node.js based AWS Lambdas", | ||
@@ -31,4 +31,4 @@ "author": { | ||
| "test": "mocha --config=test/.mocharc.js --sort $(find test -iname '*test.js')", | ||
| "test:debug": "WITH_STDOUT=true INSTANA_DEBUG=true npm run test", | ||
| "test:ci": "mocha --config=test/.mocharc.js --reporter mocha-multi-reporters --reporter-options configFile=reporter-config.json 'test/**/*test.js'", | ||
| "test:debug": "WITH_STDOUT=true npm run test --", | ||
| "test:ci": "mocha --config=test/.mocharc.js --reporter mocha-multi-reporters --reporter-options configFile=reporter-config.json $(bash ./scripts/ci-get-test-files.sh 'test/**/*test.js')", | ||
| "lint": "eslint src test lambdas", | ||
@@ -52,10 +52,6 @@ "verify": "npm run lint && npm test", | ||
| "engines": { | ||
| "node": ">=18.0.0" | ||
| "node": ">=18.19.0" | ||
| }, | ||
| "contributors": [ | ||
| { | ||
| "name": "Willian Carvalho", | ||
| "email": "willian.carvalho@instana.com" | ||
| }, | ||
| { | ||
| "name": "Katharina Irrgang", | ||
@@ -67,2 +63,6 @@ "email": "katharina.irrgang@ibm.com" | ||
| "email": "arya.mohanan@ibm.com" | ||
| }, | ||
| { | ||
| "name": "Abhilash Sivan", | ||
| "email": "abhilash.sivan@ibm.com" | ||
| } | ||
@@ -75,6 +75,7 @@ ], | ||
| "dependencies": { | ||
| "@instana/core": "5.0.0", | ||
| "@instana/serverless": "5.0.0" | ||
| "@instana/core": "5.0.1", | ||
| "@instana/serverless": "5.0.1", | ||
| "semver": "^7.7.3" | ||
| }, | ||
| "gitHead": "209e1ac4c64c5224c99bffcc82a172c3d22e4438" | ||
| "gitHead": "77fa60d1e6d88a852540f0e88ff3a8b2e36826ac" | ||
| } |
+6
-1
@@ -19,3 +19,3 @@ /* | ||
| const { environment: environmentUtil } = require('@instana/serverless'); | ||
| const { environment: environmentUtil, consoleLogger: serverlessLogger } = require('@instana/serverless'); | ||
| const ssm = require('./ssm'); | ||
@@ -26,2 +26,7 @@ const path = require('path'); | ||
| // TODO: we currently call "log.init()" twice. Once here | ||
| // and once in the wrapper.js. Please merge. | ||
| const logger = serverlessLogger.init(); | ||
| environmentUtil.init({ logger }); | ||
| environmentUtil.validate({ | ||
@@ -28,0 +33,0 @@ validateInstanaAgentKey: ssm.validate |
+13
-11
@@ -8,24 +8,26 @@ /* | ||
| const { metrics: coreMetrics } = require('@instana/core'); | ||
| const core = require('@instana/core'); | ||
| const npmPackageName = require('./npmPackageName'); | ||
| const npmPackageVersion = require('./npmPackageVersion'); | ||
| const npmPackageDescription = require('./npmPackageDescription'); | ||
| coreMetrics.registerAdditionalMetrics([ | ||
| require('./npmPackageName'), | ||
| require('./npmPackageVersion'), | ||
| require('./npmPackageDescription') | ||
| ]); | ||
| exports.init = function init(config) { | ||
| core.metrics.init(config); | ||
| npmPackageName.init(config); | ||
| npmPackageVersion.init(config); | ||
| npmPackageDescription.init(config); | ||
| exports.init = function init(config) { | ||
| coreMetrics.init(config); | ||
| core.metrics.registerAdditionalMetrics([npmPackageName, npmPackageVersion, npmPackageDescription]); | ||
| }; | ||
| exports.activate = function activate() { | ||
| coreMetrics.activate(); | ||
| core.metrics.activate(); | ||
| }; | ||
| exports.deactivate = function deactivate() { | ||
| coreMetrics.deactivate(); | ||
| core.metrics.deactivate(); | ||
| }; | ||
| exports.gatherData = function gatherData() { | ||
| return coreMetrics.gatherData(); | ||
| return core.metrics.gatherData(); | ||
| }; |
@@ -9,4 +9,2 @@ /* | ||
| const { util: coreUtil } = require('@instana/core'); | ||
| const { consoleLogger: logger } = require('@instana/serverless'); | ||
| const rootDir = require('./rootDir'); | ||
@@ -17,6 +15,12 @@ | ||
| let logger; | ||
| exports.init = config => { | ||
| logger = config.logger; | ||
| }; | ||
| exports.activate = function activate() { | ||
| coreUtil.applicationUnderMonitoring.getMainPackageJsonStartingAtDirectory(rootDir.root, (err, pckg) => { | ||
| if (err) { | ||
| logger.warn('Failed to determine main package json. Reason: ', err.message, err.stack); | ||
| logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); | ||
| } | ||
@@ -23,0 +27,0 @@ |
@@ -9,4 +9,2 @@ /* | ||
| const { util: coreUtil } = require('@instana/core'); | ||
| const { consoleLogger: logger } = require('@instana/serverless'); | ||
| const rootDir = require('./rootDir'); | ||
@@ -17,6 +15,12 @@ | ||
| let logger; | ||
| exports.init = config => { | ||
| logger = config.logger; | ||
| }; | ||
| exports.activate = function activate() { | ||
| coreUtil.applicationUnderMonitoring.getMainPackageJsonStartingAtDirectory(rootDir.root, (err, pckg) => { | ||
| if (err) { | ||
| logger.warn('Failed to determine main package json. Reason: ', err.message, err.stack); | ||
| logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); | ||
| } | ||
@@ -23,0 +27,0 @@ |
@@ -9,4 +9,2 @@ /* | ||
| const { util: coreUtil } = require('@instana/core'); | ||
| const { consoleLogger: logger } = require('@instana/serverless'); | ||
| const rootDir = require('./rootDir'); | ||
@@ -17,6 +15,12 @@ | ||
| let logger; | ||
| exports.init = config => { | ||
| logger = config.logger; | ||
| }; | ||
| exports.activate = function activate() { | ||
| coreUtil.applicationUnderMonitoring.getMainPackageJsonStartingAtDirectory(rootDir.root, (err, pckg) => { | ||
| if (err) { | ||
| logger.warn('Failed to determine main package json. Reason: ', err.message, err.stack); | ||
| logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); | ||
| } | ||
@@ -23,0 +27,0 @@ |
@@ -11,5 +11,3 @@ /* | ||
| const instanaCore = require('@instana/core'); | ||
| const { tracing } = instanaCore; | ||
| let config; | ||
@@ -23,3 +21,2 @@ exports.wrap = noopWrap; | ||
| } | ||
| config = _config || {}; | ||
@@ -35,7 +32,6 @@ return originalHandler; | ||
| exports.setLogger = function setLogger(logger) { | ||
| config.logger = logger; | ||
| instanaCore.logger.init(config); | ||
| exports.setLogger = function setLogger() { | ||
| // We do nothing. Noop. | ||
| }; | ||
| exports.opentracing = tracing.opentracing; |
+45
-47
@@ -13,2 +13,3 @@ /* | ||
| let initTimeoutInMs = 0; | ||
| let logger; | ||
@@ -36,6 +37,6 @@ module.exports.reset = () => { | ||
| module.exports.init = ({ logger }) => { | ||
| let AWS; | ||
| module.exports.init = config => { | ||
| logger = config.logger; | ||
| // CASE: Customer did not set INSTANA_SSM_PARAM_NAME, skip | ||
| // CASE: INSTANA_SSM_PARAM_NAME is not set, skip | ||
| if (!exports.isUsed()) { | ||
@@ -54,18 +55,17 @@ return; | ||
| /** | ||
| * From https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html: | ||
| * As per AWS Lambda Node.js documentation: https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html | ||
| * The environment includes the AWS SDK for JavaScript, with credentials from an IAM role that you manage. | ||
| * | ||
| * Your code runs in an environment that includes the AWS SDK for JavaScript, | ||
| * with credentials from an AWS Identity and Access Management (IAM) role that you manage. | ||
| * https://aws.amazon.com/blogs/compute/node-js-18-x-runtime-now-available-in-aws-lambda/ | ||
| */ | ||
| // eslint-disable-next-line instana/no-unsafe-require, import/no-extraneous-dependencies | ||
| AWS = require('aws-sdk'); | ||
| // eslint-disable-next-line import/no-extraneous-dependencies, instana/no-unsafe-require, prefer-const | ||
| const { SSMClient, GetParameterCommand } = require('@aws-sdk/client-ssm'); | ||
| // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html | ||
| const ssm = new AWS.SSM({ region: process.env.AWS_REGION }); | ||
| const params = { | ||
| Name: envValue, | ||
| /** | ||
| * See https://docs.aws.amazon.com/cli/latest/reference/ssm/get-parameter.html#options | ||
| * The value in the parameter store was either created with type "string" or "safestring" | ||
| * A "safestring" uses a KMS key to encrypt/decrypt the value in the store. | ||
| * For more details, see: | ||
| * https://docs.aws.amazon.com/cli/latest/reference/ssm/get-parameter.html#options | ||
| * The parameter in the store is either a "string" or a "SecureString". | ||
| * A "SecureString" uses a KMS key for encryption/decryption. | ||
| */ | ||
@@ -75,28 +75,25 @@ WithDecryption: process.env[ENV_DECRYPTION] === 'true' | ||
| logger.debug(`INSTANA_SSM_PARAM_NAME is ${envValue}.`); | ||
| ssm.getParameter(params, (err, data) => { | ||
| if (err) { | ||
| errorFromAWS = `Error from AWS-SDK SSM Parameter Store: ${err.message}`; | ||
| } else { | ||
| try { | ||
| // CASE: Customer created key with decryption KMS key, but does not tell us | ||
| if (data.Parameter.Type === 'SecureString' && process.env[ENV_DECRYPTION] !== 'true') { | ||
| errorFromAWS = 'SSM Key is a SecureString. Please pass INSTANA_SSM_DECRYPTION=true'; | ||
| } else { | ||
| fetchedValue = data.Parameter.Value; | ||
| errorFromAWS = null; | ||
| logger.debug(`INSTANA AGENT KEY: ${fetchedValue}`); | ||
| } | ||
| } catch (readError) { | ||
| errorFromAWS = `Could not read returned response from AWS-SDK SSM Parameter Store: ${readError.message}`; | ||
| logger.debug(`INSTANA_SSM_PARAM_NAME is ${process.env.INSTANA_SSM_PARAM_NAME}.`); | ||
| const client = new SSMClient({ region: process.env.AWS_REGION }); | ||
| const command = new GetParameterCommand(params); | ||
| client | ||
| .send(command) | ||
| .then(response => { | ||
| // CASE: The parameter is of type SecureString, but decryption wasn't specified | ||
| if (response.Parameter.Type === 'SecureString' && process.env[ENV_DECRYPTION] !== 'true') { | ||
| errorFromAWS = 'The SSM parameter is a SecureString. Please set INSTANA_SSM_DECRYPTION=true.'; | ||
| } else { | ||
| fetchedValue = response.Parameter.Value; | ||
| errorFromAWS = null; | ||
| logger.debug(`INSTANA AGENT KEY: ${fetchedValue}`); | ||
| } | ||
| } | ||
| }); | ||
| }) | ||
| .catch(error => { | ||
| errorFromAWS = `Could not read returned response from AWS-SDK SSM Parameter Store: ${error.message}`; | ||
| }); | ||
| } catch (err) { | ||
| logger.warn('AWS SDK not available.'); | ||
| logger.warn('AWS SDK is not available.'); | ||
| errorFromAWS = | ||
| 'Could not fetch instana key from SSM parameter store using ' + | ||
| `"${process.env.INSTANA_SSM_PARAM_NAME}", because the AWS SDK is not available. ` + | ||
| `Reason: ${err.message}`; | ||
| `Unable to fetch the Instana key from the SSM Parameter Store using "${process.env.INSTANA_SSM_PARAM_NAME}",` + | ||
| ` as the AWS SDK is unavailable. Reason: ${err?.message}`; | ||
| } | ||
@@ -110,3 +107,3 @@ }; | ||
| } | ||
| // CASE: Customer has set INSTANA_SSM_PARAM_NAME, but we were not able to fetch the value from AWS | ||
| // CASE: INSTANA_SSM_PARAM_NAME was set, but AWS response could not be fetched | ||
| if (errorFromAWS) { | ||
@@ -117,6 +114,8 @@ return callback(errorFromAWS); | ||
| const endInMs = Date.now(); | ||
| const awsTimeoutInMs = process.env.INSTANA_AWS_SSM_TIMEOUT_IN_MS ? Number(process.env.INSTANA_AWS_SSM_TIMEOUT) : 1000; | ||
| const awsTimeoutInMs = process.env.INSTANA_AWS_SSM_TIMEOUT_IN_MS | ||
| ? Number(process.env.INSTANA_AWS_SSM_TIMEOUT_IN_MS) | ||
| : 1000; | ||
| // CASE: the time between ssm lib initialisation and waitAndGetInstanaKey call | ||
| // (which is the end of the customers lambda handler) is already too big to wait for the AWS response | ||
| // CASE: The time between SSM initialization and waitAndGetInstanaKey is too long to wait for the AWS response. | ||
| // See init fn - we fetch the key as early as possible. | ||
| if (endInMs - initTimeoutInMs > awsTimeoutInMs) { | ||
@@ -127,9 +126,8 @@ return callback(`Stopped waiting for AWS SSM response after ${awsTimeoutInMs}ms.`); | ||
| /** | ||
| * Inside AWS the call to `getParameter` mostly takes 30-50ms | ||
| * Because we initialise the fetch already before the customer's handler is called, | ||
| * the chance is very high that the interval is not even used. | ||
| * | ||
| * In our tests it takes usually ~>150ms (remote call) | ||
| * The `GetParameterCommand` call in AWS typically takes about 80 to 500ms. | ||
| * This fetching process starts before the customer's handler is invoked, | ||
| * and a delay was noticed during a cold start, so this interval may be significant in that case. | ||
| * However, it's unlikely that this interval will be needed in other scenarios. | ||
| */ | ||
| let stopIntervalAfterMs = 250; | ||
| let stopIntervalAfterMs = 500; | ||
| let ssmTimeOutEnv = process.env.INSTANA_LAMBDA_SSM_TIMEOUT_IN_MS; | ||
@@ -140,3 +138,3 @@ | ||
| // NOTE: Customer could set the timeout higher than the lambda timeout, but that is up to him | ||
| // NOTE: The customer might set a timeout greater than the Lambda timeout | ||
| if (!isNaN(ssmTimeOutEnv)) { | ||
@@ -143,0 +141,0 @@ stopIntervalAfterMs = ssmTimeOutEnv; |
+31
-5
@@ -23,3 +23,8 @@ /* | ||
| const awsLambdaFunctionUrlHostRegex = /^.*\.lambda-url\..*\.on\.aws$/i; | ||
| let logger; | ||
| module.exports.init = config => { | ||
| logger = config.logger; | ||
| }; | ||
| exports.enrichSpanWithTriggerData = function enrichSpanWithTriggerData(event, context, span) { | ||
@@ -109,4 +114,4 @@ if (isApiGatewayProxyTrigger(event)) { | ||
| method: requestCtxHttp.method, | ||
| url: requestCtxHttp.path, | ||
| path_tpl: event.rawPath, | ||
| url: normalizePath(requestCtxHttp.path), | ||
| path_tpl: normalizePath(event.rawPath), | ||
| params: readHttpQueryParams(event), | ||
@@ -118,4 +123,4 @@ header: captureHeaders(event) | ||
| method: event.httpMethod, | ||
| url: event.path, | ||
| path_tpl: event.resource, | ||
| url: normalizePath(event.path), | ||
| path_tpl: normalizePath(event.resource), | ||
| params: readHttpQueryParams(event), | ||
@@ -127,2 +132,23 @@ header: captureHeaders(event) | ||
| // Ensures the `path` value is always a string. The backend expects `path` to be a string, | ||
| // so we convert any non-string (for example, an empty object) to null. | ||
| // For reference, see AWS documentation on the Lambda event input format for API Gateway and Function URLs: | ||
| // eslint-disable-next-line max-len | ||
| // https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format | ||
| // https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html#urls-payloads | ||
| function normalizePath(value) { | ||
| if (typeof value === 'string') { | ||
| return value; | ||
| } | ||
| logger.debug( | ||
| `Received a non-string value for the "path" field in the incoming request event: ${JSON.stringify(value)}. ` + | ||
| 'Expected a string, as per AWS API Gateway event structure. See: ' + | ||
| // eslint-disable-next-line max-len | ||
| 'https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format. ' + | ||
| 'This likely indicates a misconfiguration on the AWS side and may result in incomplete or broken traces ' + | ||
| 'in the Instana UI.' | ||
| ); | ||
| return null; | ||
| } | ||
| function readHttpQueryParams(event) { | ||
@@ -422,3 +448,3 @@ if (event.version === '2.0') { | ||
| method: requestCtxHttp.method, | ||
| url: requestCtxHttp.path, | ||
| url: normalizePath(requestCtxHttp.path), | ||
| params: readHttpQueryParams(event), | ||
@@ -425,0 +451,0 @@ header: captureHeaders(event) |
+99
-44
@@ -8,4 +8,6 @@ /* | ||
| // eslint-disable-next-line instana/no-unsafe-require | ||
| const semver = require('semver'); | ||
| const instanaCore = require('@instana/core'); | ||
| const { backendConnector, consoleLogger, environment } = require('@instana/serverless'); | ||
| const { backendConnector, consoleLogger: serverlessLogger, environment } = require('@instana/serverless'); | ||
| const arnParser = require('./arn'); | ||
@@ -15,16 +17,24 @@ const identityProvider = require('./identity_provider'); | ||
| const ssm = require('./ssm'); | ||
| const { enrichSpanWithTriggerData, readTraceCorrelationData } = require('./triggers'); | ||
| const triggers = require('./triggers'); | ||
| const processResult = require('./process_result'); | ||
| const captureHeaders = require('./capture_headers'); | ||
| const { tracing } = instanaCore; | ||
| const { tracing, coreConfig } = instanaCore; | ||
| const { tracingHeaders, constants, spanBuffer } = tracing; | ||
| let logger = consoleLogger; | ||
| let config; | ||
| const lambdaConfigDefaults = { | ||
| tracing: { forceTransmissionStartingAt: 25, transmissionDelay: 100, initialTransmissionDelay: 100 } | ||
| }; | ||
| // Node.js 24+ removed support for callback-based handlers (3 parameters). | ||
| const latestRuntime = semver.gte(process.version, '24.0.0'); | ||
| const logger = serverlessLogger.init(); | ||
| coreConfig.init(logger); | ||
| let config = coreConfig.normalize({}, lambdaConfigDefaults); | ||
| let coldStart = true; | ||
| // Initialize instrumentations early to allow for require statements after our package has been required but before the | ||
| // actual instana.wrap(...) call. | ||
| instanaCore.preInit(); | ||
| // Initialize instrumentations early to allow for require statements after our | ||
| // package has been required but before the actual instana.wrap(...) call. | ||
| instanaCore.preInit(config); | ||
@@ -43,4 +53,2 @@ /** | ||
| // Apparently the AWS Lambda Node.js runtime does not inspect the handlers signature for the number of arguments it | ||
| // accepts. But to be extra safe, we strive to return a function with the same number of arguments anyway. | ||
| switch (originalHandler.length) { | ||
@@ -59,6 +67,14 @@ case 0: | ||
| }; | ||
| default: | ||
| return function handler3(event, context, callback) { | ||
| default: { | ||
| if (latestRuntime) { | ||
| // Required for Node.js 24+: callback is not allowed | ||
| return function handlerAsync(event, context) { | ||
| return shimmedHandler(originalHandler, this, arguments, _config); | ||
| }; | ||
| } | ||
| // For Node.js < 24, allow callback-based handlers | ||
| return function handlerCallback(event, context, callback) { | ||
| return shimmedHandler(originalHandler, this, arguments, _config); | ||
| }; | ||
| } | ||
| } | ||
@@ -72,5 +88,22 @@ }; | ||
| // For Node.js 24+, if handler expects callback but runtime doesn't provide one, | ||
| // skip wrapping and return handler directly | ||
| const handlerExpectsCallback = originalHandler?.length >= 3; | ||
| if (latestRuntime && handlerExpectsCallback && !lambdaCallback) { | ||
| // eslint-disable-next-line no-console | ||
| logger.warn( | ||
| `Callback-based Lambda handlers are not supported in Node.js ${process.version}. ` + | ||
| 'Skipping Instana instrumentation. Please migrate to async/await or promise-based handlers.' | ||
| ); | ||
| return originalHandler.apply(originalThis, originalArgs); | ||
| } | ||
| const arnInfo = arnParser(context); | ||
| init(event, arnInfo, _config); | ||
| const tracingEnabled = init(event, arnInfo, _config); | ||
| if (!tracingEnabled) { | ||
| return originalHandler.apply(originalThis, originalArgs); | ||
| } | ||
| // The AWS lambda runtime does not seem to inspect the number of arguments the handler function expects. Instead, it | ||
@@ -83,5 +116,7 @@ // always call the handler with three arguments (event, context, callback), no matter if the handler will use the | ||
| // wrap the given callback _and_ return an instrumented promise. | ||
| // | ||
| // Note: In Node.js 24+, the runtime only passes 2 parameters (event, context) and doesn't provide a callback. | ||
| let handlerHasFinished = false; | ||
| return tracing.getCls().ns.runPromiseOrRunAndReturn(() => { | ||
| const traceCorrelationData = readTraceCorrelationData(event, context); | ||
| const traceCorrelationData = triggers.readTraceCorrelationData(event, context); | ||
| const tracingSuppressed = traceCorrelationData.level === '0'; | ||
@@ -105,11 +140,9 @@ const w3cTraceContext = traceCorrelationData.w3cTraceContext; | ||
| } else { | ||
| entrySpan = tracing | ||
| .getCls() | ||
| .startSpan( | ||
| 'aws.lambda.entry', | ||
| constants.ENTRY, | ||
| traceCorrelationData.traceId, | ||
| traceCorrelationData.parentId, | ||
| w3cTraceContext | ||
| ); | ||
| entrySpan = tracing.getCls().startSpan({ | ||
| spanName: 'aws.lambda.entry', | ||
| kind: constants.ENTRY, | ||
| traceId: traceCorrelationData.traceId, | ||
| parentSpanId: traceCorrelationData.parentId, | ||
| w3cTraceContext: w3cTraceContext | ||
| }); | ||
| tracingHeaders.setSpanAttributes(entrySpan, traceCorrelationData); | ||
@@ -129,3 +162,3 @@ const { arn, alias } = arnInfo; | ||
| } | ||
| enrichSpanWithTriggerData(event, context, entrySpan); | ||
| triggers.enrichSpanWithTriggerData(event, context, entrySpan); | ||
| } | ||
@@ -245,18 +278,20 @@ | ||
| function init(event, arnInfo, _config) { | ||
| config = _config || {}; | ||
| const userConfig = _config || {}; | ||
| if (config.logger) { | ||
| logger = config.logger; | ||
| } else { | ||
| config.logger = logger; | ||
| // CASE: customer provides a custom logger or custom level | ||
| if (userConfig.logger || userConfig.level) { | ||
| serverlessLogger.init(userConfig); | ||
| } | ||
| // NOTE: We accept for `process.env.INSTANA_DEBUG` any string value - does not have to be "true". | ||
| if (process.env.INSTANA_DEBUG || config.level || process.env.INSTANA_LOG_LEVEL) { | ||
| logger.setLevel(process.env.INSTANA_DEBUG ? 'debug' : config.level || process.env.INSTANA_LOG_LEVEL); | ||
| // NOTE: We SHOULD renormalize because of: | ||
| // - in-code _config object | ||
| // - late env variables (less likely) | ||
| // - custom logger | ||
| // - we always renormalize unconditionally to ensure safety. | ||
| config = coreConfig.normalize(userConfig, lambdaConfigDefaults); | ||
| if (!config.tracing.enabled) { | ||
| return false; | ||
| } | ||
| ssm.init({ logger }); | ||
| identityProvider.init(arnInfo); | ||
| const useLambdaExtension = shouldUseLambdaExtension(); | ||
@@ -272,7 +307,22 @@ if (useLambdaExtension) { | ||
| backendConnector.init(identityProvider, logger, true, false, 500, useLambdaExtension); | ||
| identityProvider.init(arnInfo); | ||
| triggers.init(config); | ||
| backendConnector.init({ | ||
| config, | ||
| identityProvider, | ||
| defaultTimeout: 500, | ||
| useLambdaExtension, | ||
| isLambdaRequest: true, | ||
| // NOTE: We only retry for the extension, because if the extenion is not used, the time to transmit | ||
| // the data to the serverless acceptor directly takes too long. | ||
| retries: !!useLambdaExtension | ||
| }); | ||
| // instanaCore.init also normalizes the config as a side effect | ||
| instanaCore.init(config, backendConnector, identityProvider); | ||
| // After core init, because ssm requires require('@aws-sdk/client-ssm'), which triggers | ||
| // the requireHook + shimmer. Any module which requires another external module has to be | ||
| // initialized after the core. | ||
| ssm.init(config); | ||
| spanBuffer.setIsFaaS(true); | ||
@@ -283,2 +333,4 @@ captureHeaders.init(config); | ||
| tracing.activate(); | ||
| return true; | ||
| } | ||
@@ -335,2 +387,5 @@ | ||
| // NOTE: This function only "guesses" whether the Lambda extension should be used or not. | ||
| // TODO: Figure out how we can reliably determine whether the Lambda extension should be | ||
| // used or not e.g. by checking the lambda handler name if that is possible. | ||
| function shouldUseLambdaExtension() { | ||
@@ -429,3 +484,3 @@ if (process.env.INSTANA_DISABLE_LAMBDA_EXTENSION) { | ||
| */ | ||
| function postHandler(entrySpan, error, result, callback) { | ||
| function postHandler(entrySpan, error, result, postHandlerDone) { | ||
| // entrySpan is null when tracing is suppressed due to X-Instana-L | ||
@@ -438,3 +493,3 @@ if (entrySpan) { | ||
| // let it finish. | ||
| callback(); | ||
| postHandlerDone(); | ||
| return; | ||
@@ -483,3 +538,6 @@ } | ||
| finalLambdaRequest: true, | ||
| callback | ||
| callback: () => { | ||
| // We don't process or care if there is an error returned from the backend connector right now. | ||
| postHandlerDone(); | ||
| } | ||
| }); | ||
@@ -537,8 +595,5 @@ } | ||
| exports.setLogger = function setLogger(_logger) { | ||
| logger = _logger; | ||
| config.logger = logger; | ||
| instanaCore.logger.init(config); | ||
| backendConnector.setLogger(logger); | ||
| serverlessLogger.init({ logger: _logger }); | ||
| }; | ||
| exports.opentracing = tracing.opentracing; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 14 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
100795
20.38%1445
6.09%21
-12.5%5
-16.67%3
50%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated