From 60f3bb960f909e0640b372de97c8f6d7c1654038 Mon Sep 17 00:00:00 2001 From: gurke Date: Mon, 12 Jun 2023 16:16:42 +0200 Subject: [PATCH] feat(collector): added node:fs, restify and socket.io support (OpenTelemetry integration) (#715) refs #109122 --- package-lock.json | 1346 ++++++++++++++++- package.json | 3 + .../autoprofile/lib/samplers/async_sampler.js | 2 +- packages/autoprofile/package.json | 1 + packages/aws-lambda-auto-wrap/package.json | 3 +- packages/aws-lambda-auto-wrap/src/utils.js | 3 +- packages/collector/src/actions/source.js | 2 +- packages/collector/src/agentConnection.js | 30 +- packages/collector/src/cmdline.js | 2 +- packages/collector/src/pidStore/index.js | 2 +- .../instrumentation/process/selfPath.js | 2 +- packages/collector/test/bazel_inode_test.js | 9 +- packages/collector/test/cmdline_test.js | 4 +- packages/collector/test/opentelemetry/app.js | 12 +- .../collector/test/pidStore/pidStore_test.js | 4 +- .../cloud/aws-sdk/v2/sqs/receiveMessage.js | 12 +- .../tracing/cloud/aws-sdk/v2/sqs/sqsUtil.js | 1 - .../test/tracing/control_flow/q/test.js | 10 +- .../test/tracing/database/db2/test.js | 35 +- .../test/tracing/logger/bunyan/test.js | 9 +- .../tracing/open_tracing/integration_test.js | 15 +- .../test/tracing/opentelemetry/fs-app.js | 48 + .../test/tracing/opentelemetry/restify-app.js | 79 + .../tracing/opentelemetry/socketio-client.js | 36 + .../tracing/opentelemetry/socketio-server.js | 57 + .../test/tracing/opentelemetry/test.js | 460 ++++++ packages/core/.eslintignore | 1 + packages/core/package-lock.json | 390 +++++ packages/core/package.json | 6 + packages/core/src/index.js | 3 + packages/core/src/metrics/index.js | 2 +- packages/core/src/tracing/index.js | 8 + .../files/NonRecordingSpan.js | 61 + .../files/invalid-span-constants.js | 26 + .../files/trace_flags.js | 25 + .../opentelemetry-instrumentations/fs.js | 47 + .../opentelemetry-instrumentations/index.js | 11 + .../opentelemetry-instrumentations/restify.js | 33 + .../socket.io.js | 50 + .../opentelemetry-instrumentations/wrap.js | 92 ++ packages/core/src/uninstrumentedFs.js | 10 + .../src/util/applicationUnderMonitoring.js | 2 +- packages/core/src/util/normalizeConfig.js | 22 + .../test/test_util/common_verifications.js | 71 +- .../core/test/util/normalizeConfig_test.js | 31 + .../google-cloud-run/test/using_api/app.js | 7 +- .../google-cloud-run/test/using_api/test.js | 3 +- packages/shared-metrics/src/dependencies.js | 9 +- .../shared-metrics/src/directDependencies.js | 6 +- .../src/util/DependencyDistanceCalculator.js | 4 +- .../src/util/nativeModuleRetry.js | 4 +- .../test/activeRequests_test.js | 2 +- 52 files changed, 3024 insertions(+), 89 deletions(-) create mode 100644 packages/collector/test/tracing/opentelemetry/fs-app.js create mode 100644 packages/collector/test/tracing/opentelemetry/restify-app.js create mode 100644 packages/collector/test/tracing/opentelemetry/socketio-client.js create mode 100644 packages/collector/test/tracing/opentelemetry/socketio-server.js create mode 100644 packages/collector/test/tracing/opentelemetry/test.js create mode 100644 packages/core/.eslintignore create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/files/NonRecordingSpan.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/files/invalid-span-constants.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/files/trace_flags.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/fs.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/index.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/restify.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/socket.io.js create mode 100644 packages/core/src/tracing/opentelemetry-instrumentations/wrap.js create mode 100644 packages/core/src/uninstrumentedFs.js diff --git a/package-lock.json b/package-lock.json index 594a9d87c9..9004251def 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,10 +144,13 @@ "request": "^2.88.0", "request-promise": "^4.2.2", "request-promise-native": "^1.0.5", + "restify": "^8.6.1", "rimraf": "^3.0.2", "sequelize": "^6.17.0", "sinon": "^11.1.1", "sinon-chai": "^3.7.0", + "socket.io": "^4.6.0", + "socket.io-client": "^4.6.0", "sqs-consumer": "5.7.0", "sqs-consumer-v6": "npm:sqs-consumer@^6.2.0", "superagent": "^6.1.0", @@ -17354,6 +17357,26 @@ "node": ">= 10" } }, + "node_modules/@netflix/nerror": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.3.tgz", + "integrity": "sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "extsprintf": "^1.4.0", + "lodash": "^4.17.15" + } + }, + "node_modules/@netflix/nerror/node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -19963,6 +19986,12 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -20361,6 +20390,12 @@ "integrity": "sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==", "dev": true }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, "node_modules/@types/cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", @@ -22821,6 +22856,15 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -23465,10 +23509,10 @@ "version": "1.8.15", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", + "devOptional": true, "engines": [ "node >=0.10.0" ], - "optional": true, "bin": { "bunyan": "bin/bunyan" }, @@ -25567,9 +25611,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, "engines": { "node": ">= 0.6" @@ -26010,6 +26054,39 @@ "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=", "dev": true }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, "node_modules/currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -26700,6 +26777,12 @@ "node": ">=0.10" } }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, "node_modules/dev-null": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", @@ -27084,6 +27167,104 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz", + "integrity": "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/engine.io-parser": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", + "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -27351,6 +27532,12 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, + "node_modules/escape-regexp-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", + "integrity": "sha512-B0yxafj1D1ZTNEHkFoQxz4iboZSfaZHhaNhIug7GcUCL4ZUrVSJZTmWUAkPOFaYDfi3RNT9XM082TuGE6jpmiQ==", + "dev": true + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -28318,6 +28505,15 @@ "node": ">=0.4.x" } }, + "node_modules/ewma": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", + "integrity": "sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -31690,6 +31886,12 @@ "node": ">=12.0.0" } }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -32120,6 +32322,48 @@ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/hpagent": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", @@ -32191,6 +32435,12 @@ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "dev": true }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, "node_modules/http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -36004,6 +36254,12 @@ "node": ">=4" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -36245,6 +36501,15 @@ "node": ">=0.10.0" } }, + "node_modules/mixme": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.9.tgz", + "integrity": "sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/mkdirp": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", @@ -39563,6 +39828,12 @@ "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", "dev": true }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, "node_modules/octokit-pagination-methods": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", @@ -40894,6 +41165,38 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pidusage/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -43221,6 +43524,187 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restify": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/restify/-/restify-8.6.1.tgz", + "integrity": "sha512-I54/Geo2qN4K/2Ers+zNAU/A/nwPrcoTVBVeamw/sROv/kLLuMAzidLmO3f6842tKFxxQvcNhOMYoWZAhYr3vQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "bunyan": "^1.8.12", + "csv": "^5.1.1", + "escape-regexp-component": "^1.0.2", + "ewma": "^2.0.1", + "find-my-way": "^2.0.1", + "formidable": "^1.2.1", + "http-signature": "^1.2.0", + "lodash": "^4.17.11", + "lru-cache": "^5.1.1", + "mime": "^2.4.3", + "negotiator": "^0.6.2", + "once": "^1.4.0", + "pidusage": "^2.0.17", + "qs": "^6.7.0", + "restify-errors": "^8.0.2", + "semver": "^6.1.1", + "send": "^0.16.2", + "spdy": "^4.0.0", + "uuid": "^3.3.2", + "vasync": "^2.2.0" + }, + "bin": { + "report-latency": "bin/report-latency" + }, + "engines": { + "node": ">=8.3.0" + }, + "optionalDependencies": { + "dtrace-provider": "^0.8.1" + } + }, + "node_modules/restify-errors": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-8.0.2.tgz", + "integrity": "sha512-UsXUVQo7M26xoQzeUcZQ0+H8L2t9DGzrXcAgR3WB/1vnbl+UdI4tZ1PqYsN+sS5WnqHKZ0Xy9w0CKf83bbrwYA==", + "dev": true, + "dependencies": { + "@netflix/nerror": "^1.0.0", + "assert-plus": "^1.0.0", + "lodash": "^4.17.15" + }, + "optionalDependencies": { + "safe-json-stringify": "^1.0.4" + } + }, + "node_modules/restify/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, + "node_modules/restify/node_modules/find-my-way": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.5.tgz", + "integrity": "sha512-GjRZZlGcGmTh9t+6Xrj5K0YprpoAFCAiCPgmAH9Kb09O4oX6hYuckDfnDipYj+Q7B1GtYWSzDI5HEecNYscLQg==", + "dev": true, + "dependencies": { + "fast-decode-uri-component": "^1.0.0", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/restify/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/restify/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/restify/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/restify/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/restify/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/restify/node_modules/send/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "bin": { + "mime": "cli.js" + } + }, + "node_modules/restify/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/restify/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/restify/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/restify/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -43541,6 +44025,12 @@ "dev": true, "optional": true }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, "node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -44251,6 +44741,129 @@ "@napi-rs/snappy-win32-x64-msvc": "7.2.2" } }, + "node_modules/socket.io": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", + "integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.4.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dev": true, + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.2.tgz", + "integrity": "sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.4.0", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-client/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -44498,6 +45111,82 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -44769,6 +45458,15 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "dependencies": { + "mixme": "^0.5.1" + } + }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -46832,6 +47530,18 @@ "node": ">= 0.8" } }, + "node_modules/vasync": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz", + "integrity": "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "verror": "1.10.0" + } + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -46908,6 +47618,15 @@ "foreachasync": "^3.0.0" } }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -47458,6 +48177,15 @@ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xorshift": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", @@ -62033,6 +62761,25 @@ "optional": true, "peer": true }, + "@netflix/nerror": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.3.tgz", + "integrity": "sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "extsprintf": "^1.4.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -64027,6 +64774,12 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, "@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -64363,6 +65116,12 @@ "integrity": "sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==", "dev": true }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, "@types/cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", @@ -66467,6 +67226,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -66982,7 +67747,7 @@ "version": "1.8.15", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", - "optional": true, + "devOptional": true, "requires": { "dtrace-provider": "~0.8", "moment": "^2.19.3", @@ -68651,9 +69416,9 @@ } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true }, "cookie-signature": { @@ -68989,6 +69754,36 @@ "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=", "dev": true }, + "csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "requires": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + } + }, + "csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -69515,6 +70310,12 @@ "dev": true, "optional": true }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, "dev-null": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", @@ -69846,6 +70647,86 @@ "once": "^1.4.0" } }, + "engine.io": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0" + }, + "dependencies": { + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "engine.io-client": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.4.0.tgz", + "integrity": "sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", + "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", + "dev": true + }, "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -70067,6 +70948,12 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, + "escape-regexp-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", + "integrity": "sha512-B0yxafj1D1ZTNEHkFoQxz4iboZSfaZHhaNhIug7GcUCL4ZUrVSJZTmWUAkPOFaYDfi3RNT9XM082TuGE6jpmiQ==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -70782,6 +71669,15 @@ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", "dev": true }, + "ewma": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ewma/-/ewma-2.0.1.tgz", + "integrity": "sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -73454,6 +74350,12 @@ "jws": "^4.0.0" } }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -73775,6 +74677,50 @@ "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "hpagent": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", @@ -73831,6 +74777,12 @@ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "dev": true }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -76855,6 +77807,12 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -77064,6 +78022,12 @@ } } }, + "mixme": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.9.tgz", + "integrity": "sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==", + "dev": true + }, "mkdirp": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", @@ -79562,6 +80526,12 @@ "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", "dev": true }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, "octokit-pagination-methods": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", @@ -80580,6 +81550,23 @@ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, + "pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "dev": true, + "requires": { + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -82383,6 +83370,153 @@ "lowercase-keys": "^2.0.0" } }, + "restify": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/restify/-/restify-8.6.1.tgz", + "integrity": "sha512-I54/Geo2qN4K/2Ers+zNAU/A/nwPrcoTVBVeamw/sROv/kLLuMAzidLmO3f6842tKFxxQvcNhOMYoWZAhYr3vQ==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "bunyan": "^1.8.12", + "csv": "^5.1.1", + "dtrace-provider": "^0.8.1", + "escape-regexp-component": "^1.0.2", + "ewma": "^2.0.1", + "find-my-way": "^2.0.1", + "formidable": "^1.2.1", + "http-signature": "^1.2.0", + "lodash": "^4.17.11", + "lru-cache": "^5.1.1", + "mime": "^2.4.3", + "negotiator": "^0.6.2", + "once": "^1.4.0", + "pidusage": "^2.0.17", + "qs": "^6.7.0", + "restify-errors": "^8.0.2", + "semver": "^6.1.1", + "send": "^0.16.2", + "spdy": "^4.0.0", + "uuid": "^3.3.2", + "vasync": "^2.2.0" + }, + "dependencies": { + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true + }, + "find-my-way": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-2.2.5.tgz", + "integrity": "sha512-GjRZZlGcGmTh9t+6Xrj5K0YprpoAFCAiCPgmAH9Kb09O4oX6hYuckDfnDipYj+Q7B1GtYWSzDI5HEecNYscLQg==", + "dev": true, + "requires": { + "fast-decode-uri-component": "^1.0.0", + "safe-regex2": "^2.0.0", + "semver-store": "^0.3.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + } + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "restify-errors": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/restify-errors/-/restify-errors-8.0.2.tgz", + "integrity": "sha512-UsXUVQo7M26xoQzeUcZQ0+H8L2t9DGzrXcAgR3WB/1vnbl+UdI4tZ1PqYsN+sS5WnqHKZ0Xy9w0CKf83bbrwYA==", + "dev": true, + "requires": { + "@netflix/nerror": "^1.0.0", + "assert-plus": "^1.0.0", + "lodash": "^4.17.15", + "safe-json-stringify": "^1.0.4" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -82636,6 +83770,12 @@ "dev": true, "optional": true }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -83182,6 +84322,102 @@ "@napi-rs/snappy-win32-x64-msvc": "7.2.2" } }, + "socket.io": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", + "integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.4.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dev": true, + "requires": { + "ws": "~8.11.0" + } + }, + "socket.io-client": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.6.2.tgz", + "integrity": "sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.4.0", + "socket.io-parser": "~4.2.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -83392,6 +84628,67 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -83604,6 +84901,15 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "requires": { + "mixme": "^0.5.1" + } + }, "streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -85231,6 +86537,15 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "vasync": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz", + "integrity": "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==", + "dev": true, + "requires": { + "verror": "1.10.0" + } + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -85281,6 +86596,15 @@ "foreachasync": "^3.0.0" } }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -85706,6 +87030,12 @@ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "dev": true + }, "xorshift": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", diff --git a/package.json b/package.json index dbe4f2e55d..34f2172665 100644 --- a/package.json +++ b/package.json @@ -191,10 +191,13 @@ "request": "^2.88.0", "request-promise": "^4.2.2", "request-promise-native": "^1.0.5", + "restify": "^8.6.1", "rimraf": "^3.0.2", "sequelize": "^6.17.0", "sinon": "^11.1.1", "sinon-chai": "^3.7.0", + "socket.io": "^4.6.0", + "socket.io-client": "^4.6.0", "sqs-consumer": "5.7.0", "sqs-consumer-v6": "npm:sqs-consumer@^6.2.0", "superagent": "^6.1.0", diff --git a/packages/autoprofile/lib/samplers/async_sampler.js b/packages/autoprofile/lib/samplers/async_sampler.js index ea3dfabdc3..ad7c995e1a 100644 --- a/packages/autoprofile/lib/samplers/async_sampler.js +++ b/packages/autoprofile/lib/samplers/async_sampler.js @@ -7,7 +7,7 @@ 'use strict'; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); const util = require('util'); const CallSite = require('../profile').CallSite; const Profile = require('../profile').Profile; diff --git a/packages/autoprofile/package.json b/packages/autoprofile/package.json index 78ceaba336..39a2c4cad7 100644 --- a/packages/autoprofile/package.json +++ b/packages/autoprofile/package.json @@ -48,6 +48,7 @@ } ], "dependencies": { + "@instana/core": "2.23.0", "detect-libc": "^1.0.3", "nan": "^2.14.2" }, diff --git a/packages/aws-lambda-auto-wrap/package.json b/packages/aws-lambda-auto-wrap/package.json index 136694e05d..2ad8a4fe94 100644 --- a/packages/aws-lambda-auto-wrap/package.json +++ b/packages/aws-lambda-auto-wrap/package.json @@ -63,7 +63,8 @@ "url": "https://github.com/instana/nodejs/issues" }, "dependencies": { - "@instana/aws-lambda": "2.23.0" + "@instana/aws-lambda": "2.23.0", + "@instana/core": "2.23.0" }, "devDependencies": { "no-code2": "2.0.0" diff --git a/packages/aws-lambda-auto-wrap/src/utils.js b/packages/aws-lambda-auto-wrap/src/utils.js index fe508dd03a..f2ae36b255 100644 --- a/packages/aws-lambda-auto-wrap/src/utils.js +++ b/packages/aws-lambda-auto-wrap/src/utils.js @@ -5,8 +5,9 @@ 'use strict'; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); const path = require('path'); + const SPLIT_AT_DOT_REGEX = /^([^.]*)\.(.*)$/; const TWO_DOTS = '..'; const DEFAULT_HANDLER = 'index.handler'; diff --git a/packages/collector/src/actions/source.js b/packages/collector/src/actions/source.js index e078b85d4f..0c4cb1a521 100644 --- a/packages/collector/src/actions/source.js +++ b/packages/collector/src/actions/source.js @@ -5,7 +5,7 @@ 'use strict'; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); /** @type {import('@instana/core/src/logger').GenericLogger} */ let logger; diff --git a/packages/collector/src/agentConnection.js b/packages/collector/src/agentConnection.js index 54a4e0e90b..ff3b7919fc 100644 --- a/packages/collector/src/agentConnection.js +++ b/packages/collector/src/agentConnection.js @@ -5,11 +5,10 @@ 'use strict'; -const { atMostOnce } = require('@instana/core').util; -const fs = require('fs'); -const { http } = require('@instana/core').uninstrumentedHttp; +const { util, uninstrumentedHttp, uninstrumentedFs: fs } = require('@instana/core'); +const http = uninstrumentedHttp.http; + const pathUtil = require('path'); -const { propertySizes } = require('@instana/core').util; /** @typedef {import('@instana/core/src/tracing/cls').InstanaBaseSpan} InstanaBaseSpan */ @@ -79,7 +78,7 @@ exports.AgentEventSeverity = { * @param {(err: Error, rawResponse?: string) => void} cb */ exports.announceNodeCollector = function announceNodeCollector(cb) { - cb = atMostOnce('callback for announceNodeCollector', cb); + cb = util.atMostOnce('callback for announceNodeCollector', cb); /** @type {AgentConnectionPayload} */ const payload = { @@ -202,7 +201,7 @@ exports.checkWhetherAgentIsReadyToAcceptData = function checkWhetherAgentIsReady * @param {(...args: *) => *} cb */ function checkWhetherResponseForPathIsOkay(path, cb) { - cb = atMostOnce('callback for checkWhetherResponseForPathIsOkay', cb); + cb = util.atMostOnce('callback for checkWhetherResponseForPathIsOkay', cb); const req = http.request( { @@ -238,7 +237,7 @@ function checkWhetherResponseForPathIsOkay(path, cb) { * @param {(...args: *) => *} cb */ exports.sendMetrics = function sendMetrics(data, cb) { - cb = atMostOnce('callback for sendMetrics', cb); + cb = util.atMostOnce('callback for sendMetrics', cb); sendData(`/com.instana.plugin.nodejs.${pidStore.pid}`, data, (err, body) => { if (err) { @@ -264,7 +263,7 @@ exports.sendMetrics = function sendMetrics(data, cb) { * @param {(...args: *) => *} cb */ exports.sendSpans = function sendSpans(spans, cb) { - const callback = atMostOnce('callback for sendSpans', err => { + const callback = util.atMostOnce('callback for sendSpans', err => { if (err && !maxContentErrorHasBeenLogged && err instanceof PayloadTooLargeError) { logLargeSpans(spans); } @@ -279,7 +278,7 @@ exports.sendSpans = function sendSpans(spans, cb) { * @param {(...args: *) => *} cb */ exports.sendProfiles = function sendProfiles(profiles, cb) { - const callback = atMostOnce('callback for sendProfiles', err => { + const callback = util.atMostOnce('callback for sendProfiles', err => { if (err && err instanceof PayloadTooLargeError) { logger.warn('Profiles are too too large to be sent.'); } else if (err && err.statusCode === 404) { @@ -299,7 +298,7 @@ exports.sendProfiles = function sendProfiles(profiles, cb) { * @param {(...args: *) => *} cb */ exports.sendEvent = function sendEvent(eventData, cb) { - const callback = atMostOnce('callback for sendEvent', (err, responseBody) => { + const callback = util.atMostOnce('callback for sendEvent', (err, responseBody) => { cb(err, responseBody); }); @@ -321,7 +320,7 @@ exports.sendAgentMonitoringEvent = function sendAgentMonitoringEvent(code, categ category }; - const callback = atMostOnce('callback for sendAgentMonitoringEvent', (err, responseBody) => { + const callback = util.atMostOnce('callback for sendAgentMonitoringEvent', (err, responseBody) => { cb(err, responseBody); }); @@ -334,7 +333,7 @@ exports.sendAgentMonitoringEvent = function sendAgentMonitoringEvent(code, categ * @param {(...args: *) => *} cb */ exports.sendAgentResponseToAgent = function sendAgentResponseToAgent(messageId, response, cb) { - cb = atMostOnce('callback for sendAgentResponseToAgent', cb); + cb = util.atMostOnce('callback for sendAgentResponseToAgent', cb); sendData( `/com.instana.plugin.nodejs/response.${pidStore.pid}?messageId=${encodeURIComponent(messageId)}`, @@ -348,7 +347,7 @@ exports.sendAgentResponseToAgent = function sendAgentResponseToAgent(messageId, * @param {(...args: *) => *} cb */ exports.sendTracingMetricsToAgent = function sendTracingMetricsToAgent(tracingMetrics, cb) { - const callback = atMostOnce('callback for sendTracingMetricsToAgent', err => { + const callback = util.atMostOnce('callback for sendTracingMetricsToAgent', err => { cb(err); }); @@ -363,7 +362,7 @@ exports.sendTracingMetricsToAgent = function sendTracingMetricsToAgent(tracingMe * @returns */ function sendData(path, data, cb, ignore404 = false) { - cb = atMostOnce(`callback for sendData: ${path}`, cb); + cb = util.atMostOnce(`callback for sendData: ${path}`, cb); const payloadAsString = JSON.stringify(data, circularReferenceRemover()); if (typeof logger.trace === 'function') { @@ -474,7 +473,8 @@ function logLargeSpans(spans) { .slice(0, 4) .map( s => - `span name: ${s.span.n}, largest attribute: ${propertySizes(s.span) + `span name: ${s.span.n}, largest attribute: ${util + .propertySizes(s.span) .sort((p1, p2) => p2.length - p1.length) .slice(0, 1) .map(p => `${p.property} (${p.length} bytes)`)}` diff --git a/packages/collector/src/cmdline.js b/packages/collector/src/cmdline.js index 9f8c90747c..5b8a54983d 100644 --- a/packages/collector/src/cmdline.js +++ b/packages/collector/src/cmdline.js @@ -5,7 +5,7 @@ 'use strict'; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); /** @type {import('@instana/core/src/logger').GenericLogger} */ let logger; diff --git a/packages/collector/src/pidStore/index.js b/packages/collector/src/pidStore/index.js index 0f1194c984..77206c1ebb 100644 --- a/packages/collector/src/pidStore/index.js +++ b/packages/collector/src/pidStore/index.js @@ -5,9 +5,9 @@ 'use strict'; -const fs = require('fs'); const EventEmitter = require('events').EventEmitter; +const { uninstrumentedFs: fs } = require('@instana/core'); const internalPidStore = require('./internalPidStore'); const agentOpts = require('../agent/opts'); diff --git a/packages/collector/src/tracing/instrumentation/process/selfPath.js b/packages/collector/src/tracing/instrumentation/process/selfPath.js index 2d454555f8..c89f98e17e 100644 --- a/packages/collector/src/tracing/instrumentation/process/selfPath.js +++ b/packages/collector/src/tracing/instrumentation/process/selfPath.js @@ -5,7 +5,7 @@ 'use strict'; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); const path = require('path'); /** @type {import('@instana/core/src/logger').GenericLogger} */ diff --git a/packages/collector/test/bazel_inode_test.js b/packages/collector/test/bazel_inode_test.js index b9be29da79..f55ef19282 100644 --- a/packages/collector/test/bazel_inode_test.js +++ b/packages/collector/test/bazel_inode_test.js @@ -29,10 +29,6 @@ describe('agent connection/bazel', function () { describe("Bazel's node-patches are present", () => { before(() => { agentConnection = proxyquire('../src/agentConnection', { - // Stub out the fs part part of the fd/inode lookup (the readlinkSync call), and act as if node-patches from - // Bazel were active, that is, return an absolute path from readlinkSync. - fs: mockFs(`/proc/${process.pid}/fd/socket:[12345]`), - // stub out the http communication part of the announce request '@instana/core': mockInstanaCoreHttp(), @@ -111,7 +107,10 @@ describe('agent connection/bazel', function () { return req; } } - } + }, + // Stub out the fs part part of the fd/inode lookup (the readlinkSync call), and act as if node-patches from + // Bazel were active, that is, return an absolute path from readlinkSync. + uninstrumentedFs: mockFs(`/proc/${process.pid}/fd/socket:[12345]`) }; } }); diff --git a/packages/collector/test/cmdline_test.js b/packages/collector/test/cmdline_test.js index a26a11dddb..3a4b81f0ec 100644 --- a/packages/collector/test/cmdline_test.js +++ b/packages/collector/test/cmdline_test.js @@ -57,7 +57,9 @@ describe('cmdline', () => { function req() { result = proxyquire('../src/cmdline', { - fs, + '@instana/core': { + uninstrumentedFs: fs + }, // We need to proxyquire logger, too, to work around the duplicate module logger name check. './logger': proxyquire('../src/logger', {}) diff --git a/packages/collector/test/opentelemetry/app.js b/packages/collector/test/opentelemetry/app.js index 6cfdae61e8..a61673ceb0 100644 --- a/packages/collector/test/opentelemetry/app.js +++ b/packages/collector/test/opentelemetry/app.js @@ -38,11 +38,19 @@ const initOtel = () => { }; if (process.env.INSTANA_LOAD_FIRST === 'true') { - require('../../src')(); + require('../../src')({ + tracing: { + useOpentelemetry: false + } + }); initOtel(); } else { initOtel(); - require('../../src')(); + require('../../src')({ + tracing: { + useOpentelemetry: false + } + }); } require('mysql'); diff --git a/packages/collector/test/pidStore/pidStore_test.js b/packages/collector/test/pidStore/pidStore_test.js index 42198d1925..4f4ce9ad0a 100644 --- a/packages/collector/test/pidStore/pidStore_test.js +++ b/packages/collector/test/pidStore/pidStore_test.js @@ -30,8 +30,8 @@ describe('pidStore', () => { function doRequire() { pidStore = proxyquire('../../src/pidStore', { - fs: { - readFileSync + '@instana/core': { + uninstrumentedFs: { readFileSync } }, './internalPidStore': { pid: process.pid diff --git a/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/receiveMessage.js b/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/receiveMessage.js index c56f61c259..c26a2ba21b 100644 --- a/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/receiveMessage.js +++ b/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/receiveMessage.js @@ -5,7 +5,17 @@ 'use strict'; -const instana = require('../../../../../..')(); +const instana = require('../../../../../..')({ + tracing: { + // We need to disable Otel here because on CI the AWS sdk loads the config file more often than locally + // and creates more spans than locally. + // Background: if you receive a message, aws verifies if you have a cached config file. + // AWS tries to load the file from disk ~/.aws/config and caches it. + // But if the file does not exist, it tries to load it again and again. + // https://github.com/aws/aws-sdk-js/blob/5bfd7c11067e1d52391deb06d165551218f7f19e/lib/shared-ini/ini-loader.js#L67 + useOpentelemetry: false + } +}); const express = require('express'); const request = require('request-promise'); diff --git a/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/sqsUtil.js b/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/sqsUtil.js index 12c3f9f70c..094cc0c739 100644 --- a/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/sqsUtil.js +++ b/packages/collector/test/tracing/cloud/aws-sdk/v2/sqs/sqsUtil.js @@ -19,7 +19,6 @@ AWS.HttpRequest.prototype.appendToUserAgent = function () { }; AWS.config.update({ region: 'us-east-2' }); - const sqs = new AWS.SQS(); exports.sqs = sqs; diff --git a/packages/collector/test/tracing/control_flow/q/test.js b/packages/collector/test/tracing/control_flow/q/test.js index cb455a944f..5aa58b05ac 100644 --- a/packages/collector/test/tracing/control_flow/q/test.js +++ b/packages/collector/test/tracing/control_flow/q/test.js @@ -48,28 +48,28 @@ mochaSuiteFn('tracing/q', function () { runTest('/delay2'); runTest('/timeout', verifySingleEntryWithError); runTest('/nodeify'); - runTest('/make-node-resolver'); + runTest('/make-node-resolver', verifySingleEntry, { spanLength: 2 }); // calls fs.readFile runTest('/with-event-emitter'); runTest('/entry-exit', verifyEntryAndExit); - function runTest(path, verification = verifySingleEntry) { + function runTest(path, verification = verifySingleEntry, opts = { spanLength: 1 }) { it(`must trace: ${path}`, () => controls .sendRequest({ method: 'GET', path }) - .then(response => verification(response, path))); + .then(response => verification(response, path, opts))); } - function verifySingleEntry(response, path) { + function verifySingleEntry(response, path, opts) { expect(response.span).to.be.an('object'); expect(response.error).to.not.exist; return testUtils.retry(() => agentControls.getSpans().then(spans => { const entrySpan = verifyRootEntrySpan(spans, path); expect(response.span.t).to.equal(entrySpan.t); - expect(spans).to.have.lengthOf(1); + expect(spans).to.have.lengthOf(opts.spanLength); }) ); } diff --git a/packages/collector/test/tracing/database/db2/test.js b/packages/collector/test/tracing/database/db2/test.js index c6de785229..e39c0f9d4d 100644 --- a/packages/collector/test/tracing/database/db2/test.js +++ b/packages/collector/test/tracing/database/db2/test.js @@ -70,7 +70,7 @@ const verifySpans = (agentControls, controls, options = {}) => return; } - expect(spans.length).to.equal(options.spanLength || 2); + expect(spans.length).to.equal(options.numberOfSpans || 2); if (options.verifyCustom) return options.verifyCustom(entrySpan, spans); @@ -390,7 +390,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, - spanLength: 3 + numberOfSpans: 3 }) ) ); @@ -406,7 +406,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, - spanLength: 3 + numberOfSpans: 3 }) ) ); @@ -424,7 +424,7 @@ mochaSuiteFn('tracing/db2', function () { verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, error: 'Error: [IBM][CLI Driver] CLI0115E Invalid cursor state. SQLSTATE=24000', - spanLength: 3, + numberOfSpans: 3, verifyCustom: (entrySpan, spans) => { testUtils.expectAtLeastOneMatching(spans, [ span => expect(span.t).to.equal(entrySpan.t), @@ -464,7 +464,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, - spanLength: 3, + numberOfSpans: 3, verifyCustom: (entrySpan, spans) => { const realParent = testUtils.expectAtLeastOneMatching(spans, [ span => expect(span.n).to.equal('node.http.server'), @@ -525,7 +525,7 @@ mochaSuiteFn('tracing/db2', function () { .then(() => testUtils.retry(() => verifySpans(agentControls, controls, { - spanLength: 3, + numberOfSpans: 3, verifyCustom: (entrySpan, spans) => { testUtils.expectExactlyNMatching(spans, 2, [ span => expect(span.t).to.equal(entrySpan.t), @@ -559,7 +559,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { stmt: `insert into ${TABLE_NAME_1} (COLINT, COLDATETIME, COLTEXT) VALUES (?, ?, ?)`, - spanLength: 3, + numberOfSpans: 3, verifyCustom: (entrySpan, spans) => { testUtils.expectAtLeastOneMatching(spans, [ span => expect(span.t).to.equal(entrySpan.t), @@ -608,7 +608,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { expectNoDb2Span: true, - spanLength: 1 + numberOfSpans: 1 }) ) ); @@ -655,7 +655,7 @@ mochaSuiteFn('tracing/db2', function () { .then(() => testUtils.retry(() => verifySpans(agentControls, controls, { - spanLength: 7, + numberOfSpans: 7, verifyCustom: (entrySpan, spans) => { const stmtsToExpect = [ `drop table ${TABLE_NAME_2} if exists`, @@ -745,7 +745,7 @@ mochaSuiteFn('tracing/db2', function () { testUtils.retry(() => verifySpans(agentControls, controls, { expectNoDb2Span: true, - spanLength: 1 + numberOfSpans: 1 }) ) ); @@ -763,7 +763,7 @@ mochaSuiteFn('tracing/db2', function () { verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, error: `'result.closeSync' was not called within ${DB2_CLOSE_TIMEOUT_IN_MS}ms.`, - spanLength: 2 + numberOfSpans: 2 }) ) ); @@ -848,7 +848,7 @@ mochaSuiteFn('tracing/db2', function () { verifySpans(agentControls, controls, { stmt: `SELECT * FROM ${TABLE_NAME_1}`, error: `'result.closeSync' was not called within ${DB2_CLOSE_TIMEOUT_IN_MS}ms.`, - spanLength: 2 + numberOfSpans: 2 }) ) ); @@ -878,7 +878,10 @@ mochaSuiteFn('tracing/db2', function () { .then(() => testUtils.retry(() => verifySpans(agentControls, controls, { - spanLength: 11, + // 11 queries splitted from the file + // 5 fs operations on top (ours + from db2 internally fs-extra) + // https://github.com/ibmdb/node-ibm_db/blob/fb25937524d74d25917e9aa67fb4737971317986/lib/odbc.js#L916 + numberOfSpans: 15, verifyCustom: (entrySpan, spans) => { const stmtsToExpect = [ `create table ${TABLE_NAME_3}(no integer,name varchar(10))`, @@ -924,7 +927,8 @@ mochaSuiteFn('tracing/db2', function () { .then(() => testUtils.retry(() => verifySpans(agentControls, controls, { - spanLength: 11, + // 11 queries + fs calls + numberOfSpans: 16, verifyCustom: (entrySpan, spans) => { const stmtsToExpect = [ `create table ${TABLE_NAME_3}(no integer,name varchar(10))`, @@ -970,7 +974,8 @@ mochaSuiteFn('tracing/db2', function () { .then(() => testUtils.retry(() => verifySpans(agentControls, controls, { - spanLength: 11, + // 11 queries + fs calls + numberOfSpans: 16, verifyCustom: (entrySpan, spans) => { const stmtsToExpect = [ `create table ${TABLE_NAME_3}(no integer,name varchar(10))`, diff --git a/packages/collector/test/tracing/logger/bunyan/test.js b/packages/collector/test/tracing/logger/bunyan/test.js index 9386949457..edb9d92884 100644 --- a/packages/collector/test/tracing/logger/bunyan/test.js +++ b/packages/collector/test/tracing/logger/bunyan/test.js @@ -65,7 +65,8 @@ mochaSuiteFn('tracing/logger/bunyan', function () { true, // eslint-disable-next-line max-len '{"_id":"638dea148cff492d47e792ea","index":0,"guid":"01b61bfa-fe4c-4d75-9224-389c4c04de10","isActive":false,"balance":"$1,919.18","picture":"http://placehold.it/32x32","age":37,"eyeColor":"blue","name":"Manning Brady","gender":"male","company":"ZYTRAC","email":"manningbrady@zytrac.com","phone":"+1 (957) 538-2183","address":"146 Bushwick Court, Gilgo, New York, 2992","about":"Ullamco cillum reprehenderit eu proident veniam laboris tempor voluptate. Officia deserunt velit incididunt consequat la...', - 500 + 500, + 4 )); it("must capture an error object's message and an additional string", () => @@ -127,7 +128,7 @@ mochaSuiteFn('tracing/logger/bunyan', function () { }); }); - function runTest(url, expectErroneous, message, lengthOfMessage) { + function runTest(url, expectErroneous, message, lengthOfMessage, numberOfSpans) { return appControls.trigger(url).then(() => testUtils.retry(() => agentControls.getSpans().then(spans => { @@ -147,10 +148,10 @@ mochaSuiteFn('tracing/logger/bunyan', function () { const allBunyanSpans = testUtils.getSpansByName(spans, 'log.bunyan'); expect(allBunyanSpans.length).to.equal(1); - // entry + exit + bunyan log + // entry + exit + bunyan log (+ fs call) // NOTE: Bunyan uses process.stdout directly // Length of 3 just ensures that our console.* instrumentation isn't counted when customer uses Bunyan - expect(spans.length).to.eql(3); + expect(spans.length).to.eql(numberOfSpans || 3); }) ) ); diff --git a/packages/collector/test/tracing/open_tracing/integration_test.js b/packages/collector/test/tracing/open_tracing/integration_test.js index 298d0bfcab..ad383a205c 100644 --- a/packages/collector/test/tracing/open_tracing/integration_test.js +++ b/packages/collector/test/tracing/open_tracing/integration_test.js @@ -84,7 +84,7 @@ describe('tracing/opentracing/integration', function () { expressOpentracingControls.sendRequest({ path: '/withOpentracingConnectedToInstanaTrace' }).then(() => testUtils.retry(() => agentControls.getSpans().then(spans => { - expect(spans).to.have.lengthOf(2); + expect(spans).to.have.lengthOf(3); const httpSpan = testUtils.expectAtLeastOneMatching(spans, [ span => expect(span.n).to.equal('node.http.server'), @@ -104,6 +104,19 @@ describe('tracing/opentracing/integration', function () { span => expect(span.data.service).to.equal('theFancyServiceYouWouldntBelieveActuallyExists'), span => expect(span.data.sdk.name).to.equal('service') ]); + + // opentracing lazy loads cls.js + // realpathSync /Users/kirrg001/dev/instana/nodejs/packages/core/src/tracing/cls.js + testUtils.expectAtLeastOneMatching(spans, [ + span => expect(span.t).to.equal(httpSpan.t), + span => expect(span.p).to.equal(httpSpan.s), + span => expect(span.s).to.be.a('string'), + span => expect(span.s).not.to.equal(span.t), + span => expect(span.s).not.to.equal(span.p), + span => expect(span.n).to.equal('otel'), + span => expect(span.f.e).to.equal(String(expressOpentracingControls.getPid())), + span => expect(span.f.h).to.equal('agent-stub-uuid') + ]); }) ) )); diff --git a/packages/collector/test/tracing/opentelemetry/fs-app.js b/packages/collector/test/tracing/opentelemetry/fs-app.js new file mode 100644 index 0000000000..c0ab8bd69a --- /dev/null +++ b/packages/collector/test/tracing/opentelemetry/fs-app.js @@ -0,0 +1,48 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +/* eslint-disable no-console */ + +'use strict'; + +require('../../../src')(); + +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const port = require('../../test_util/app-port')(); +const app = express(); +const logPrefix = `FS App (${process.pid}):\t`; + +app.get('/', (req, res) => { + res.sendStatus(200); +}); + +app.get('/fsread', (req, res) => { + log('Received /fsread request'); + + // NOTE: instana http span, single otel span without parent + fs.readFileSync(path.join(__dirname, './test.js')); + res.send(); +}); + +app.get('/fsread2', (req, res) => { + log('Received /fsread2 request'); + + // NOTE: instana http span, fs otel span as parent and another fs span + fs.readFileSync(path.join(__dirname, './test.js')); + fs.statSync(path.join(__dirname, './test.js')); + + res.send(); +}); + +app.listen(port, () => { + log(`Listening on port: ${port}`); +}); + +function log() { + const args = Array.prototype.slice.call(arguments); + args[0] = logPrefix + args[0]; + console.log.apply(console, args); +} diff --git a/packages/collector/test/tracing/opentelemetry/restify-app.js b/packages/collector/test/tracing/opentelemetry/restify-app.js new file mode 100644 index 0000000000..b0487ce04d --- /dev/null +++ b/packages/collector/test/tracing/opentelemetry/restify-app.js @@ -0,0 +1,79 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +/* eslint-disable no-console */ + +'use strict'; + +const agentPort = process.env.INSTANA_AGENT_PORT; +const opentelemetryDisabled = process.env.INSTANA_DISABLE_USE_OPENTELEMETRY === 'true'; + +require('../../../src')({ + tracing: { + useOpentelemetry: !opentelemetryDisabled + } +}); + +const restify = require('restify'); +const request = require('request-promise-native'); +const _pg = require('pg'); +const Pool = _pg.Pool; +const Client = _pg.Client; +const port = require('../../test_util/app-port')(); +const logPrefix = `Restify App (${process.pid}):\t`; + +const pool = new Pool({ + user: process.env.POSTGRES_USER, + host: process.env.POSTGRES_HOST, + database: process.env.POSTGRES_DB, + password: process.env.POSTGRES_PASSWORD +}); +const client = new Client({ + user: process.env.POSTGRES_USER, + host: process.env.POSTGRES_HOST, + database: process.env.POSTGRES_DB, + password: process.env.POSTGRES_PASSWORD +}); +client.connect(); + +const server = restify.createServer({ + name: 'myrestifyapp', + version: '1.0.0' +}); + +server.use(restify.plugins.acceptParser(server.acceptable)); +server.use(restify.plugins.queryParser()); +server.use(restify.plugins.bodyParser()); + +server.get('/', (req, res, next) => { + res.send(); + next(); +}); + +server.get('/test', function (req, res, next) { + log('Received /test request'); + + pool.query('SELECT NOW()', (err, results) => { + if (err) { + log('Failed to execute select now query', err); + return res.sendStatus(500); + } + // Execute another traced call to verify that we keep the tracing context. + request(`http://127.0.0.1:${agentPort}`).then(() => { + res.send(results); + next(); + }); + }); +}); + +server.listen(port, function () { + log('%s listening at %s', server.name, server.url); +}); + +function log() { + /* eslint-disable no-console */ + const args = Array.prototype.slice.call(arguments); + args[0] = logPrefix + args[0]; + console.log.apply(console, args); +} diff --git a/packages/collector/test/tracing/opentelemetry/socketio-client.js b/packages/collector/test/tracing/opentelemetry/socketio-client.js new file mode 100644 index 0000000000..ec1cd643d4 --- /dev/null +++ b/packages/collector/test/tracing/opentelemetry/socketio-client.js @@ -0,0 +1,36 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +/* eslint-disable no-console */ + +'use strict'; + +require('../../..')(); + +const socketioclient = require('socket.io-client'); +const express = require('express'); +const port = require('../../test_util/app-port')(); +const app = express(); +const logPrefix = `SocketIO ClientApp (${process.pid}):\t`; + +const ioClient = socketioclient.connect('http://localhost:3000'); + +ioClient.on('test', () => { + log('Received msg for "test"'); + ioClient.emit('test_reply', 'welcome'); +}); + +app.get('/', (req, res) => { + res.sendStatus(200); +}); + +app.listen(port, () => { + log(`Listening on port: ${port}`); +}); + +function log() { + const args = Array.prototype.slice.call(arguments); + args[0] = logPrefix + args[0]; + console.log.apply(console, args); +} diff --git a/packages/collector/test/tracing/opentelemetry/socketio-server.js b/packages/collector/test/tracing/opentelemetry/socketio-server.js new file mode 100644 index 0000000000..3b31e83677 --- /dev/null +++ b/packages/collector/test/tracing/opentelemetry/socketio-server.js @@ -0,0 +1,57 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +/* eslint-disable no-console */ + +'use strict'; + +require('../../../src')(); + +const express = require('express'); +const port = require('../../test_util/app-port')(); +const app = express(); +const logPrefix = `SocketIO Server App (${process.pid}):\t`; + +const ioserver = require('http').createServer(); +const io = require('socket.io')(ioserver); +ioserver.listen(3000); + +let socket; +io.on('connection', _socket => { + log('Connected'); + socket = _socket; + + socket.on('test_reply', msg => { + log('Received msg', msg); + }); +}); + +app.get('/', (req, res) => { + if (!socket) return res.sendStatus(500); + res.sendStatus(200); +}); + +app.get('/io-emit', (req, res) => { + log('Received /io-emit request'); + + socket.emit('test', 'this is a msg'); + res.send(); +}); + +app.get('/io-send', (req, res) => { + log('Received /io-send request'); + + socket.send('anothertest', 'another msg'); + res.send(); +}); + +app.listen(port, () => { + log(`Listening on port: ${port}`); +}); + +function log() { + const args = Array.prototype.slice.call(arguments); + args[0] = logPrefix + args[0]; + console.log.apply(console, args); +} diff --git a/packages/collector/test/tracing/opentelemetry/test.js b/packages/collector/test/tracing/opentelemetry/test.js new file mode 100644 index 0000000000..552f4f7a4a --- /dev/null +++ b/packages/collector/test/tracing/opentelemetry/test.js @@ -0,0 +1,460 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +'use strict'; + +const expect = require('chai').expect; +const path = require('path'); +const semver = require('semver'); +const supportedVersion = require('@instana/core').tracing.supportedVersion; +const config = require('../../../../core/test/config'); +const constants = require('@instana/core').tracing.constants; + +const { + retry, + verifyHttpRootEntry, + verifyExitSpan, + verifyIntermediateSpan, + verifyEntrySpan, + expectExactlyNMatching, + delay, + expectExactlyOneMatching +} = require('../../../../core/test/test_util'); +const ProcessControls = require('../../test_util/ProcessControls'); +const globalAgent = require('../../globalAgent'); +const DELAY_TIMEOUT_IN_MS = 500; + +const mochaSuiteFn = + supportedVersion(process.versions.node) && semver.gte(process.versions.node, '14.0.0') ? describe : describe.skip; + +mochaSuiteFn('opentelemetry/instrumentations', function () { + this.timeout(config.getTestTimeout()); + + describe('restify', function () { + // No support for Node v18 yet. + // https://github.com/restify/node-restify/issues/1925 + // https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1339 + const skip = semver.lt(process.versions.node, '18.0.0') !== true; + if (skip) return it.skip(`skipping ${process.versions.node}`); + + describe('opentelemetry is enabled', function () { + globalAgent.setUpCleanUpHooks(); + const agentControls = globalAgent.instance; + + const controls = new ProcessControls({ + appPath: path.join(__dirname, './restify-app'), + useGlobalAgent: true + }); + + ProcessControls.setUpHooks(controls); + + it('should trace', () => + controls + .sendRequest({ + method: 'GET', + path: '/test' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(8); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/test', + pid: String(controls.getPid()) + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql('request handler - /test'); + expect(span.data.tags['restify.version']).to.eql('8.6.1'); + expect(span.data.tags['restify.type']).to.eql('request_handler'); + expect(span.data.tags['restify.method']).to.eql('get'); + expect(span.data.tags['http.route']).to.eql('/test'); + + checkTelemetryResourceAttrs(span); + } + }); + + verifyIntermediateSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + testMethod: expectExactlyNMatching, + n: 4 + }); + + ['parseAccept', 'parseQueryString', 'readBody', 'parseBody'].forEach(name => { + verifyIntermediateSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql(`middleware - ${name}`); + expect(span.data.tags['restify.name']).to.eql(name); + expect(span.data.tags['restify.version']).to.eql('8.6.1'); + expect(span.data.tags['restify.type']).to.eql('middleware'); + expect(span.data.tags['restify.method']).to.eql('use'); + expect(span.data.tags['http.route']).to.eql('/test'); + + checkTelemetryResourceAttrs(span); + } + }); + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql('request handler - /test'); + expect(span.data.tags['restify.name']).to.not.exist; + expect(span.data.tags['restify.version']).to.eql('8.6.1'); + expect(span.data.tags['restify.type']).to.eql('request_handler'); + expect(span.data.tags['restify.method']).to.eql('get'); + expect(span.data.tags['http.route']).to.eql('/test'); + + checkTelemetryResourceAttrs(span); + } + }); + + verifyExitSpan({ + spanName: 'postgres', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'pg' + }); + + verifyHttpExit(spans, httpEntry); + }) + ) + )); + + it('[suppressed] should not trace', () => + controls + .sendRequest({ + method: 'GET', + path: '/test', + suppressTracing: true + }) + .then(() => delay(DELAY_TIMEOUT_IN_MS)) + .then(() => retry(() => agentControls.getSpans().then(spans => expect(spans).to.be.empty)))); + }); + + describe('opentelemetry is disabled', function () { + globalAgent.setUpCleanUpHooks(); + const agentControls = globalAgent.instance; + + const controls = new ProcessControls({ + appPath: path.join(__dirname, './restify-app'), + useGlobalAgent: true, + env: { + INSTANA_DISABLE_USE_OPENTELEMETRY: true + } + }); + + ProcessControls.setUpHooks(controls); + + it('should trace instana spans only', () => + controls + .sendRequest({ + method: 'GET', + path: '/test' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(3); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/test', + pid: String(controls.getPid()) + }); + + verifyExitSpan({ + spanName: 'postgres', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'pg' + }); + + verifyHttpExit(spans, httpEntry); + }) + ) + )); + }); + }); + + describe('fs', function () { + globalAgent.setUpCleanUpHooks(); + const agentControls = globalAgent.instance; + + const controls = new ProcessControls({ + appPath: path.join(__dirname, './fs-app'), + useGlobalAgent: true + }); + + ProcessControls.setUpHooks(controls); + + it('should trace when there is no otel parent', () => + controls + .sendRequest({ + method: 'GET', + path: '/fsread' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(2); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/fsread', + pid: String(controls.getPid()) + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql('fs readFileSync'); + checkTelemetryResourceAttrs(span); + } + }); + }) + ) + )); + + it('should trace when there is an otel parent', () => + controls + .sendRequest({ + method: 'GET', + path: '/fsread2' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(3); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/fsread2', + pid: String(controls.getPid()) + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql('fs statSync'); + checkTelemetryResourceAttrs(span); + } + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(controls.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.eql('fs readFileSync'); + checkTelemetryResourceAttrs(span); + } + }); + }) + ) + )); + + it('[suppressed] should not trace', () => + controls + .sendRequest({ + method: 'GET', + path: '/fsread', + suppressTracing: true + }) + .then(() => delay(DELAY_TIMEOUT_IN_MS)) + .then(() => retry(() => agentControls.getSpans().then(spans => expect(spans).to.be.empty)))); + }); + + describe('socket.io', function () { + globalAgent.setUpCleanUpHooks(); + const agentControls = globalAgent.instance; + + const server = new ProcessControls({ + appPath: path.join(__dirname, './socketio-server'), + useGlobalAgent: true + }); + const client = new ProcessControls({ + appPath: path.join(__dirname, './socketio-client'), + useGlobalAgent: true + }); + + ProcessControls.setUpHooks(server, client); + + it('should trace', () => + server + .sendRequest({ + method: 'GET', + path: '/io-emit' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(3); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/io-emit', + pid: String(server.getPid()) + }); + + verifyEntrySpan({ + spanName: 'otel', + spans, + withError: false, + pid: String(server.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.contain('test_reply receive'); + expect(span.data.tags['messaging.system']).to.eql('socket.io'); + expect(span.data.tags['messaging.destination']).to.eql('ON test_reply'); + expect(span.data.tags['messaging.operation']).to.eql('receive'); + expect(span.data.tags['messaging.socket.io.event_name']).to.eql('test_reply'); + + checkTelemetryResourceAttrs(span); + } + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(server.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.contain('send'); + expect(span.data.tags['messaging.system']).to.eql('socket.io'); + expect(span.data.tags['messaging.destination_kind']).to.eql('topic'); + expect(span.data.tags['messaging.socket.io.event_name']).to.eql('test'); + expect(span.data.tags['messaging.socket.io.namespace']).to.eql('/'); + expect(span.data.tags['messaging.destination']).to.eql('EMIT test'); + + checkTelemetryResourceAttrs(span); + } + }); + }) + ) + )); + + it('should trace', () => + server + .sendRequest({ + method: 'GET', + path: '/io-send' + }) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + expect(spans.length).to.equal(2); + + const httpEntry = verifyHttpRootEntry({ + spans, + apiPath: '/io-send', + pid: String(server.getPid()) + }); + + verifyExitSpan({ + spanName: 'otel', + spans, + parent: httpEntry, + withError: false, + pid: String(server.getPid()), + dataProperty: 'tags', + extraTests: span => { + expect(span.data.tags.name).to.contain('send'); + expect(span.data.tags['messaging.system']).to.eql('socket.io'); + expect(span.data.tags['messaging.destination_kind']).to.eql('topic'); + expect(span.data.tags['messaging.socket.io.event_name']).to.eql('message'); + expect(span.data.tags['messaging.socket.io.namespace']).to.eql('/'); + expect(span.data.tags['messaging.destination']).to.eql('EMIT message'); + + checkTelemetryResourceAttrs(span); + } + }); + }) + ) + )); + + it('[suppressed] should not trace', () => + server + .sendRequest({ + method: 'GET', + path: '/io-emit', + suppressTracing: true + }) + .then(() => delay(DELAY_TIMEOUT_IN_MS)) + .then(() => + retry(() => + agentControls.getSpans().then(spans => { + // We cannot forward the headers because socket.io does not support headers + expect(spans.length).to.eql(1); + }) + ) + )); + }); +}); + +function checkTelemetryResourceAttrs(span) { + expect(span.data.resource['telemetry.sdk.language']).to.eql('nodejs'); + expect(span.data.resource['telemetry.sdk.name']).to.eql('opentelemetry'); + expect(span.data.resource['telemetry.sdk.version']).to.match(/1\.\d+\.\d/); +} + +function verifyHttpExit(spans, parentSpan) { + return expectExactlyOneMatching(spans, [ + span => expect(span.n).to.equal('node.http.client'), + span => expect(span.k).to.equal(constants.EXIT), + span => expect(span.async).to.not.exist, + span => expect(span.error).to.not.exist, + span => expect(span.ec).to.equal(0), + span => expect(span.t).to.be.a('string'), + span => expect(span.s).to.be.a('string'), + span => expect(span.p).to.equal(parentSpan.s), + span => expect(span.data.http.method).to.equal('GET'), + span => expect(span.data.http.status).to.equal(200), + span => expect(span.fp).to.not.exist + ]); +} diff --git a/packages/core/.eslintignore b/packages/core/.eslintignore new file mode 100644 index 0000000000..ee0a538dd5 --- /dev/null +++ b/packages/core/.eslintignore @@ -0,0 +1 @@ +src/tracing/opentelemetry-instrumentations/files \ No newline at end of file diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index b99be872cc..cb8a22fac4 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -9,6 +9,12 @@ "version": "2.23.0", "license": "MIT", "dependencies": { + "@opentelemetry/api": "1.4.1", + "@opentelemetry/context-async-hooks": "1.9.1", + "@opentelemetry/instrumentation-fs": "0.7.3", + "@opentelemetry/instrumentation-restify": "0.32.3", + "@opentelemetry/instrumentation-socket.io": "0.33.3", + "@opentelemetry/sdk-trace-base": "1.14.0", "cls-bluebird": "^2.1.0", "lru-cache": "6.0.0", "methods": "^1.1.2", @@ -20,6 +26,141 @@ "no-code2": "2.0.0" } }, + "node_modules/@opentelemetry/api": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", + "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.9.1.tgz", + "integrity": "sha512-HmycxnnIm00gdmxfD5OkDotL15bGqazLYqQJdcv1uNt22OSc5F/a3Paz3yznmf+/gWdPG8nlq/zd9H0mNXJnGg==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.14.0.tgz", + "integrity": "sha512-MnMZ+sxsnlzloeuXL2nm5QcNczt/iO82UOeQQDHhV83F2fP3sgntW2evvtoxJki0MBLxEsh5ADD7PR/Hn5uzjw==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.39.1.tgz", + "integrity": "sha512-s7/9tPmM0l5KCd07VQizC4AO2/5UJdkXq5gMSHPdCeiMKSeBEdyDyQX7A+Cq+RYZM452qzFmrJ4ut628J5bnSg==", + "dependencies": { + "require-in-the-middle": "^7.1.0", + "semver": "^7.3.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.7.3.tgz", + "integrity": "sha512-GUJvcU6/lZI4gpA3Mu7FP7hVHYk9IS6C2gGJlEhzzBOrStIw+xWzupFbra+sA2+ds1IPDUdAOBvNp0fhBrou5A==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-restify": { + "version": "0.32.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.32.3.tgz", + "integrity": "sha512-KThDEAJyfMBVn829GFaW58/EhkIMbuIGf0H6aCOjYBV5RrS1v5y8i13OYtxnN2gk/fCU/9t47I6bqrKUyLRjjQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-socket.io": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.33.3.tgz", + "integrity": "sha512-Tk0WwIQPKmm+j5EWbQwc111utkk+TkkIbJlV0O+vVHFaUjuP0lQ52eFCw2O8WClOUBa9SxnIt1Bul8bSntXJhQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", + "dependencies": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.14.0.tgz", + "integrity": "sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==", + "dependencies": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.14.0.tgz", + "integrity": "sha512-rJfCY8rCWz3cb4KI6pEofnytvMPuj3YLQwoscCCYZ5DkdiPjo15IQ0US7+mjcWy9H3fcZIzf2pbJZ7ck/h4tug==", + "engines": { + "node": ">=14" + } + }, "node_modules/cls-bluebird": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", @@ -29,6 +170,38 @@ "shimmer": "^1.1.0" } }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/is-bluebird": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", @@ -37,6 +210,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -56,6 +240,16 @@ "node": ">= 0.6" } }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/no-code2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/no-code2/-/no-code2-2.0.0.tgz", @@ -70,11 +264,45 @@ "node": ">=0.10" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "node_modules/require-in-the-middle": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.1.1.tgz", + "integrity": "sha512-OScOjQjrrjhAdFpQmnkE/qbIBGCRFhQB/YaJhcC3CPOlmhe7llnW46Ac1J5+EjcNXOTnDdpF96Erw/yedsGksQ==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/semver": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.3.tgz", @@ -108,6 +336,17 @@ "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -115,6 +354,88 @@ } }, "dependencies": { + "@opentelemetry/api": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", + "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==" + }, + "@opentelemetry/context-async-hooks": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.9.1.tgz", + "integrity": "sha512-HmycxnnIm00gdmxfD5OkDotL15bGqazLYqQJdcv1uNt22OSc5F/a3Paz3yznmf+/gWdPG8nlq/zd9H0mNXJnGg==", + "requires": {} + }, + "@opentelemetry/core": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.14.0.tgz", + "integrity": "sha512-MnMZ+sxsnlzloeuXL2nm5QcNczt/iO82UOeQQDHhV83F2fP3sgntW2evvtoxJki0MBLxEsh5ADD7PR/Hn5uzjw==", + "requires": { + "@opentelemetry/semantic-conventions": "1.14.0" + } + }, + "@opentelemetry/instrumentation": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.39.1.tgz", + "integrity": "sha512-s7/9tPmM0l5KCd07VQizC4AO2/5UJdkXq5gMSHPdCeiMKSeBEdyDyQX7A+Cq+RYZM452qzFmrJ4ut628J5bnSg==", + "requires": { + "require-in-the-middle": "^7.1.0", + "semver": "^7.3.2", + "shimmer": "^1.2.1" + } + }, + "@opentelemetry/instrumentation-fs": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.7.3.tgz", + "integrity": "sha512-GUJvcU6/lZI4gpA3Mu7FP7hVHYk9IS6C2gGJlEhzzBOrStIw+xWzupFbra+sA2+ds1IPDUdAOBvNp0fhBrou5A==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-restify": { + "version": "0.32.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.32.3.tgz", + "integrity": "sha512-KThDEAJyfMBVn829GFaW58/EhkIMbuIGf0H6aCOjYBV5RrS1v5y8i13OYtxnN2gk/fCU/9t47I6bqrKUyLRjjQ==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-socket.io": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.33.3.tgz", + "integrity": "sha512-Tk0WwIQPKmm+j5EWbQwc111utkk+TkkIbJlV0O+vVHFaUjuP0lQ52eFCw2O8WClOUBa9SxnIt1Bul8bSntXJhQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.39.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", + "requires": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.14.0.tgz", + "integrity": "sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==", + "requires": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.14.0.tgz", + "integrity": "sha512-rJfCY8rCWz3cb4KI6pEofnytvMPuj3YLQwoscCCYZ5DkdiPjo15IQ0US7+mjcWy9H3fcZIzf2pbJZ7ck/h4tug==" + }, "cls-bluebird": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", @@ -124,11 +445,40 @@ "shimmer": "^1.1.0" } }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "is-bluebird": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" }, + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "requires": { + "has": "^1.0.3" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -142,6 +492,16 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "no-code2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/no-code2/-/no-code2-2.0.0.tgz", @@ -153,11 +513,36 @@ "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.5.tgz", "integrity": "sha512-XLKtEfHxqrWyF1fzxznsv78w3csW41ucHnjiKnfzZLD5FN8UBDZZL1i4q0FR29zjxXhm+2Hop+5Vr/b8tKIvEg==" }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "require-in-the-middle": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.1.1.tgz", + "integrity": "sha512-OScOjQjrrjhAdFpQmnkE/qbIBGCRFhQB/YaJhcC3CPOlmhe7llnW46Ac1J5+EjcNXOTnDdpF96Erw/yedsGksQ==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, "semver": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.3.tgz", @@ -187,6 +572,11 @@ "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index d312209fb0..4a662d689c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -124,6 +124,12 @@ }, "homepage": "https://github.com/instana/nodejs/blob/main/packages/core/README.md", "dependencies": { + "@opentelemetry/api": "1.4.1", + "@opentelemetry/context-async-hooks": "1.9.1", + "@opentelemetry/instrumentation-fs": "0.7.3", + "@opentelemetry/instrumentation-restify": "0.32.3", + "@opentelemetry/instrumentation-socket.io": "0.33.3", + "@opentelemetry/sdk-trace-base": "1.14.0", "cls-bluebird": "^2.1.0", "lru-cache": "6.0.0", "methods": "^1.1.2", diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 084a08535c..0073ccc515 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -10,6 +10,8 @@ const normalizeConfig = require('./util/normalizeConfig'); // Require this first to ensure that we have non-instrumented http available. const uninstrumentedHttp = require('./uninstrumentedHttp'); +const uninstrumentedFs = require('./uninstrumentedFs'); + const metrics = require('./metrics'); const secrets = require('./secrets'); const tracing = require('./tracing'); @@ -78,6 +80,7 @@ module.exports = { secrets, tracing, uninstrumentedHttp, + uninstrumentedFs, util, init, preInit, diff --git a/packages/core/src/metrics/index.js b/packages/core/src/metrics/index.js index d1a7b84004..59752ce0b4 100644 --- a/packages/core/src/metrics/index.js +++ b/packages/core/src/metrics/index.js @@ -5,7 +5,7 @@ 'use strict'; -const fs = require('fs'); +const fs = require('../uninstrumentedFs'); const path = require('path'); /** @typedef {import('../util/normalizeConfig').InstanaConfig} InstanaConfig */ diff --git a/packages/core/src/tracing/index.js b/packages/core/src/tracing/index.js index cd3692472d..4ca9a4bc1c 100644 --- a/packages/core/src/tracing/index.js +++ b/packages/core/src/tracing/index.js @@ -14,6 +14,7 @@ const tracingHeaders = require('./tracingHeaders'); const tracingUtil = require('./tracingUtil'); const spanBuffer = require('./spanBuffer'); const supportedVersion = require('./supportedVersion'); +const { otelInstrumentations } = require('./opentelemetry-instrumentations'); let tracingEnabled = false; let tracingActivated = false; @@ -159,6 +160,10 @@ exports.init = function init(_config, downstreamConnection, _processIdentityProv if (automaticTracingEnabled) { initInstrumenations(config); + + if (_config.tracing.useOpentelemetry) { + otelInstrumentations.init(config, cls); + } } } @@ -176,13 +181,16 @@ function initInstrumenations(_config) { instrumentations.forEach(instrumentationKey => { instrumentationModules[instrumentationKey] = require(instrumentationKey); instrumentationModules[instrumentationKey].init(_config); + if (instrumentationModules[instrumentationKey].batchable && instrumentationModules[instrumentationKey].spanName) { spanBuffer.addBatchableSpanName(instrumentationModules[instrumentationKey].spanName); } }); + additionalInstrumentationModules.forEach(instrumentationModule => { instrumentationModule.init(_config); }); + instrumenationsInitialized = true; } else { instrumentations.forEach(instrumentationKey => { diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/files/NonRecordingSpan.js b/packages/core/src/tracing/opentelemetry-instrumentations/files/NonRecordingSpan.js new file mode 100644 index 0000000000..769c93c254 --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/files/NonRecordingSpan.js @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, '__esModule', { value: true }); +exports.NonRecordingSpan = void 0; +const invalid_span_constants_1 = require('./invalid-span-constants'); +/** + * The NonRecordingSpan is the default {@link Span} that is used when no Span + * implementation is available. All operations are no-op including context + * propagation. + */ +class NonRecordingSpan { + constructor(_spanContext = invalid_span_constants_1.INVALID_SPAN_CONTEXT) { + this._spanContext = _spanContext; + } + // Returns a SpanContext. + spanContext() { + return this._spanContext; + } + // By default does nothing + setAttribute(_key, _value) { + return this; + } + // By default does nothing + setAttributes(_attributes) { + return this; + } + // By default does nothing + addEvent(_name, _attributes) { + return this; + } + // By default does nothing + setStatus(_status) { + return this; + } + // By default does nothing + updateName(_name) { + return this; + } + // By default does nothing + end(_endTime) {} + // isRecording always returns false for NonRecordingSpan. + isRecording() { + return false; + } + // By default does nothing + recordException(_exception, _time) {} +} +exports.NonRecordingSpan = NonRecordingSpan; diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/files/invalid-span-constants.js b/packages/core/src/tracing/opentelemetry-instrumentations/files/invalid-span-constants.js new file mode 100644 index 0000000000..7854e2a544 --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/files/invalid-span-constants.js @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, '__esModule', { value: true }); +exports.INVALID_SPAN_CONTEXT = exports.INVALID_TRACEID = exports.INVALID_SPANID = void 0; +const trace_flags_1 = require('./trace_flags'); +exports.INVALID_SPANID = '0000000000000000'; +exports.INVALID_TRACEID = '00000000000000000000000000000000'; +exports.INVALID_SPAN_CONTEXT = { + traceId: exports.INVALID_TRACEID, + spanId: exports.INVALID_SPANID, + traceFlags: trace_flags_1.TraceFlags.NONE +}; +//# sourceMappingURL=invalid-span-constants.js.map diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/files/trace_flags.js b/packages/core/src/tracing/opentelemetry-instrumentations/files/trace_flags.js new file mode 100644 index 0000000000..328bc75ff5 --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/files/trace_flags.js @@ -0,0 +1,25 @@ +Object.defineProperty(exports, '__esModule', { value: true }); +exports.TraceFlags = void 0; +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var TraceFlags; +(function (TraceFlags) { + /** Represents no flag set. */ + TraceFlags[(TraceFlags['NONE'] = 0)] = 'NONE'; + /** Bit to represent whether trace is sampled in trace flags. */ + TraceFlags[(TraceFlags['SAMPLED'] = 1)] = 'SAMPLED'; +})((TraceFlags = exports.TraceFlags || (exports.TraceFlags = {}))); +//# sourceMappingURL=trace_flags.js.map diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/fs.js b/packages/core/src/tracing/opentelemetry-instrumentations/fs.js new file mode 100644 index 0000000000..c59239f1ce --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/fs.js @@ -0,0 +1,47 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +'use strict'; + +// NOTE: otel fs instrumentation does not capture the file name currently +module.exports.init = cls => { + const constants = require('../constants'); + const api = require('@opentelemetry/api'); + const { NonRecordingSpan } = require('./files/NonRecordingSpan'); + const { FsInstrumentation } = require('@opentelemetry/instrumentation-fs'); + + // eslint-disable-next-line max-len + // https://github.com/open-telemetry/opentelemetry-js-contrib/pull/1335/files#diff-9a2f445c78d964623d07987299501cbc3101cbe0f76f9e18d2d75787601539daR428 + // As we mix Instana & Otel instrumentations, we need to check here if + // we have an Instana parentSpan otherwise we loose spans. + // e.g. http server call is instana span && fs call exit call is otel span + const orig = api.trace.getSpan; + api.trace.getSpan = function instanaGetSpan() { + const parentSpan = cls.getCurrentSpan(); + + // CASE: we only want to trace fs calls on entry spans + if (!parentSpan || constants.isExitSpan(parentSpan)) { + return orig.apply(this, arguments); + } + + // We tell Otel that there is a fake parent span + return new NonRecordingSpan(); + }; + + const instrumentation = new FsInstrumentation({ + // NOTE: we have to use requireParentSpan otherwise we would create spans on bootstrap for all require statements + requireParentSpan: true, + createHook: (operation, opts) => { + // CASE: we ignore lazy loading of npm modules, + // because this can create a lot of require calls e.g. fs-extra creates > 500 calls + // NOTE: createHook is called **after** requireParentSpan + if (opts.args && opts.args[0] && opts.args[0].indexOf('/node_modules') !== -1) return false; + return true; + } + }); + + if (!instrumentation.getConfig().enabled) { + instrumentation.enable(); + } +}; diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/index.js b/packages/core/src/tracing/opentelemetry-instrumentations/index.js new file mode 100644 index 0000000000..fb758fe550 --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/index.js @@ -0,0 +1,11 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +'use strict'; + +module.exports = { + get otelInstrumentations() { + return require('./wrap'); + } +}; diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/restify.js b/packages/core/src/tracing/opentelemetry-instrumentations/restify.js new file mode 100644 index 0000000000..6dd165d378 --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/restify.js @@ -0,0 +1,33 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +'use strict'; + +const semver = require('semver'); +const constants = require('../constants'); + +module.exports.init = () => { + // No support for Node v18 yet. + // https://github.com/restify/node-restify/issues/1925 + // https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1339 + if (!semver.lt(process.versions.node, '18.0.0')) return; + + const { RestifyInstrumentation } = require('@opentelemetry/instrumentation-restify'); + + const instrumentation = new RestifyInstrumentation(); + + if (!instrumentation.getConfig().enabled) { + instrumentation.enable(); + } +}; + +module.exports.getKind = otelSpan => { + let kind = constants.EXIT; + + if (otelSpan.attributes && otelSpan.attributes['restify.type'] === 'middleware') { + kind = constants.INTERMEDIATE; + } + + return kind; +}; diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/socket.io.js b/packages/core/src/tracing/opentelemetry-instrumentations/socket.io.js new file mode 100644 index 0000000000..d9e69202ea --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/socket.io.js @@ -0,0 +1,50 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ + +'use strict'; + +const constants = require('../constants'); + +const isOnEvent = otelSpan => otelSpan.name.indexOf('receive') !== -1; +/** + * socket.io-client is not instrumented. + * We can easily instrument socket.io-client by instrumenting @socket.io/component-emitter + * but the client is usually used in the browser, therefor we want to wait for requests. + * Receiving messages does not create spans, only emitting. + * https://github.com/socketio/socket.io-client/blob/4.6.1/lib/socket.ts#L9 + * + * Trace correlation does not work with socket.io, because they do not support + * headers or meta data, only payload. + */ +exports.init = () => { + const { SocketIoInstrumentation } = require('@opentelemetry/instrumentation-socket.io'); + const instrumentation = new SocketIoInstrumentation(); + + if (!instrumentation.getConfig().enabled) { + instrumentation.enable(); + } +}; + +exports.getKind = otelSpan => { + let kind = constants.EXIT; + + if (isOnEvent(otelSpan)) { + kind = constants.ENTRY; + } + + return kind; +}; + +exports.transform = otelSpan => { + // NOTE: this adaption is needed to show the event name instead of a '/' for the endpoint name in the UI + if (otelSpan.attributes && 'messaging.socket.io.event_name' in otelSpan.attributes) { + if (isOnEvent(otelSpan)) { + otelSpan.attributes['messaging.destination'] = `ON ${otelSpan.attributes['messaging.socket.io.event_name']}`; + } else { + otelSpan.attributes['messaging.destination'] = `EMIT ${otelSpan.attributes['messaging.socket.io.event_name']}`; + } + } + + return otelSpan; +}; diff --git a/packages/core/src/tracing/opentelemetry-instrumentations/wrap.js b/packages/core/src/tracing/opentelemetry-instrumentations/wrap.js new file mode 100644 index 0000000000..d0496f426f --- /dev/null +++ b/packages/core/src/tracing/opentelemetry-instrumentations/wrap.js @@ -0,0 +1,92 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ +// @ts-nocheck + +'use strict'; + +const semver = require('semver'); +const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks'); +const api = require('@opentelemetry/api'); +const { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base'); +const constants = require('../constants'); +const instrumentations = { + '@opentelemetry/instrumentation-fs': { name: 'fs' }, + '@opentelemetry/instrumentation-restify': { name: 'restify' }, + '@opentelemetry/instrumentation-socket.io': { name: 'socket.io' } +}; + +// NOTE: using a logger might create a recursive execution +// logger.debug -> creates fs call -> calls transformToInstanaSpan -> calls logger.debug +// use uninstrumented logger, but useless for production +module.exports.init = (_config, cls) => { + // CASE: otel offically does not support Node < 14 + // https://github.com/open-telemetry/opentelemetry-js/tree/main#supported-runtimes + if (semver.lt(process.versions.node, '14.0.0')) { + return; + } + + Object.keys(instrumentations).forEach(k => { + const value = instrumentations[k]; + const instrumentation = require(`./${value.name}`); + instrumentation.init(cls); + value.module = instrumentation; + }); + + const transformToInstanaSpan = otelSpan => { + if (!otelSpan || !otelSpan.instrumentationLibrary) { + return; + } + + const targetInstrumentionName = otelSpan.instrumentationLibrary.name; + let kind = constants.EXIT; + + if (instrumentations[targetInstrumentionName] && instrumentations[targetInstrumentionName].module) { + const targetInstrumentationModule = instrumentations[targetInstrumentionName].module; + + if (targetInstrumentationModule.getKind) { + kind = targetInstrumentationModule.getKind(otelSpan); + } + + if (targetInstrumentationModule.transform) { + otelSpan = targetInstrumentationModule.transform(otelSpan); + } + } + + if (cls.tracingSuppressed()) { + return; + } + + if (kind === constants.EXIT && cls.skipExitTracing()) { + return; + } + + try { + cls.ns.runAndReturn(() => { + const instanaSpan = cls.startSpan('otel', kind); + instanaSpan.data = { + tags: Object.assign({ name: otelSpan.name }, otelSpan.attributes), + resource: otelSpan.resource.attributes + }; + + const origEnd = otelSpan.end; + otelSpan.end = function instanaOnEnd() { + instanaSpan.transmit(); + return origEnd.apply(this, arguments); + }; + }); + } catch (e) { + // ignore for now + } + }; + + const provider = new BasicTracerProvider(); + api.trace.setGlobalTracerProvider(provider); + api.context.setGlobalContextManager(new AsyncHooksContextManager()); + + const orig = api.trace.setSpan; + api.trace.setSpan = function instanaSetSpan(ctx, span) { + transformToInstanaSpan(span); + return orig.apply(this, arguments); + }; +}; diff --git a/packages/core/src/uninstrumentedFs.js b/packages/core/src/uninstrumentedFs.js new file mode 100644 index 0000000000..53df80d06a --- /dev/null +++ b/packages/core/src/uninstrumentedFs.js @@ -0,0 +1,10 @@ +/* + * (c) Copyright IBM Corp. 2023 + */ +// @ts-nocheck + +'use strict'; + +const fs = require('fs'); +const copy = Object.assign({}, fs); +module.exports = exports = copy; diff --git a/packages/core/src/util/applicationUnderMonitoring.js b/packages/core/src/util/applicationUnderMonitoring.js index 12d02e7948..f73c5fc919 100644 --- a/packages/core/src/util/applicationUnderMonitoring.js +++ b/packages/core/src/util/applicationUnderMonitoring.js @@ -5,7 +5,7 @@ 'use strict'; -const fs = require('fs'); +const fs = require('../uninstrumentedFs'); const path = require('path'); /** @type {import('../logger').GenericLogger} */ diff --git a/packages/core/src/util/normalizeConfig.js b/packages/core/src/util/normalizeConfig.js index 83eee2176c..c6cb11d491 100644 --- a/packages/core/src/util/normalizeConfig.js +++ b/packages/core/src/util/normalizeConfig.js @@ -14,6 +14,7 @@ const constants = require('../tracing/constants'); /** * @typedef {Object} InstanaTracingOption * @property {boolean} [enabled] + * @property {boolean} [useOpentelemetry] * @property {boolean} [automaticTracingEnabled] * @property {boolean} [activateImmediately] * @property {number} [forceTransmissionStartingAt] @@ -98,6 +99,7 @@ const defaults = { }, tracing: { enabled: true, + useOpentelemetry: true, automaticTracingEnabled: true, activateImmediately: false, forceTransmissionStartingAt: 500, @@ -188,6 +190,7 @@ function normalizeTracingConfig(config) { config.tracing = {}; } normalizeTracingEnabled(config); + normalizeUseOpentelemetry(config); normalizeAutomaticTracingEnabled(config); normalizeActivateImmediately(config); normalizeTracingTransmission(config); @@ -220,6 +223,25 @@ function normalizeTracingEnabled(config) { config.tracing.enabled = defaults.tracing.enabled; } +/** + * + * @param {InstanaConfig} config + */ +function normalizeUseOpentelemetry(config) { + if (config.tracing.useOpentelemetry === false) { + return; + } + if (config.tracing.useOpentelemetry === true) { + return; + } + if (process.env['INSTANA_DISABLE_USE_OPENTELEMETRY'] === 'true') { + config.tracing.useOpentelemetry = false; + return; + } + + config.tracing.useOpentelemetry = defaults.tracing.useOpentelemetry; +} + /** * @param {InstanaConfig} config */ diff --git a/packages/core/test/test_util/common_verifications.js b/packages/core/test/test_util/common_verifications.js index 1607de1caf..382705c970 100644 --- a/packages/core/test/test_util/common_verifications.js +++ b/packages/core/test/test_util/common_verifications.js @@ -6,6 +6,7 @@ 'use strict'; const expectExactlyOneMatching = require('./expectExactlyOneMatching'); +const expectExactlyNMatching = require('./expectExactlyNMatching'); const constants = require('../../src/index').tracing.constants; const { expect } = require('chai'); @@ -50,11 +51,13 @@ exports.verifyExitSpan = function verifyExitSpan({ pid, extraTests, testMethod = expectExactlyOneMatching, + kind = constants.EXIT, + n, dataProperty }) { const tests = [ span => { - expect(span.k).to.equal(constants.EXIT); + expect(span.k).to.equal(kind); }, span => { expect(span.n).to.equal(spanName); @@ -82,6 +85,72 @@ exports.verifyExitSpan = function verifyExitSpan({ } ].concat(extraTests || []); + if (testMethod === expectExactlyNMatching) return testMethod(spans, n, tests); + return testMethod(spans, tests); +}; + +// eslint-disable-next-line +exports.verifyIntermediateSpan = function verifyIntermediateSpan({ + spanName, + spans, + parent, + withError, + pid, + extraTests, + testMethod = expectExactlyOneMatching, + n, + dataProperty +}) { + return exports.verifyExitSpan({ + spanName, + spans, + parent, + withError, + pid, + extraTests, + testMethod, + n, + kind: constants.INTERMEDIATE, + dataProperty + }); +}; + +// eslint-disable-next-line +exports.verifyEntrySpan = function verifyEntrySpan({ + spanName, + spans, + withError, + pid, + extraTests, + testMethod = expectExactlyOneMatching, + n, + dataProperty +}) { + const tests = [ + span => { + expect(span.k).to.equal(constants.ENTRY); + }, + span => { + expect(span.n).to.equal(spanName); + }, + span => { + expect(span.f.e).to.equal(pid); + }, + span => { + expect(span.f.h).to.equal('agent-stub-uuid'); + }, + span => { + expect(span.ec).to.equal(withError ? 1 : 0); + }, + span => { + expect(span.data).to.exist; + }, + span => { + expect(span.data[dataProperty || spanName]).to.be.an('object'); + } + ].concat(extraTests || []); + + if (testMethod === expectExactlyNMatching) return testMethod(spans, n, tests); return testMethod(spans, tests); }; diff --git a/packages/core/test/util/normalizeConfig_test.js b/packages/core/test/util/normalizeConfig_test.js index 9f377872a2..7ef992278a 100644 --- a/packages/core/test/util/normalizeConfig_test.js +++ b/packages/core/test/util/normalizeConfig_test.js @@ -377,6 +377,32 @@ describe('util.normalizeConfig', () => { expect(config.tracing.kafka.headerFormat).to.equal('string'); }); + it('should disable opentelemetry if config is set', () => { + const config = normalizeConfig({ + tracing: { useOpentelemetry: false } + }); + expect(config.tracing.useOpentelemetry).to.equal(false); + }); + + it('should enable opentelemetry if config is set', () => { + const config = normalizeConfig({ + tracing: { useOpentelemetry: true } + }); + expect(config.tracing.useOpentelemetry).to.equal(true); + }); + + it('should disable opentelemetry if INSTANA_DISABLE_USE_OPENTELEMETRY is set', () => { + process.env.INSTANA_DISABLE_USE_OPENTELEMETRY = 'true'; + const config = normalizeConfig(); + expect(config.tracing.useOpentelemetry).to.equal(false); + }); + + it('should enable opentelemetry if INSTANA_DISABLE_USE_OPENTELEMETRY is set', () => { + process.env.INSTANA_DISABLE_USE_OPENTELEMETRY = 'false'; + const config = normalizeConfig(); + expect(config.tracing.useOpentelemetry).to.equal(true); + }); + it('should set Kafka header format to both via INSTANA_KAFKA_HEADER_FORMAT', () => { process.env.INSTANA_KAFKA_HEADER_FORMAT = 'both'; const config = normalizeConfig(); @@ -460,10 +486,13 @@ describe('util.normalizeConfig', () => { function checkDefaults(config) { expect(config).to.be.an('object'); + expect(config.serviceName).to.not.exist; + expect(config.metrics).to.be.an('object'); expect(config.metrics.transmissionDelay).to.equal(1000); expect(config.metrics.timeBetweenHealthcheckCalls).to.equal(3000); + expect(config.tracing).to.be.an('object'); expect(config.tracing.enabled).to.be.true; expect(config.tracing.automaticTracingEnabled).to.be.true; @@ -482,6 +511,8 @@ describe('util.normalizeConfig', () => { expect(config.tracing.disableW3cTraceCorrelation).to.be.false; expect(config.tracing.kafka.traceCorrelation).to.be.true; expect(config.tracing.kafka.headerFormat).to.equal('both'); + expect(config.tracing.useOpentelemetry).to.equal(true); + expect(config.secrets).to.be.an('object'); expect(config.secrets.matcherMode).to.equal('contains-ignore-case'); expect(config.secrets.keywords).to.deep.equal(['key', 'pass', 'secret']); diff --git a/packages/google-cloud-run/test/using_api/app.js b/packages/google-cloud-run/test/using_api/app.js index 7028c92269..8de78956e0 100644 --- a/packages/google-cloud-run/test/using_api/app.js +++ b/packages/google-cloud-run/test/using_api/app.js @@ -15,7 +15,6 @@ const http = require('http'); const { delay, sendToParent } = require('../../../core/test/test_util'); - const instana = require('../..'); const port = process.env.PORT || 4216; @@ -55,8 +54,10 @@ app.on('request', (req, res) => { // use Instana SDK to create spans manually instana.sdk.callback.startExitSpan('custom-span', () => { - delay(10).then(() => { - instana.sdk.promise.completeExitSpan(); + // add an additional delay to wait that the span was sent to the BE + instana.sdk.promise.completeExitSpan(); + + delay(100).then(() => { res.end( JSON.stringify({ message: 'Hello Cloud Run!', diff --git a/packages/google-cloud-run/test/using_api/test.js b/packages/google-cloud-run/test/using_api/test.js index 2485716294..15075396e7 100644 --- a/packages/google-cloud-run/test/using_api/test.js +++ b/packages/google-cloud-run/test/using_api/test.js @@ -10,9 +10,8 @@ const path = require('path'); const constants = require('@instana/core').tracing.constants; const Control = require('../Control'); -const { delay, expectExactlyOneMatching } = require('../../../core/test/test_util'); +const { delay, expectExactlyOneMatching, retry } = require('../../../core/test/test_util'); const config = require('../../../serverless/test/config'); -const retry = require('../../../serverless/test/util/retry'); const instanceId = // eslint-disable-next-line max-len diff --git a/packages/shared-metrics/src/dependencies.js b/packages/shared-metrics/src/dependencies.js index fc90f9caa4..b81bffe931 100644 --- a/packages/shared-metrics/src/dependencies.js +++ b/packages/shared-metrics/src/dependencies.js @@ -6,8 +6,7 @@ 'use strict'; const path = require('path'); -const fs = require('fs'); -const { applicationUnderMonitoring } = require('@instana/core').util; +const { util, uninstrumentedFs: fs } = require('@instana/core'); let logger = require('@instana/core').logger.getLogger('metrics'); @@ -43,7 +42,7 @@ exports.activate = function activate() { attempts++; const started = Date.now(); - applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, mainPackageJsonPath) => { + util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, mainPackageJsonPath) => { if (err) { return logger.warn('Failed to determine main package.json. Reason: %s %s ', err.message, err.stack); } else if (!mainPackageJsonPath && attempts < exports.MAX_ATTEMPTS) { @@ -54,7 +53,7 @@ exports.activate = function activate() { logger.info( `Main package.json could not be found after ${attempts} retries. Looking for node_modules folder now.` ); - applicationUnderMonitoring.findNodeModulesFolder((errNodeModules, nodeModulesFolder) => { + util.applicationUnderMonitoring.findNodeModulesFolder((errNodeModules, nodeModulesFolder) => { if (errNodeModules) { return logger.warn('Failed to determine node_modules folder. Reason: %s %s ', err.message, err.stack); } else if (!nodeModulesFolder) { @@ -69,7 +68,7 @@ exports.activate = function activate() { } let dependencyDir; - if (applicationUnderMonitoring.isAppInstalledIntoNodeModules()) { + if (util.applicationUnderMonitoring.isAppInstalledIntoNodeModules()) { dependencyDir = path.join(path.dirname(mainPackageJsonPath), '..', '..', 'node_modules'); } else { dependencyDir = path.join(path.dirname(mainPackageJsonPath), 'node_modules'); diff --git a/packages/shared-metrics/src/directDependencies.js b/packages/shared-metrics/src/directDependencies.js index 30f1d04178..5b521518bc 100644 --- a/packages/shared-metrics/src/directDependencies.js +++ b/packages/shared-metrics/src/directDependencies.js @@ -5,9 +5,7 @@ 'use strict'; -const fs = require('fs'); - -const { applicationUnderMonitoring } = require('@instana/core').util; +const { util, uninstrumentedFs: fs } = require('@instana/core'); let logger = require('@instana/core').logger.getLogger('metrics'); @@ -33,7 +31,7 @@ let attempts = 0; exports.activate = function activate() { attempts++; - applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, packageJsonPath) => { + util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, packageJsonPath) => { if (err) { return logger.info( 'Failed to determine main package.json for analysis of direct dependencies. Reason: %s %s ', diff --git a/packages/shared-metrics/src/util/DependencyDistanceCalculator.js b/packages/shared-metrics/src/util/DependencyDistanceCalculator.js index 6d7c7dcd72..0aee4fbfeb 100644 --- a/packages/shared-metrics/src/util/DependencyDistanceCalculator.js +++ b/packages/shared-metrics/src/util/DependencyDistanceCalculator.js @@ -6,12 +6,12 @@ 'use strict'; const assert = require('assert'); -const fs = require('fs'); +const { logger: Logger, uninstrumentedFs: fs } = require('@instana/core'); const path = require('path'); const CountDownLatch = require('./CountDownLatch'); -let logger = require('@instana/core').logger.getLogger('metrics'); +let logger = Logger.getLogger('metrics'); /** * @param {import('@instana/core/src/logger').GenericLogger} _logger diff --git a/packages/shared-metrics/src/util/nativeModuleRetry.js b/packages/shared-metrics/src/util/nativeModuleRetry.js index 88733adc32..94ed4b1ae2 100644 --- a/packages/shared-metrics/src/util/nativeModuleRetry.js +++ b/packages/shared-metrics/src/util/nativeModuleRetry.js @@ -5,11 +5,11 @@ 'use strict'; -let logger = require('@instana/core').logger.getLogger('shared-metrics/native-module-retry'); +const { logger: Logger, uninstrumentedFs: fs } = require('@instana/core'); +let logger = Logger.getLogger('shared-metrics/native-module-retry'); const EventEmitter = require('events'); const copy = require('recursive-copy'); -const fs = require('fs'); const os = require('os'); const tar = require('tar'); const path = require('path'); diff --git a/packages/shared-metrics/test/activeRequests_test.js b/packages/shared-metrics/test/activeRequests_test.js index be850eebd6..7068087cc1 100644 --- a/packages/shared-metrics/test/activeRequests_test.js +++ b/packages/shared-metrics/test/activeRequests_test.js @@ -6,7 +6,7 @@ 'use strict'; const expect = require('chai').expect; -const fs = require('fs'); +const { uninstrumentedFs: fs } = require('@instana/core'); const activeRequests = require('../src/activeRequests');