From 189f896d9c8e836cffa4a6eccaa97d77f3f3671d Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 30 Jun 2021 13:11:56 +0300 Subject: [PATCH 01/16] feat: implement nestjs-core instrumentation --- .../.eslintignore | 1 + .../.eslintrc.js | 7 + .../.npmignore | 4 + .../LICENSE | 201 ++++++++++++++ .../README.md | 62 +++++ .../package.json | 78 ++++++ .../scripts/test-all-versions | 78 ++++++ .../src/enums/AttributeNames.ts | 26 ++ .../src/enums/NestType.ts | 21 ++ .../src/enums/index.ts | 18 ++ .../src/index.ts | 21 ++ .../src/instrumentation.ts | 251 ++++++++++++++++++ .../src/utils.ts | 27 ++ .../src/version.ts | 18 ++ .../test/index.test.ts | 222 ++++++++++++++++ .../test/setup.ts | 215 +++++++++++++++ .../tsconfig.json | 11 + 17 files changed, 1261 insertions(+) create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintignore create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintrc.js create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/.npmignore create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/LICENSE create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/README.md create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/package.json create mode 100755 plugins/node/opentelemetry-instrumentation-nestjs-core/scripts/test-all-versions create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/NestType.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/index.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts create mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/tsconfig.json diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintignore b/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintignore @@ -0,0 +1 @@ +build diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintrc.js b/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintrc.js new file mode 100644 index 0000000000..5054f4d287 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + env: { + mocha: true, + node: true + }, + ...require('../../../eslint.config.js') +}; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/.npmignore b/plugins/node/opentelemetry-instrumentation-nestjs-core/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/LICENSE b/plugins/node/opentelemetry-instrumentation-nestjs-core/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + http://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. diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md new file mode 100644 index 0000000000..fa3e0d6bb4 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md @@ -0,0 +1,62 @@ +# OpenTelemetry NestJS Instrumentation for Node.js + +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + +This module provides automatic tracing instrumentation for [Nest framework][pkg-web-url]. + +## Installation + +```bash +npm install --save @opentelemetry/instrumentation-nestjs-core +``` + +### Supported Versions + +- `>=4.0.0` + +## Usage + +OpenTelemetry Nest Instrumentation allows the user to automatically collect trace data from the controller handlers and export them to the backend of choice. + +To load a specific instrumentation (**Nest** in this case), specify it in the registerInstrumentations' configuration. + +```javascript +const { NodeTracerProvider } = require('@opentelemetry/node'); +const { NestInstrumentation } = require('@opentelemetry/instrumentation-nestjs-core'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); + +const provider = new NodeTracerProvider(); +provider.register(); + +registerInstrumentations({ + instrumentations: [ + new NestInstrumentation(), + ], +}); +``` + +## Useful links + +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us in [GitHub Discussions][discussions-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions +[license-url]: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://status.david-dm.org/gh/open-telemetry/opentelemetry-js-contrib.svg?path=plugins%2Fnode%2Fopentelemetry-instrumentation-nestjs-core +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins%2Fnode%2Fopentelemetry-instrumentation-nestjs-core +[devDependencies-image]: https://status.david-dm.org/gh/open-telemetry/opentelemetry-js-contrib.svg?path=plugins%2Fnode%2Fopentelemetry-instrumentation-nestjs-core&type=dev +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins%2Fnode%2Fopentelemetry-instrumentation-nestjs-core&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-nestjs-core +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-nestjs-core.svg +[pkg-repo-url]: https://github.com/nestjs/nest +[pkg-npm-url]: https://www.npmjs.com/package/@nestjs/core +[pkg-web-url]: https://nestjs.com/ diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json new file mode 100644 index 0000000000..ecefb61437 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -0,0 +1,78 @@ +{ + "name": "@opentelemetry/instrumentation-nestjs-core", + "version": "0.21.0", + "description": "OpenTelemetry NestJS automatic instrumentation package.", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "repository": "open-telemetry/opentelemetry-js-contrib", + "scripts": { + "clean": "rimraf build/*", + "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "compile": "npm run version:update && tsc -p .", + "compile:watch": "tsc -w", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "precompile": "tsc --version", + "prepare": "npm run compile", + "tdd": "npm run test -- --watch-extensions ts --watch", + "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'", + "version:update": "node ../../../scripts/version-update.js" + }, + "keywords": [ + "opentelemetry", + "nestjs", + "nodejs", + "tracing", + "profiling", + "instrumentation" + ], + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "peerDependencies": { + "@opentelemetry/api": "^0.21.0" + }, + "devDependencies": { + "@nestjs/common": "^8.0.5", + "@nestjs/core": "^8.0.5", + "@nestjs/microservices": "^8.0.5", + "@nestjs/platform-express": "^8.0.5", + "@nestjs/websockets": "^8.0.5", + "@opentelemetry/api": "0.21.0", + "@opentelemetry/context-async-hooks": "0.21.0", + "@opentelemetry/node": "0.21.0", + "@opentelemetry/tracing": "0.21.0", + "@types/mocha": "7.0.2", + "@types/node": "14.17.2", + "@types/semver": "^7.3.8", + "@types/vinyl-fs": "^2.4.12", + "codecov": "3.8.2", + "cross-env": "7.0.3", + "gts": "3.1.0", + "mocha": "7.2.0", + "nyc": "15.1.0", + "reflect-metadata": "^0.1.13", + "rimraf": "3.0.2", + "rxjs": "^7.2.0", + "rxjs-compat": "^6.6.7", + "semver": "^7.3.5", + "ts-mocha": "8.0.0", + "typescript": "4.3.2" + }, + "dependencies": { + "@opentelemetry/instrumentation": "^0.21.0", + "@opentelemetry/semantic-conventions": "^0.21.0" + } +} diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/scripts/test-all-versions b/plugins/node/opentelemetry-instrumentation-nestjs-core/scripts/test-all-versions new file mode 100755 index 0000000000..07de70e070 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/scripts/test-all-versions @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +# return to the default package.json and install all deps +git checkout -- package.json +npm install + +test_silent () { + npm run test &> /dev/null && echo OK || echo FAIL +} + +echo -e "\n## 4.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^4.0.0 \ + @nestjs/core@^4.0.0 \ + @nestjs/microservices@^4.0.0 \ + @nestjs/websockets@^4.0.0 \ + rxjs@^5.4.2 \ + rxjs-compat@^6.0.0 > /dev/null +test_silent + +echo -e "\n## ^4.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^4.4.0 \ + @nestjs/core@^4.4.0 \ + @nestjs/microservices@^4.4.0 \ + @nestjs/websockets@^4.4.0 \ + rxjs@^5.4.2 \ + rxjs-compat@^6.0.0 > /dev/null +test_silent + +echo -e "\n## ^5.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^5.0.0 \ + @nestjs/core@^5.0.0 \ + @nestjs/microservices@^5.0.0 \ + @nestjs/websockets@^5.0.0 \ + rxjs@^6.0.0 \ + rxjs-compat@^6.0.0 > /dev/null +test_silent + +echo -e "\n## ^6.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^6.0.0 \ + @nestjs/core@^6.0.0 \ + @nestjs/microservices@^6.0.0 \ + @nestjs/websockets@^6.0.0 \ + @nestjs/platform-express@^6.0.0 \ + rxjs@^6.0.0 \ + rxjs-compat@^6.0.0 > /dev/null +test_silent + +echo -e "\n## ^7.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^7.0.0 \ + @nestjs/core@^7.0.0 \ + @nestjs/microservices@^7.0.0 \ + @nestjs/websockets@^7.0.0 \ + @nestjs/platform-express@^7.0.0 \ + rxjs@^7.0.0 \ + rxjs-compat@latest > /dev/null +test_silent + +echo -e "\n## ^8.0.0" +npm install -D \ + reflect-metadata@0.1.13 \ + @nestjs/common@^8.0.0 \ + @nestjs/core@^8.0.0 \ + @nestjs/microservices@^8.0.0 \ + @nestjs/websockets@^8.0.0 \ + @nestjs/platform-express@^8.0.0 \ + rxjs@^7.2.0 \ + rxjs-compat@latest > /dev/null +test_silent diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts new file mode 100644 index 0000000000..88c94f2f46 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts @@ -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. + */ + +export enum AttributeNames { + VERSION = 'nestjs.version', + TYPE = 'nestjs.type', + MODULE = 'nestjs.module', + CONTROLLER_INSTANCE = 'nestjs.controller.instance', + CALLBACK = 'nestjs.callback', + PIPES = 'nestjs.pipes', + INTERCEPTORS = 'nestjs.interceptors', + GUARDS = 'nestjs.guards', +} diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/NestType.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/NestType.ts new file mode 100644 index 0000000000..69e6fa60b8 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/NestType.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +export enum NestType { + APP_CREATION = 'app_creation', + REQUEST_CONTEXT = 'request_context', + REQUEST_HANDLER = 'handler', +} diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/index.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/index.ts new file mode 100644 index 0000000000..83f7d0769d --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { AttributeNames } from './AttributeNames'; +export { NestType } from './NestType'; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts new file mode 100644 index 0000000000..eb8cc76b14 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +import { Instrumentation } from './instrumentation'; + +export * from './instrumentation'; +export default Instrumentation; +export { Instrumentation as NestInstrumentation }; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts new file mode 100644 index 0000000000..8866653742 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts @@ -0,0 +1,251 @@ +/* + * 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. + */ + +import * as api from '@opentelemetry/api'; +import { + InstrumentationBase, + InstrumentationNodeModuleDefinition, + InstrumentationNodeModuleFile, + isWrapped, +} from '@opentelemetry/instrumentation'; +import type * as NestJS from '@nestjs/core'; +import type { NestFactory } from '@nestjs/core/nest-factory.js'; +import type { RouterExecutionContext } from '@nestjs/core/router/router-execution-context.js'; +import type { Controller } from '@nestjs/common/interfaces'; +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; +import { VERSION } from './version'; +import { AttributeNames, NestType } from './enums'; + +export class Instrumentation extends InstrumentationBase { + static readonly COMPONENT = '@nestjs/core'; + static readonly COMMON_ATTRIBUTES = { + component: Instrumentation.COMPONENT, + }; + + constructor() { + super( + '@opentelemetry/instrumentation-nestjs-core', + VERSION + ); + } + + init() { + const module = new InstrumentationNodeModuleDefinition( + Instrumentation.COMPONENT, + ['>=4.0.0'], + (moduleExports, moduleVersion) => { + this._diag.debug( + `Patching ${Instrumentation.COMPONENT}@${moduleVersion}` + ); + return moduleExports; + }, + (moduleExports, moduleVersion) => { + this._diag.debug( + `Unpatching ${Instrumentation.COMPONENT}@${moduleVersion}` + ); + if (moduleExports === undefined) return; + } + ); + + module.files.push( + this.getNestFactoryFileInstrumentation(['>=4.0.0']), + this.getRouterExecutionContextFileInstrumentation(['>=4.0.0']) + ); + + return module; + } + + getNestFactoryFileInstrumentation(versions: string[]) { + return new InstrumentationNodeModuleFile( + '@nestjs/core/nest-factory.js', + versions, + (NestFactoryStatic: any, moduleVersion?: string) => { + this.ensureWrapped( + moduleVersion, + NestFactoryStatic.NestFactoryStatic.prototype, + 'create', + createWrapNestFactoryCreate(this.tracer, moduleVersion) + ); + return NestFactoryStatic; + }, + (NestFactoryStatic: any) => { + this._unwrap(NestFactoryStatic.NestFactoryStatic.prototype, 'create'); + } + ); + } + + getRouterExecutionContextFileInstrumentation(versions: string[]) { + return new InstrumentationNodeModuleFile( + '@nestjs/core/router/router-execution-context.js', + versions, + (RouterExecutionContext: any, moduleVersion?: string) => { + this.ensureWrapped( + moduleVersion, + RouterExecutionContext.RouterExecutionContext.prototype, + 'create', + createWrapCreateHandler(this.tracer, moduleVersion) + ); + return RouterExecutionContext; + }, + (RouterExecutionContext: any) => { + this._unwrap( + RouterExecutionContext.RouterExecutionContext.prototype, + 'create' + ); + } + ); + } + + private ensureWrapped( + moduleVersion: string | undefined, + obj: any, + methodName: string, + wrapper: (original: any) => any + ) { + this._diag.debug( + `Applying ${methodName} patch for ${Instrumentation.COMPONENT}@${moduleVersion}` + ); + if (isWrapped(obj[methodName])) { + this._unwrap(obj, methodName); + } + this._wrap(obj, methodName, wrapper); + } +} + +function createWrapNestFactoryCreate( + tracer: api.Tracer, + moduleVersion?: string +) { + return function wrapCreate(original: typeof NestFactory.create) { + return function createWithTrace( + this: typeof NestFactory, + nestModule: any + /* serverOrOptions */ + ) { + const span = tracer.startSpan('Create Nest App', { + attributes: { + ...Instrumentation.COMMON_ATTRIBUTES, + [AttributeNames.TYPE]: NestType.APP_CREATION, + [AttributeNames.VERSION]: moduleVersion, + [AttributeNames.MODULE]: nestModule.name, + }, + }); + const spanContext = api.trace.setSpan(api.context.active(), span); + + return api.context.with(spanContext, async () => { + try { + return await original.apply(this, arguments as any); + } catch (e) { + throw addError(span, e); + } finally { + span.end(); + } + }); + }; + }; +} + +function createWrapCreateHandler(tracer: api.Tracer, moduleVersion?: string) { + return function wrapCreateHandler( + original: RouterExecutionContext['create'] + ) { + return function createHandlerWithTrace( + this: RouterExecutionContext, + instance: Controller, + callback: (...args: any[]) => unknown + ) { + arguments[1] = createWrapHandler(tracer, moduleVersion, callback); + const handler = original.apply(this, arguments as any); + return function ( + this: any, + req: any, + res: any, + next: (...args: any[]) => unknown + ) { + const callbackName = callback.name; + const instanceName = + instance.constructor && instance.constructor.name + ? instance.constructor.name + : 'UnnamedInstance'; + const spanName = callbackName + ? `${instanceName}.${callbackName}` + : instanceName; + + const span = tracer.startSpan(spanName, { + attributes: { + ...Instrumentation.COMMON_ATTRIBUTES, + [AttributeNames.VERSION]: moduleVersion, + [AttributeNames.TYPE]: NestType.REQUEST_CONTEXT, + [SemanticAttributes.HTTP_METHOD]: req.method, + [SemanticAttributes.HTTP_URL]: req.originalUrl, + [SemanticAttributes.HTTP_ROUTE]: req.route.path, + [AttributeNames.CALLBACK]: callbackName, + }, + }); + const spanContext = api.trace.setSpan(api.context.active(), span); + + return api.context.with(spanContext, async () => { + try { + return await handler.apply(this, arguments as any); + } catch (e) { + throw addError(span, e); + } finally { + span.end(); + } + }); + }; + }; + }; +} + +function createWrapHandler( + tracer: api.Tracer, + moduleVersion: string | undefined, + handler: Function +) { + const wrappedHandler = function (this: RouterExecutionContext) { + const span = tracer.startSpan(handler.name || 'anonymous nest handler', { + attributes: { + ...Instrumentation.COMMON_ATTRIBUTES, + [AttributeNames.VERSION]: moduleVersion, + [AttributeNames.TYPE]: NestType.REQUEST_HANDLER, + [AttributeNames.CALLBACK]: handler.name, + }, + }); + const spanContext = api.trace.setSpan(api.context.active(), span); + + return api.context.with(spanContext, async () => { + try { + return await handler.apply(this, arguments); + } catch (e) { + throw addError(span, e); + } finally { + span.end(); + } + }); + }; + + if (handler.name) { + Object.defineProperty(wrappedHandler, 'name', { value: handler.name }); + } + return wrappedHandler; +} + +const addError = (span: api.Span, error: Error) => { + span.recordException(error); + span.setStatus({ code: api.SpanStatusCode.ERROR, message: error.message }); + return error; +}; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts new file mode 100644 index 0000000000..24d41ae7fe --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// util.types.isPromise is supported from 10.0.0 +export const isPromise = (value: any): value is Promise => { + if ( + typeof value.then === 'function' && + typeof value.catch === 'function' && + value.toString() === '[object Promise]' + ) { + return true; + } + return false; +}; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts new file mode 100644 index 0000000000..fb47fc303b --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// this is autogenerated file, see scripts/version-update.js +export const VERSION = '0.21.0'; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts new file mode 100644 index 0000000000..45f94e73e9 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts @@ -0,0 +1,222 @@ +/* + * 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. + */ + +import * as semver from 'semver'; + +import { context, SpanStatusCode } from '@opentelemetry/api'; +import { NodeTracerProvider } from '@opentelemetry/node'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; +import * as assert from 'assert'; +import Instrumentation from '../src'; +import { getRequester, setup, App } from './setup'; + +import * as util from 'util'; + +const LIB_VERSION = require('@nestjs/core/package.json').version; + +const instrumentation = new Instrumentation(); +const memoryExporter = new InMemorySpanExporter(); + +util.inspect.defaultOptions.depth = 3; +util.inspect.defaultOptions.breakLength = 200; + +describe('nestjs-core', () => { + const provider = new NodeTracerProvider(); + provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + instrumentation.setTracerProvider(provider); + let contextManager: AsyncHooksContextManager; + let app: App; + let request = async (path: string): Promise => { + throw new Error('Not yet initialized.'); + }; + + beforeEach(async () => { + contextManager = new AsyncHooksContextManager(); + context.setGlobalContextManager(contextManager.enable()); + instrumentation.setConfig({}); + instrumentation.enable(); + + app = await setup(LIB_VERSION); + request = getRequester(app); + }); + + afterEach(async () => { + await app.close(); + + memoryExporter.reset(); + context.disable(); + instrumentation.disable(); + }); + + before(() => {}); + + after(() => {}); + + it('should capture setup', async () => { + assertSpans(memoryExporter.getFinishedSpans(), [ + { service: 'test', name: 'Create Nest App', module: 'AppModule' }, + ]); + }); + + it('should capture requests', async () => { + const path = semver.intersects(LIB_VERSION, '<5.0.0') ? '/' : '/users'; + const url = '/users'; + const instance = 'UsersController'; + const callback = 'getUsers'; + + assert.strictEqual(await request('/users'), 'Hello, world!\n'); + + assertSpans(memoryExporter.getFinishedSpans(), [ + { service: 'test', name: 'Create Nest App', module: 'AppModule' }, + { + service: 'test', + name: callback, + callback, + parentSpanName: `${instance}.${callback}`, + }, + { + service: 'test', + name: `${instance}.${callback}`, + method: 'GET', + url, + path, + callback, + }, + ]); + }); + + it('should capture errors', async () => { + const path = semver.intersects(LIB_VERSION, '<5.0.0') ? '/' : '/errors'; + const url = '/errors'; + const instance = 'ErrorController'; + const callback = 'getError'; + + assert.strictEqual( + await request('/errors'), + '{"statusCode":500,"message":"Internal server error"}' + ); + + assertSpans(memoryExporter.getFinishedSpans(), [ + { service: 'test', name: 'Create Nest App', module: 'AppModule' }, + { + service: 'test', + name: callback, + callback, + status: { + code: SpanStatusCode.ERROR, + message: 'custom error', + }, + parentSpanName: `${instance}.${callback}`, + }, + { + service: 'test', + name: `${instance}.${callback}`, + method: 'GET', + url, + path, + callback, + status: { + code: SpanStatusCode.ERROR, + message: 'custom error', + }, + }, + ]); + }); +}); + +const assertSpans = (actualSpans: any[], expectedSpans: any[]) => { + assert(Array.isArray(actualSpans), 'Expected `actualSpans` to be an array'); + assert( + Array.isArray(expectedSpans), + 'Expected `expectedSpans` to be an array' + ); + assert.strictEqual( + actualSpans.length, + expectedSpans.length, + 'Expected span count different from actual' + ); + + actualSpans.forEach((span, idx) => { + const expected = expectedSpans[idx]; + if (expected === null) return; + try { + assert.notStrictEqual(span, undefined); + assert.notStrictEqual(expected, undefined); + + assert.strictEqual(span.attributes.component, '@nestjs/core'); + assert.strictEqual(span.attributes['nestjs.module'], expected.module); + + assert.strictEqual(span.name, expected.name); + + assert.strictEqual(span.attributes['http.method'], expected.method); + assert.strictEqual(span.attributes['http.url'], expected.url); + assert.strictEqual(span.attributes['http.route'], expected.path); + assert.strictEqual(span.attributes['nestjs.callback'], expected.callback); + assert.strictEqual( + span.attributes['nest.controller.instance'], + expected.instance + ); + + assert.strictEqual(span.attributes.component, Instrumentation.COMPONENT); + assert.strictEqual( + typeof span.attributes['nestjs.version'], + 'string', + 'nestjs.version not specified' + ); + assert.deepEqual( + span.status, + expected.status || { code: SpanStatusCode.UNSET } + ); + if (typeof expected.parentSpanIdx === 'number') { + assert.strictEqual( + span.parentSpanId, + actualSpans[expected.parentSpanIdx].spanContext().spanId + ); + } else if (typeof expected.parentSpanName === 'string') { + const parentSpan = actualSpans.find( + s => s.name === expected.parentSpanName + ); + assert.notStrictEqual( + parentSpan, + undefined, + `Cannot find span named ${expected.parentSpanName} expected to be the parent of ${span.name}` + ); + assert.strictEqual( + span.parentSpanId, + parentSpan.spanContext().spanId, + `Expected "${expected.parentSpanName}" to be the parent of "${ + span.name + }", but found "${ + actualSpans.find(s => s.spanContext().spanId === span.parentSpanId) + .name + }"` + ); + } else if (expected.parentSpan !== null) { + assert.strictEqual( + span.parentSpanId, + expected.parentSpan?.spanContext().spanId + ); + } + } catch (e) { + e.message = `At span[${idx}] "${span.name}": ${e.message}`; + throw e; + } + }); +}; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts new file mode 100644 index 0000000000..e91da557cd --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts @@ -0,0 +1,215 @@ +/* + * 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. + */ +import * as http from 'http'; +import * as semver from 'semver'; +import { AddressInfo } from 'net'; +import { + CanActivate, + ExecutionContext, + NestInterceptor, + CallHandler, +} from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +// mimics the support for @decorators +const __decorate = function ( + decorators: any, + target?: any, + key?: any, + desc?: any +) { + if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') { + return Reflect.decorate(decorators, target, key, desc); + } + switch (arguments.length) { + case 2: + return decorators.reduceRight((o: any, d: Function) => { + return (d && d(o)) || o; + }, target); + case 3: + return decorators.reduceRight((o: any, d: Function) => { + return (d && d(target, key)) || o; + }, void 0); + case 4: + return decorators.reduceRight((o: any, d: Function) => { + return (d && d(target, key, o)) || o; + }, desc); + } +}; + +const decorateProperty = (obj: any, propName: string, decorators: any) => { + Object.defineProperty( + obj, + propName, + __decorate( + Array.isArray(decorators) ? decorators : [decorators], + obj, + propName, + Object.getOwnPropertyDescriptor(obj, propName) + ) + ); +}; + +const makeModule = ( + name = 'Unnamed', + handler = (...args: unknown[]) => {}, + controllerDecorators: any[] = [] +) => { + const common = require('@nestjs/common'); + const methodName = `get${name}`; + + let Controller = class { + [methodName](...args: any[]) { + return handler(...args); + } + }; + Object.defineProperty(Controller, 'name', { value: `${name}Controller` }); + + Controller = __decorate(controllerDecorators, Controller); + decorateProperty(Controller.prototype, methodName, [common.Get()]); + + let Module = class {}; + Object.defineProperty(Module, 'name', { value: `${name}Module` }); + + Module = __decorate( + [ + common.Module({ + controllers: [Controller], + }), + ], + Module + ); + + return [Controller, Module]; +}; + +export type App = { + close: Function; +}; + +export const setup = async (version: string): Promise => { + const core = require('@nestjs/core'); + const common = require('@nestjs/common'); + + let AppModule = class AppModule {}; + let MyGuard = class MyGuard implements CanActivate { + canActivate(context: ExecutionContext): boolean { + return true; + } + }; + MyGuard = __decorate( + [ + semver.intersects(version, '^4.0.0') + ? common.Guard() + : common.Injectable(), + ], + MyGuard + ); + let YellInterceptor = class YellInterceptor implements NestInterceptor { + intercept(context: ExecutionContext, next: CallHandler): Observable { + return next + .handle() + .pipe( + map(value => + typeof value === 'string' ? value.toUpperCase() : value + ) + ); + } + }; + YellInterceptor = __decorate( + [ + semver.intersects(version, '^4.0.0') + ? common.Interceptor() + : common.Injectable(), + ], + YellInterceptor + ); + + const [UsersController, UsersModule] = makeModule('Users', () => 'Hello, world!\n', [ + common.Controller('users'), + ]); + const [GuardedController, GuardedModule] = makeModule('Guarded', () => 'Hello, guarded!\n', [ + common.Controller('guarded'), + common.UseGuards(MyGuard), + common.UseGuards(MyGuard), + ]); + const [InterceptedController, InterceptedModule] = makeModule( + 'Intercepted', + () => 'Hello, Intercepted!\n', + [ + common.Controller('intercepted'), + common.UseInterceptors(YellInterceptor), + common.UseInterceptors(YellInterceptor), + ] + ); + const [ErrorController, ErrorModule] = makeModule( + 'Error', + () => { + throw new Error('custom error'); + }, + [common.Controller('errors')] + ); + + if (semver.intersects(version, '>=4.6.3')) { + AppModule = __decorate( + [ + common.Module({ + imports: [UsersModule, ErrorModule, GuardedModule, InterceptedModule], + controllers: [UsersController, ErrorController, GuardedController, InterceptedController], + }), + ], + AppModule + ); + } else { + AppModule = __decorate( + [ + common.Module({ + modules: [UsersModule, ErrorModule, GuardedModule, InterceptedModule], + controllers: [UsersController, ErrorController, GuardedController, InterceptedController], + }), + ], + AppModule + ); + } + + const app = await core.NestFactory.create(AppModule); + await app.listenAsync(0, 'localhost'); + + return app as App; +}; + +export const getRequester = (app: any) => { + const port = (app.httpServer.address() as AddressInfo).port; + return (path: string) => { + return new Promise((resolve, reject) => { + return http.get(`http://localhost:${port}${path}`, resp => { + let data = ''; + resp.on('data', chunk => { + data += chunk; + }); + resp.on('end', () => { + resolve(data); + }); + resp.on('error', err => { + reject(err); + }); + }); + }); + }; +}; + +export default setup; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/tsconfig.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/tsconfig.json new file mode 100644 index 0000000000..28be80d266 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} From 64b16b3d3bdf15b60ee10e00ab46c369b7c58b4c Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 17:41:47 +0300 Subject: [PATCH 02/16] fix: update versions --- .../package.json | 16 ++++++++-------- .../src/version.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json index ecefb61437..f348f8fa52 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-nestjs-core", - "version": "0.21.0", + "version": "0.23.0", "description": "OpenTelemetry NestJS automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -42,7 +42,7 @@ "access": "public" }, "peerDependencies": { - "@opentelemetry/api": "^0.21.0" + "@opentelemetry/api": "^1.0.1" }, "devDependencies": { "@nestjs/common": "^8.0.5", @@ -50,10 +50,10 @@ "@nestjs/microservices": "^8.0.5", "@nestjs/platform-express": "^8.0.5", "@nestjs/websockets": "^8.0.5", - "@opentelemetry/api": "0.21.0", - "@opentelemetry/context-async-hooks": "0.21.0", - "@opentelemetry/node": "0.21.0", - "@opentelemetry/tracing": "0.21.0", + "@opentelemetry/api": "1.0.1", + "@opentelemetry/context-async-hooks": "0.23.0", + "@opentelemetry/node": "0.23.0", + "@opentelemetry/tracing": "0.23.0", "@types/mocha": "7.0.2", "@types/node": "14.17.2", "@types/semver": "^7.3.8", @@ -72,7 +72,7 @@ "typescript": "4.3.2" }, "dependencies": { - "@opentelemetry/instrumentation": "^0.21.0", - "@opentelemetry/semantic-conventions": "^0.21.0" + "@opentelemetry/instrumentation": "^0.23.0", + "@opentelemetry/semantic-conventions": "^0.23.0" } } diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts index fb47fc303b..113a67d8b1 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.21.0'; +export const VERSION = '0.23.0'; From cc028c8330ccf4a5aa74ff4aeb3d1a5fe529cadc Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 17:44:07 +0300 Subject: [PATCH 03/16] feat: assure forward compatibility with next versions of Nest In v8 there's a deprecation warning for `listenAsync`. --- .../opentelemetry-instrumentation-nestjs-core/test/setup.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts index e91da557cd..9a18740e55 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts @@ -187,7 +187,11 @@ export const setup = async (version: string): Promise => { } const app = await core.NestFactory.create(AppModule); - await app.listenAsync(0, 'localhost'); + if (app.listenAsync) { + await app.listenAsync(0, 'localhost'); + } else { + await app.listen(0, 'localhost'); + } return app as App; }; From 10eb8d69eec6345cb6d30c4e5500ddec822fff52 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 18:08:32 +0300 Subject: [PATCH 04/16] refactor: rename controller attribute --- .../src/enums/AttributeNames.ts | 2 +- .../src/instrumentation.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts index 88c94f2f46..da84db8f25 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/enums/AttributeNames.ts @@ -18,7 +18,7 @@ export enum AttributeNames { VERSION = 'nestjs.version', TYPE = 'nestjs.type', MODULE = 'nestjs.module', - CONTROLLER_INSTANCE = 'nestjs.controller.instance', + CONTROLLER = 'nestjs.controller', CALLBACK = 'nestjs.callback', PIPES = 'nestjs.pipes', INTERCEPTORS = 'nestjs.interceptors', diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts index 8866653742..69c1c7de29 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts @@ -192,6 +192,7 @@ function createWrapCreateHandler(tracer: api.Tracer, moduleVersion?: string) { [SemanticAttributes.HTTP_METHOD]: req.method, [SemanticAttributes.HTTP_URL]: req.originalUrl, [SemanticAttributes.HTTP_ROUTE]: req.route.path, + [AttributeNames.CONTROLLER]: instanceName, [AttributeNames.CALLBACK]: callbackName, }, }); From 331b456ae5ac06aa6b287ec9ce51099c037d54b9 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 18:09:48 +0300 Subject: [PATCH 05/16] docs: list all emitted spans and attributes --- .../README.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md index fa3e0d6bb4..a476c2b567 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md @@ -38,6 +38,30 @@ registerInstrumentations({ }); ``` +## Emitted Spans + +| Name | Description | Included attributes +| ---- | ---- | ---- +`Create Nest App` | Traces the bootup for the Nest App. The `NestFactory(Static).create` call. | `nestjs.module` +`.` | Traces the whole request context. | `http.*`, `nestjs.callback` +`` | Traces the work of a specific controller member function. | `nestjs.callback` + +#### Attributes + +| Name | Description +| ---- | ---- +| `component`* | "@nestjs/core" +| `nestjs.version`* | Version of instrumented `@nestjs/core` package +| `nestjs.type`* | See [NestType](./src/enums/NestType.ts) +| `nestjs.module` | Nest module class name +| `nestjs.controller` | Nest Controller class name +| `nestjs.callback` | The function name of the member in the Controller +| `http.method` | HTTP method +| `http.url` | Full request URL +| `http.route` | Route assigned to handler. Ex: `/users/:id` + +\* included in all of the spans. + ## Useful links - For more information on OpenTelemetry, visit: From e8f9b0b7558121dda405a73c764220f89fc7d568 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 18:15:51 +0300 Subject: [PATCH 06/16] docs: mention type values for each of the spans --- .../README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md index a476c2b567..29f8b7acb2 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/README.md @@ -40,11 +40,11 @@ registerInstrumentations({ ## Emitted Spans -| Name | Description | Included attributes -| ---- | ---- | ---- -`Create Nest App` | Traces the bootup for the Nest App. The `NestFactory(Static).create` call. | `nestjs.module` -`.` | Traces the whole request context. | `http.*`, `nestjs.callback` -`` | Traces the work of a specific controller member function. | `nestjs.callback` +| Name | `nestjs.type` | Description | Included attributes +| ---- | ---- | ---- | ---- +`Create Nest App` | `app_creation` | Traces the bootup for the Nest App. The `NestFactory(Static).create` call. | `nestjs.module` +`.` | `request_context` | Traces the whole request context. | `http.*`, `nestjs.callback` +`` | `handler` | Traces the work of a specific controller member function. | `nestjs.callback` #### Attributes @@ -54,8 +54,8 @@ registerInstrumentations({ | `nestjs.version`* | Version of instrumented `@nestjs/core` package | `nestjs.type`* | See [NestType](./src/enums/NestType.ts) | `nestjs.module` | Nest module class name -| `nestjs.controller` | Nest Controller class name -| `nestjs.callback` | The function name of the member in the Controller +| `nestjs.controller` | Nest controller class name +| `nestjs.callback` | The function name of the member in the controller | `http.method` | HTTP method | `http.url` | Full request URL | `http.route` | Route assigned to handler. Ex: `/users/:id` From 7b021489e3593d456db32d7f3bede243d0950d9f Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Wed, 28 Jul 2021 18:49:46 +0300 Subject: [PATCH 07/16] chore: update versions Co-authored-by: Daniel Dyla --- .../package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json index f348f8fa52..65f2bf7507 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -51,9 +51,9 @@ "@nestjs/platform-express": "^8.0.5", "@nestjs/websockets": "^8.0.5", "@opentelemetry/api": "1.0.1", - "@opentelemetry/context-async-hooks": "0.23.0", - "@opentelemetry/node": "0.23.0", - "@opentelemetry/tracing": "0.23.0", + "@opentelemetry/context-async-hooks": "0.24.0", + "@opentelemetry/node": "0.24.0", + "@opentelemetry/tracing": "0.24.0", "@types/mocha": "7.0.2", "@types/node": "14.17.2", "@types/semver": "^7.3.8", @@ -72,7 +72,7 @@ "typescript": "4.3.2" }, "dependencies": { - "@opentelemetry/instrumentation": "^0.23.0", - "@opentelemetry/semantic-conventions": "^0.23.0" + "@opentelemetry/instrumentation": "^0.24.0", + "@opentelemetry/semantic-conventions": "^0.24.0" } } From 3fa91737be97bcee46fca16d2a1f730c9800ef48 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 29 Jul 2021 11:48:39 +0300 Subject: [PATCH 08/16] chore: update packages --- .../package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json index 65f2bf7507..f38adad096 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -29,10 +29,11 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=8.0.0" + "node": ">=8.5.0" }, "files": [ "build/src/**/*.js", + "build/src/**/*.js.map", "build/src/**/*.d.ts", "doc", "LICENSE", @@ -58,18 +59,18 @@ "@types/node": "14.17.2", "@types/semver": "^7.3.8", "@types/vinyl-fs": "^2.4.12", - "codecov": "3.8.2", + "codecov": "3.8.3", "cross-env": "7.0.3", "gts": "3.1.0", "mocha": "7.2.0", "nyc": "15.1.0", "reflect-metadata": "^0.1.13", "rimraf": "3.0.2", - "rxjs": "^7.2.0", + "rxjs": "^7.3.0", "rxjs-compat": "^6.6.7", "semver": "^7.3.5", "ts-mocha": "8.0.0", - "typescript": "4.3.2" + "typescript": "4.3.5" }, "dependencies": { "@opentelemetry/instrumentation": "^0.24.0", From 778cb2086e4173557d5d60eb7e1d0d1951b20b0b Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 29 Jul 2021 11:50:42 +0300 Subject: [PATCH 09/16] style: lint --- .../src/instrumentation.ts | 5 +-- .../test/setup.ts | 36 +++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts index 69c1c7de29..c94c2ec0a3 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/instrumentation.ts @@ -36,10 +36,7 @@ export class Instrumentation extends InstrumentationBase { }; constructor() { - super( - '@opentelemetry/instrumentation-nestjs-core', - VERSION - ); + super('@opentelemetry/instrumentation-nestjs-core', VERSION); } init() { diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts index 9a18740e55..c4ffc0e280 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/setup.ts @@ -139,14 +139,20 @@ export const setup = async (version: string): Promise => { YellInterceptor ); - const [UsersController, UsersModule] = makeModule('Users', () => 'Hello, world!\n', [ - common.Controller('users'), - ]); - const [GuardedController, GuardedModule] = makeModule('Guarded', () => 'Hello, guarded!\n', [ - common.Controller('guarded'), - common.UseGuards(MyGuard), - common.UseGuards(MyGuard), - ]); + const [UsersController, UsersModule] = makeModule( + 'Users', + () => 'Hello, world!\n', + [common.Controller('users')] + ); + const [GuardedController, GuardedModule] = makeModule( + 'Guarded', + () => 'Hello, guarded!\n', + [ + common.Controller('guarded'), + common.UseGuards(MyGuard), + common.UseGuards(MyGuard), + ] + ); const [InterceptedController, InterceptedModule] = makeModule( 'Intercepted', () => 'Hello, Intercepted!\n', @@ -169,7 +175,12 @@ export const setup = async (version: string): Promise => { [ common.Module({ imports: [UsersModule, ErrorModule, GuardedModule, InterceptedModule], - controllers: [UsersController, ErrorController, GuardedController, InterceptedController], + controllers: [ + UsersController, + ErrorController, + GuardedController, + InterceptedController, + ], }), ], AppModule @@ -179,7 +190,12 @@ export const setup = async (version: string): Promise => { [ common.Module({ modules: [UsersModule, ErrorModule, GuardedModule, InterceptedModule], - controllers: [UsersController, ErrorController, GuardedController, InterceptedController], + controllers: [ + UsersController, + ErrorController, + GuardedController, + InterceptedController, + ], }), ], AppModule From e60806223a2681cae4d9066f906343787af17ce0 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 29 Jul 2021 11:54:37 +0300 Subject: [PATCH 10/16] chore: remove utils for now It was left there from an earlier verison which used it. --- .../src/utils.ts | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts deleted file mode 100644 index 24d41ae7fe..0000000000 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/utils.ts +++ /dev/null @@ -1,27 +0,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. - */ - -// util.types.isPromise is supported from 10.0.0 -export const isPromise = (value: any): value is Promise => { - if ( - typeof value.then === 'function' && - typeof value.catch === 'function' && - value.toString() === '[object Promise]' - ) { - return true; - } - return false; -}; From e31c22ffd671d058077f398ca00be95a12434854 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 29 Jul 2021 11:59:19 +0300 Subject: [PATCH 11/16] chore: update node types patch version --- .../node/opentelemetry-instrumentation-nestjs-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json index f38adad096..3e1f3f6384 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -56,7 +56,7 @@ "@opentelemetry/node": "0.24.0", "@opentelemetry/tracing": "0.24.0", "@types/mocha": "7.0.2", - "@types/node": "14.17.2", + "@types/node": "14.17.6", "@types/semver": "^7.3.8", "@types/vinyl-fs": "^2.4.12", "codecov": "3.8.3", From 87f82cb134de3629076ada64d4594b14f37d44b8 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 29 Jul 2021 17:51:43 +0300 Subject: [PATCH 12/16] test: test nestjs.type --- .../test/index.test.ts | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts index 45f94e73e9..76e5b43661 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts @@ -65,13 +65,14 @@ describe('nestjs-core', () => { instrumentation.disable(); }); - before(() => {}); - - after(() => {}); - it('should capture setup', async () => { assertSpans(memoryExporter.getFinishedSpans(), [ - { service: 'test', name: 'Create Nest App', module: 'AppModule' }, + { + type: 'app_creation', + service: 'test', + name: 'Create Nest App', + module: 'AppModule', + }, ]); }); @@ -84,14 +85,21 @@ describe('nestjs-core', () => { assert.strictEqual(await request('/users'), 'Hello, world!\n'); assertSpans(memoryExporter.getFinishedSpans(), [ - { service: 'test', name: 'Create Nest App', module: 'AppModule' }, { + type: 'app_creation', + service: 'test', + name: 'Create Nest App', + module: 'AppModule', + }, + { + type: 'handler', service: 'test', name: callback, callback, parentSpanName: `${instance}.${callback}`, }, { + type: 'request_context', service: 'test', name: `${instance}.${callback}`, method: 'GET', @@ -114,8 +122,14 @@ describe('nestjs-core', () => { ); assertSpans(memoryExporter.getFinishedSpans(), [ - { service: 'test', name: 'Create Nest App', module: 'AppModule' }, { + type: 'app_creation', + service: 'test', + name: 'Create Nest App', + module: 'AppModule', + }, + { + type: 'handler', service: 'test', name: callback, callback, @@ -126,6 +140,7 @@ describe('nestjs-core', () => { parentSpanName: `${instance}.${callback}`, }, { + type: 'request_context', service: 'test', name: `${instance}.${callback}`, method: 'GET', @@ -168,6 +183,7 @@ const assertSpans = (actualSpans: any[], expectedSpans: any[]) => { assert.strictEqual(span.attributes['http.method'], expected.method); assert.strictEqual(span.attributes['http.url'], expected.url); assert.strictEqual(span.attributes['http.route'], expected.path); + assert.strictEqual(span.attributes['nestjs.type'], expected.type); assert.strictEqual(span.attributes['nestjs.callback'], expected.callback); assert.strictEqual( span.attributes['nest.controller.instance'], From 9609ff4497dd6562d57e551ac8aefa9855f50f7a Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Tue, 3 Aug 2021 08:47:17 +0300 Subject: [PATCH 13/16] chore: update version --- .../node/opentelemetry-instrumentation-nestjs-core/package.json | 2 +- .../opentelemetry-instrumentation-nestjs-core/src/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json index 3e1f3f6384..15f6c98736 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-nestjs-core", - "version": "0.23.0", + "version": "0.24.0", "description": "OpenTelemetry NestJS automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts index 113a67d8b1..2902e7d262 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.23.0'; +export const VERSION = '0.24.0'; From 512e7568a4538acb5fab930292728071502781ec Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Tue, 10 Aug 2021 16:25:38 +0300 Subject: [PATCH 14/16] chore: add myself to component owners --- .github/component_owners.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/component_owners.yml b/.github/component_owners.yml index d1e4069c1e..dd09fdc9e6 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -13,3 +13,5 @@ components: - willarmiros detectors/node/opentelemetry-resource-detector-alibaba-cloud: - legendecas + plugins/node/opentelemetry-instrumentation-nestjs-core: + - Rauno56 From 41cbf6310075dbf23f3ea3d4419b38b5a1050619 Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Tue, 10 Aug 2021 16:26:40 +0300 Subject: [PATCH 15/16] fix: remove the default export --- .../opentelemetry-instrumentation-nestjs-core/src/index.ts | 1 - .../test/index.test.ts | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts index eb8cc76b14..d7649869f9 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/src/index.ts @@ -17,5 +17,4 @@ import { Instrumentation } from './instrumentation'; export * from './instrumentation'; -export default Instrumentation; export { Instrumentation as NestInstrumentation }; diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts index 76e5b43661..f13248c016 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts @@ -24,14 +24,14 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import * as assert from 'assert'; -import Instrumentation from '../src'; +import { NestInstrumentation } from '../src'; import { getRequester, setup, App } from './setup'; import * as util from 'util'; const LIB_VERSION = require('@nestjs/core/package.json').version; -const instrumentation = new Instrumentation(); +const instrumentation = new NestInstrumentation(); const memoryExporter = new InMemorySpanExporter(); util.inspect.defaultOptions.depth = 3; @@ -190,7 +190,7 @@ const assertSpans = (actualSpans: any[], expectedSpans: any[]) => { expected.instance ); - assert.strictEqual(span.attributes.component, Instrumentation.COMPONENT); + assert.strictEqual(span.attributes.component, NestInstrumentation.COMPONENT); assert.strictEqual( typeof span.attributes['nestjs.version'], 'string', From 042e59a99497dfa82493d4da02a63be130491bfc Mon Sep 17 00:00:00 2001 From: Rauno Viskus Date: Thu, 12 Aug 2021 17:02:34 +0300 Subject: [PATCH 16/16] style: lint --- .../test/index.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts index f13248c016..d382d1753c 100644 --- a/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts +++ b/plugins/node/opentelemetry-instrumentation-nestjs-core/test/index.test.ts @@ -190,7 +190,10 @@ const assertSpans = (actualSpans: any[], expectedSpans: any[]) => { expected.instance ); - assert.strictEqual(span.attributes.component, NestInstrumentation.COMPONENT); + assert.strictEqual( + span.attributes.component, + NestInstrumentation.COMPONENT + ); assert.strictEqual( typeof span.attributes['nestjs.version'], 'string',