From 7f1cb22df8641693185712d9aa326ecfc9c57c2d Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 13 Aug 2020 14:11:30 -0400 Subject: [PATCH 01/13] feat: add a new plugin base decoupled from the sdk --- .../.eslintignore | 2 + .../.eslintrc.js | 9 + .../.npmignore | 4 + .../LICENSE | 201 ++++++++++++++++++ .../README.md | 11 + .../karma.conf.js | 24 +++ .../package.json | 54 +++++ .../src/index.ts | 0 .../src/instrumentation-base.ts | 89 ++++++++ .../src/require-in-the-middle.d.ts | 17 ++ .../src/version.ts | 18 ++ .../tsconfig.json | 11 + 12 files changed, 440 insertions(+) create mode 100644 packages/opentelemetry-instrumentation-base/.eslintignore create mode 100644 packages/opentelemetry-instrumentation-base/.eslintrc.js create mode 100644 packages/opentelemetry-instrumentation-base/.npmignore create mode 100644 packages/opentelemetry-instrumentation-base/LICENSE create mode 100644 packages/opentelemetry-instrumentation-base/README.md create mode 100644 packages/opentelemetry-instrumentation-base/karma.conf.js create mode 100644 packages/opentelemetry-instrumentation-base/package.json create mode 100644 packages/opentelemetry-instrumentation-base/src/index.ts create mode 100644 packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts create mode 100644 packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts create mode 100644 packages/opentelemetry-instrumentation-base/src/version.ts create mode 100644 packages/opentelemetry-instrumentation-base/tsconfig.json diff --git a/packages/opentelemetry-instrumentation-base/.eslintignore b/packages/opentelemetry-instrumentation-base/.eslintignore new file mode 100644 index 0000000000..9ef96044fa --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/.eslintignore @@ -0,0 +1,2 @@ +build + diff --git a/packages/opentelemetry-instrumentation-base/.eslintrc.js b/packages/opentelemetry-instrumentation-base/.eslintrc.js new file mode 100644 index 0000000000..9dfe62f9b8 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + "env": { + "mocha": true, + "commonjs": true, + "node": true, + "browser": true + }, + ...require('../../eslint.config.js') +} diff --git a/packages/opentelemetry-instrumentation-base/.npmignore b/packages/opentelemetry-instrumentation-base/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/packages/opentelemetry-instrumentation-base/LICENSE b/packages/opentelemetry-instrumentation-base/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/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/packages/opentelemetry-instrumentation-base/README.md b/packages/opentelemetry-instrumentation-base/README.md new file mode 100644 index 0000000000..5ccf04b071 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/README.md @@ -0,0 +1,11 @@ +# `@opentelemetry/instrumentation-base` + +> TODO: description + +## Usage + +``` +const instrumentationBase = require('@opentelemetry/instrumentation-base'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/opentelemetry-instrumentation-base/karma.conf.js b/packages/opentelemetry-instrumentation-base/karma.conf.js new file mode 100644 index 0000000000..3019564a15 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/karma.conf.js @@ -0,0 +1,24 @@ +/*! + * 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 + * + * 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. + */ + +const karmaWebpackConfig = require('../../karma.webpack'); +const karmaBaseConfig = require('../../karma.base'); + +module.exports = (config) => { + config.set(Object.assign({}, karmaBaseConfig, { + webpack: karmaWebpackConfig + })) +}; diff --git a/packages/opentelemetry-instrumentation-base/package.json b/packages/opentelemetry-instrumentation-base/package.json new file mode 100644 index 0000000000..1b1900b72a --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/package.json @@ -0,0 +1,54 @@ +{ + "name": "@opentelemetry/instrumentation-base", + "version": "0.10.2", + "description": "Base class which OpenTelemetry instrumentation modules extend", + "author": "OpenTelemetry Authors", + "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", + "license": "Apache-2.0", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/open-telemetry/opentelemetry-js.git" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.js.map", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "scripts": { + "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/index-webpack.ts'", + "test:browser": "nyc karma start --single-run", + "tdd": "npm run tdd:node", + "tdd:node": "npm run test -- --watch-extensions ts --watch", + "tdd:browser": "karma start", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "clean": "rimraf build/*", + "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "precompile": "tsc --version", + "version:update": "node ../../scripts/version-update.js", + "compile": "npm run version:update && tsc -p .", + "prepare": "npm run compile", + "watch": "tsc -w" + }, + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js/issues" + }, + "dependencies": { + "@opentelemetry/api": "^0.10.2", + "@types/semver": "^7.3.1", + "require-in-the-middle": "5.0.3", + "semver": "^7.3.2", + "shimmer": "1.2.1" + }, + "devDependencies": { + "typescript": "3.4.3" + } +} diff --git a/packages/opentelemetry-instrumentation-base/src/index.ts b/packages/opentelemetry-instrumentation-base/src/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts b/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts new file mode 100644 index 0000000000..42743c1a59 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts @@ -0,0 +1,89 @@ +import { Meter, MeterProvider, metrics, trace, Tracer, TracerProvider } from "@opentelemetry/api"; +import * as path from "path"; +import * as RequireInTheMiddle from "require-in-the-middle"; +import * as semver from "semver"; + +export abstract class Instrumentation { + protected abstract module: ModuleDefinition | ModuleDefinition[]; + protected abstract patch(exports: T, name: string, baseDir?: string): T; + protected abstract unpatch(): void; + + private _hook: RequireInTheMiddle.Hooked = { unhook: () => { } }; + + private _tracer: Tracer; + private _meter: Meter; + + constructor(protected readonly instrumentationName: string, protected readonly instrumentationVersion?: string) { + this._tracer = trace.getTracer(instrumentationName, instrumentationVersion); + this._meter = metrics.getMeter(instrumentationName, instrumentationVersion); + } + + public enable() { + this._hook = RequireInTheMiddle(this._getModuleNames(), this._onRequire); + } + + public disable() { + this._hook.unhook(); + this.unpatch(); + } + + public setTracerProvider(tracerProvider: TracerProvider) { + this._tracer = tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion); + } + + public setMeterProvider(meterProvider: MeterProvider) { + this._meter = meterProvider.getMeter(this.instrumentationName, this.instrumentationVersion); + } + + protected get tracer(): Tracer { + return this._tracer; + }; + + protected get meter(): Meter { + return this._meter; + }; + + private _onRequire(exports: T, name: string, baseDir?: string): T { + if (!baseDir) { + return this.patch(exports, name); + } + + const version = require(path.join(baseDir, 'package.json')).version; + if (typeof version === "string" && this._isSupported(name, version)) { + return this.patch(exports, name, baseDir); + } + + return exports; + } + + private _isSupported(name: string, version: string): boolean { + for (const module of this._supportedModuleDefinitions) { + if (module.name === name) { + if (!module.supportedVersions) { + return true; + } + + for (const supportedVersions of module.supportedVersions) { + if (semver.satisfies(version, supportedVersions)) { + return true; + } + } + } + } + + return false + } + + private _getModuleNames() { + return Array.from(new Set(this._supportedModuleDefinitions.map(m => m.name))) + } + + private get _supportedModuleDefinitions() { + return Array.isArray(this.module) ? this.module : [this.module]; + } +} + +export interface ModuleDefinition { + name: string; + supportedVersions?: string[]; +} \ No newline at end of file diff --git a/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts b/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts new file mode 100644 index 0000000000..1b28d033bb --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts @@ -0,0 +1,17 @@ +declare module 'require-in-the-middle' { + namespace hook { + type Options = { + internals?: boolean; + }; + type OnRequireFn = (exports: T, name: string, basedir?: string) => T; + type Hooked = { unhook(): void }; + } + function hook( + modules: string[] | null, + options: hook.Options | null, + onRequire: hook.OnRequireFn + ): hook.Hooked; + function hook(modules: string[] | null, onRequire: hook.OnRequireFn): hook.Hooked; + function hook(onRequire: hook.OnRequireFn): hook.Hooked; + export = hook; +} \ No newline at end of file diff --git a/packages/opentelemetry-instrumentation-base/src/version.ts b/packages/opentelemetry-instrumentation-base/src/version.ts new file mode 100644 index 0000000000..ea45ee2fc4 --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/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.10.2'; diff --git a/packages/opentelemetry-instrumentation-base/tsconfig.json b/packages/opentelemetry-instrumentation-base/tsconfig.json new file mode 100644 index 0000000000..a2042cd68b --- /dev/null +++ b/packages/opentelemetry-instrumentation-base/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} From 0f5f50f22750d144870734f4ad393129ec12f8e0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 21:45:45 +0200 Subject: [PATCH 02/13] chore: web and node version that supports patching more files --- packages/opentelemetry-api/src/index.ts | 1 + .../trace/instrumentation/Instrumentation.ts | 83 +++++++++ .../README.md | 11 -- .../package.json | 54 ------ .../src/index.ts | 0 .../src/instrumentation-base.ts | 89 ---------- .../src/require-in-the-middle.d.ts | 17 -- .../.eslintignore | 0 .../.eslintrc.js | 0 .../.npmignore | 0 .../LICENSE | 0 .../opentelemetry-instrumentation/README.md | 10 ++ .../karma.conf.js | 4 +- .../package.json | 95 +++++++++++ .../src/index.ts | 17 ++ .../src/instrumentation.ts | 99 +++++++++++ .../src/platform/browser/index.ts | 17 ++ .../src/platform/browser/instrumentation.ts | 43 +++++ .../src/platform/index.ts | 17 ++ .../src/platform/node/index.ts | 20 +++ .../src/platform/node/instrumentation.ts | 158 ++++++++++++++++++ .../instrumentationNodeModuleDefinition.ts | 34 ++++ .../node/instrumentationNodeModuleFile.ts | 26 +++ .../platform/node/require-in-the-middle.d.ts | 36 ++++ .../src/platform/node/types.ts | 43 +++++ .../src/version.ts | 2 +- .../test/browser/index-webpack.ts | 23 +++ .../test/common/Instrumentation.test.ts | 45 +++++ .../tsconfig.json | 0 packages/opentelemetry-node/package.json | 3 +- 30 files changed, 773 insertions(+), 174 deletions(-) create mode 100644 packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts delete mode 100644 packages/opentelemetry-instrumentation-base/README.md delete mode 100644 packages/opentelemetry-instrumentation-base/package.json delete mode 100644 packages/opentelemetry-instrumentation-base/src/index.ts delete mode 100644 packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts delete mode 100644 packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/.eslintignore (100%) rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/.eslintrc.js (100%) rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/.npmignore (100%) rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/LICENSE (100%) create mode 100644 packages/opentelemetry-instrumentation/README.md rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/karma.conf.js (84%) create mode 100644 packages/opentelemetry-instrumentation/package.json create mode 100644 packages/opentelemetry-instrumentation/src/index.ts create mode 100644 packages/opentelemetry-instrumentation/src/instrumentation.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/browser/index.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/index.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/index.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleDefinition.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/require-in-the-middle.d.ts create mode 100644 packages/opentelemetry-instrumentation/src/platform/node/types.ts rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/src/version.ts (95%) create mode 100644 packages/opentelemetry-instrumentation/test/browser/index-webpack.ts create mode 100644 packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts rename packages/{opentelemetry-instrumentation-base => opentelemetry-instrumentation}/tsconfig.json (100%) diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index 0a7e8bbd85..687dc40bc4 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -35,6 +35,7 @@ export * from './metrics/ObserverResult'; export * from './trace/attributes'; export * from './trace/Event'; export * from './trace/instrumentation/Plugin'; +export * from './trace/instrumentation/Instrumentation'; export * from './trace/link_context'; export * from './trace/link'; export * from './trace/NoopSpan'; diff --git a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts new file mode 100644 index 0000000000..3b416420a6 --- /dev/null +++ b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts @@ -0,0 +1,83 @@ +/* + * 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 { MeterProvider } from '../..'; +import { Logger } from '../../common/Logger'; +import { TracerProvider } from '../tracer_provider'; + + +/** Interface Instrumentation to apply patch. */ +export interface Instrumentation { + /** Instrumentation Name */ + instrumentationName: string; + + /** Instrumentation Version */ + instrumentationVersion: string; + + /** + * Instrumentation Description - please describe all useful information + * as Instrumentation might patch different version of different modules, + * or support different browsers etc. + */ + instrumentationDescription?: string; + + /** Method to disable the instrumentation */ + disable(): void; + + /** Method to enable the instrumentation */ + enable(): void; + + /** Method to patch the instrumentation */ + // patch(exports: T, name: string, baseDir?: string): T; + + /** Method to set tracer provider */ + setTracerProvider(tracerProvider: TracerProvider): void; + + /** Method to set meter provider */ + setMeterProvider(meterProvider: MeterProvider): void + + /** + * Contains all supported versions. + * All versions must be compatible with [semver](https://semver.org/spec/v2.0.0.html) format. + * If the version is not supported, we won't apply instrumentation patch (see `enable` method). + * If omitted, all versions of the module will be patched. + */ + supportedVersions?: string[]; + + /** Method to unpatch the instrumentation */ + // unpatch(): void; +} + +export interface InstrumentationConfig { + /** + * Whether to enable the plugin. + * @default true + */ + enabled?: boolean; + + logger?: Logger; + + /** + * Request methods that match any string in ignoreMethods will not be traced. + */ + ignoreMethods?: string[]; + + /** + * Path of the trace plugin to load. + * @default '@opentelemetry/plugin-http' in case of http. + */ + path?: string; +} diff --git a/packages/opentelemetry-instrumentation-base/README.md b/packages/opentelemetry-instrumentation-base/README.md deleted file mode 100644 index 5ccf04b071..0000000000 --- a/packages/opentelemetry-instrumentation-base/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# `@opentelemetry/instrumentation-base` - -> TODO: description - -## Usage - -``` -const instrumentationBase = require('@opentelemetry/instrumentation-base'); - -// TODO: DEMONSTRATE API -``` diff --git a/packages/opentelemetry-instrumentation-base/package.json b/packages/opentelemetry-instrumentation-base/package.json deleted file mode 100644 index 1b1900b72a..0000000000 --- a/packages/opentelemetry-instrumentation-base/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@opentelemetry/instrumentation-base", - "version": "0.10.2", - "description": "Base class which OpenTelemetry instrumentation modules extend", - "author": "OpenTelemetry Authors", - "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", - "license": "Apache-2.0", - "main": "build/src/index.js", - "types": "build/src/index.d.ts", - "publishConfig": { - "access": "public" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/open-telemetry/opentelemetry-js.git" - }, - "files": [ - "build/src/**/*.js", - "build/src/**/*.js.map", - "build/src/**/*.d.ts", - "doc", - "LICENSE", - "README.md" - ], - "scripts": { - "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/index-webpack.ts'", - "test:browser": "nyc karma start --single-run", - "tdd": "npm run tdd:node", - "tdd:node": "npm run test -- --watch-extensions ts --watch", - "tdd:browser": "karma start", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", - "clean": "rimraf build/*", - "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", - "precompile": "tsc --version", - "version:update": "node ../../scripts/version-update.js", - "compile": "npm run version:update && tsc -p .", - "prepare": "npm run compile", - "watch": "tsc -w" - }, - "bugs": { - "url": "https://github.com/open-telemetry/opentelemetry-js/issues" - }, - "dependencies": { - "@opentelemetry/api": "^0.10.2", - "@types/semver": "^7.3.1", - "require-in-the-middle": "5.0.3", - "semver": "^7.3.2", - "shimmer": "1.2.1" - }, - "devDependencies": { - "typescript": "3.4.3" - } -} diff --git a/packages/opentelemetry-instrumentation-base/src/index.ts b/packages/opentelemetry-instrumentation-base/src/index.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts b/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts deleted file mode 100644 index 42743c1a59..0000000000 --- a/packages/opentelemetry-instrumentation-base/src/instrumentation-base.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Meter, MeterProvider, metrics, trace, Tracer, TracerProvider } from "@opentelemetry/api"; -import * as path from "path"; -import * as RequireInTheMiddle from "require-in-the-middle"; -import * as semver from "semver"; - -export abstract class Instrumentation { - protected abstract module: ModuleDefinition | ModuleDefinition[]; - protected abstract patch(exports: T, name: string, baseDir?: string): T; - protected abstract unpatch(): void; - - private _hook: RequireInTheMiddle.Hooked = { unhook: () => { } }; - - private _tracer: Tracer; - private _meter: Meter; - - constructor(protected readonly instrumentationName: string, protected readonly instrumentationVersion?: string) { - this._tracer = trace.getTracer(instrumentationName, instrumentationVersion); - this._meter = metrics.getMeter(instrumentationName, instrumentationVersion); - } - - public enable() { - this._hook = RequireInTheMiddle(this._getModuleNames(), this._onRequire); - } - - public disable() { - this._hook.unhook(); - this.unpatch(); - } - - public setTracerProvider(tracerProvider: TracerProvider) { - this._tracer = tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion); - } - - public setMeterProvider(meterProvider: MeterProvider) { - this._meter = meterProvider.getMeter(this.instrumentationName, this.instrumentationVersion); - } - - protected get tracer(): Tracer { - return this._tracer; - }; - - protected get meter(): Meter { - return this._meter; - }; - - private _onRequire(exports: T, name: string, baseDir?: string): T { - if (!baseDir) { - return this.patch(exports, name); - } - - const version = require(path.join(baseDir, 'package.json')).version; - if (typeof version === "string" && this._isSupported(name, version)) { - return this.patch(exports, name, baseDir); - } - - return exports; - } - - private _isSupported(name: string, version: string): boolean { - for (const module of this._supportedModuleDefinitions) { - if (module.name === name) { - if (!module.supportedVersions) { - return true; - } - - for (const supportedVersions of module.supportedVersions) { - if (semver.satisfies(version, supportedVersions)) { - return true; - } - } - } - } - - return false - } - - private _getModuleNames() { - return Array.from(new Set(this._supportedModuleDefinitions.map(m => m.name))) - } - - private get _supportedModuleDefinitions() { - return Array.isArray(this.module) ? this.module : [this.module]; - } -} - -export interface ModuleDefinition { - name: string; - supportedVersions?: string[]; -} \ No newline at end of file diff --git a/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts b/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts deleted file mode 100644 index 1b28d033bb..0000000000 --- a/packages/opentelemetry-instrumentation-base/src/require-in-the-middle.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -declare module 'require-in-the-middle' { - namespace hook { - type Options = { - internals?: boolean; - }; - type OnRequireFn = (exports: T, name: string, basedir?: string) => T; - type Hooked = { unhook(): void }; - } - function hook( - modules: string[] | null, - options: hook.Options | null, - onRequire: hook.OnRequireFn - ): hook.Hooked; - function hook(modules: string[] | null, onRequire: hook.OnRequireFn): hook.Hooked; - function hook(onRequire: hook.OnRequireFn): hook.Hooked; - export = hook; -} \ No newline at end of file diff --git a/packages/opentelemetry-instrumentation-base/.eslintignore b/packages/opentelemetry-instrumentation/.eslintignore similarity index 100% rename from packages/opentelemetry-instrumentation-base/.eslintignore rename to packages/opentelemetry-instrumentation/.eslintignore diff --git a/packages/opentelemetry-instrumentation-base/.eslintrc.js b/packages/opentelemetry-instrumentation/.eslintrc.js similarity index 100% rename from packages/opentelemetry-instrumentation-base/.eslintrc.js rename to packages/opentelemetry-instrumentation/.eslintrc.js diff --git a/packages/opentelemetry-instrumentation-base/.npmignore b/packages/opentelemetry-instrumentation/.npmignore similarity index 100% rename from packages/opentelemetry-instrumentation-base/.npmignore rename to packages/opentelemetry-instrumentation/.npmignore diff --git a/packages/opentelemetry-instrumentation-base/LICENSE b/packages/opentelemetry-instrumentation/LICENSE similarity index 100% rename from packages/opentelemetry-instrumentation-base/LICENSE rename to packages/opentelemetry-instrumentation/LICENSE diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md new file mode 100644 index 0000000000..29aae07536 --- /dev/null +++ b/packages/opentelemetry-instrumentation/README.md @@ -0,0 +1,10 @@ +# `@opentelemetry/instrumentation-base` + +> TODO: description + +## Usage in Node + +```javascript + const instrumentationBase = require('@opentelemetry/instrumentation'); +``` +## Usage in Web diff --git a/packages/opentelemetry-instrumentation-base/karma.conf.js b/packages/opentelemetry-instrumentation/karma.conf.js similarity index 84% rename from packages/opentelemetry-instrumentation-base/karma.conf.js rename to packages/opentelemetry-instrumentation/karma.conf.js index 3019564a15..455b1437c8 100644 --- a/packages/opentelemetry-instrumentation-base/karma.conf.js +++ b/packages/opentelemetry-instrumentation/karma.conf.js @@ -19,6 +19,8 @@ const karmaBaseConfig = require('../../karma.base'); module.exports = (config) => { config.set(Object.assign({}, karmaBaseConfig, { - webpack: karmaWebpackConfig + webpack: karmaWebpackConfig, + files: ['test/browser/index-webpack.ts'], + preprocessors: { 'test/browser/index-webpack.ts': ['webpack'] } })) }; diff --git a/packages/opentelemetry-instrumentation/package.json b/packages/opentelemetry-instrumentation/package.json new file mode 100644 index 0000000000..acb0b668c5 --- /dev/null +++ b/packages/opentelemetry-instrumentation/package.json @@ -0,0 +1,95 @@ +{ + "name": "@opentelemetry/instrumentation", + "version": "0.11.0", + "description": "Base class for node which OpenTelemetry instrumentation modules extend", + "author": "OpenTelemetry Authors", + "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", + "license": "Apache-2.0", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/open-telemetry/opentelemetry-js.git" + }, + "browser": { + "./src/platform/index.ts": "./src/platform/browser/index.ts", + "./build/src/platform/index.js": "./build/src/platform/browser/index.js" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.js.map", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "scripts": { + "clean": "rimraf build/*", + "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "compile": "npm run version:update && tsc -p .", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "precompile": "tsc --version", + "prepare": "npm run compile", + "tdd": "npm run tdd:node", + "tdd:node": "npm run test -- --watch-extensions ts --watch", + "tdd:browser": "karma start", + "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'", + "test:browser": "nyc karma start --single-run", + "version:update": "node ../../scripts/version-update.js", + "watch": "tsc -w" + }, + "keywords": [ + "opentelemetry", + "nodejs", + "browser", + "tracing", + "profiling", + "metrics", + "stats" + ], + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js/issues" + }, + "dependencies": { + "@opentelemetry/api": "^0.11.0", + "require-in-the-middle": "^5.0.3", + "semver": "^7.3.2", + "shimmer": "^1.2.1" + }, + "devDependencies": { + "@babel/core": "7.11.1", + "@types/mocha": "8.0.2", + "@types/node": "14.0.27", + "@types/semver": "^7.3.4", + "@types/shimmer": "^1.0.1", + "@types/sinon": "9.0.4", + "@types/webpack-env": "1.15.2", + "babel-loader": "8.1.0", + "codecov": "3.7.2", + "cpx": "1.5.0", + "gts": "2.0.2", + "istanbul-instrumenter-loader": "3.0.1", + "karma": "5.1.1", + "karma-chrome-launcher": "3.1.0", + "karma-coverage-istanbul-reporter": "3.0.3", + "karma-mocha": "2.0.1", + "karma-spec-reporter": "0.0.32", + "karma-webpack": "4.0.2", + "mocha": "7.2.0", + "nyc": "15.1.0", + "rimraf": "3.0.2", + "sinon": "9.0.3", + "ts-loader": "8.0.2", + "ts-mocha": "7.0.0", + "ts-node": "8.10.2", + "typescript": "3.9.7", + "webpack": "4.44.1", + "webpack-cli": "3.3.12", + "webpack-merge": "5.1.1" + } +} diff --git a/packages/opentelemetry-instrumentation/src/index.ts b/packages/opentelemetry-instrumentation/src/index.ts new file mode 100644 index 0000000000..f41f77b271 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './platform/index'; diff --git a/packages/opentelemetry-instrumentation/src/instrumentation.ts b/packages/opentelemetry-instrumentation/src/instrumentation.ts new file mode 100644 index 0000000000..da1c75b271 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/instrumentation.ts @@ -0,0 +1,99 @@ +/* + * 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 * as shimmer from 'shimmer'; + +/** + * Base abstract internal class for instrumenting node and web plugins + */ +export abstract class BaseInstrumentation + implements api.Instrumentation { + protected _config: api.InstrumentationConfig; + + private _tracer: api.Tracer; + private _meter: api.Meter; + protected _logger: api.Logger; + + constructor( + public readonly instrumentationName: string, + public readonly instrumentationVersion: string, + config: api.InstrumentationConfig = {} + ) { + this._config = { + enabled: true, + ...config, + }; + this._logger = this._config.logger || new api.NoopLogger(); + + this._tracer = api.trace.getTracer( + instrumentationName, + instrumentationVersion + ); + + this._meter = api.metrics.getMeter( + instrumentationName, + instrumentationVersion + ); + } + + /* Api to wrap instrumented method */ + protected _wrap = shimmer.wrap; + /* Api to unwrap instrumented methods */ + protected _unwrap = shimmer.unwrap; + /* Api to mass wrap instrumented method */ + protected _massWrap = shimmer.massWrap; + /* Api to mass unwrap instrumented methods */ + protected _massUnwrap = shimmer.massUnwrap; + + /* Returns meter */ + protected get meter(): api.Meter { + return this._meter; + } + + /** + * Sets MeterProvider to this plugin + * @param meterProvider + */ + public setMeterProvider(meterProvider: api.MeterProvider) { + this._meter = meterProvider.getMeter( + this.instrumentationName, + this.instrumentationVersion + ); + } + + /** + * Sets TraceProvider to this plugin + * @param tracerProvider + */ + public setTracerProvider(tracerProvider: api.TracerProvider) { + this._tracer = tracerProvider.getTracer( + this.instrumentationName, + this.instrumentationVersion + ); + } + + /* Returns tracer */ + protected get tracer(): api.Tracer { + return this._tracer; + } + + /* Disable plugin */ + public abstract enable(): void; + + /* Enable plugin */ + public abstract disable(): void; +} diff --git a/packages/opentelemetry-instrumentation/src/platform/browser/index.ts b/packages/opentelemetry-instrumentation/src/platform/browser/index.ts new file mode 100644 index 0000000000..24c76056a1 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/browser/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './instrumentation'; diff --git a/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts new file mode 100644 index 0000000000..99e5f47ba9 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts @@ -0,0 +1,43 @@ +/* + * 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 { BaseInstrumentation } from '../../instrumentation'; + +/** + * Base abstract class for instrumenting web plugins + */ +export abstract class Instrumentation + extends BaseInstrumentation + implements api.Instrumentation { + constructor( + readonly instrumentationName: string, + readonly instrumentationVersion: string, + config: api.InstrumentationConfig = {} + ) { + super(instrumentationName, instrumentationVersion, config); + + this._init(); + + if (this._config.enabled) { + this.enable(); + } + } + + /** Init method that will be called during initialisation before + * instrumentation is enabled */ + protected _init() {} +} diff --git a/packages/opentelemetry-instrumentation/src/platform/index.ts b/packages/opentelemetry-instrumentation/src/platform/index.ts new file mode 100644 index 0000000000..cdaf8858ce --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/index.ts @@ -0,0 +1,17 @@ +/* + * 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 * from './node'; diff --git a/packages/opentelemetry-instrumentation/src/platform/node/index.ts b/packages/opentelemetry-instrumentation/src/platform/node/index.ts new file mode 100644 index 0000000000..42310c807a --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/index.ts @@ -0,0 +1,20 @@ +/* + * 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 * from './instrumentation'; +export * from './instrumentationNodeModuleDefinition'; +export * from './instrumentationNodeModuleFile'; +export * from './types'; diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts new file mode 100644 index 0000000000..4798d45da1 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -0,0 +1,158 @@ +/* + * 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 * as path from 'path'; +import * as RequireInTheMiddle from 'require-in-the-middle'; +import * as semver from 'semver'; +import { BaseInstrumentation } from '../../instrumentation'; +import { + InstrumentationModuleDefinition, + InstrumentationModuleFile, +} from './types'; + +/** + * Base abstract class for instrumenting node plugins + */ +export abstract class Instrumentation + extends BaseInstrumentation + implements api.Instrumentation { + private _modules: InstrumentationModuleDefinition[]; + private _hooks: RequireInTheMiddle.Hooked[] = []; + + constructor( + instrumentationName: string, + instrumentationVersion: string, + config: api.InstrumentationConfig = {} + ) { + super(instrumentationName, instrumentationVersion, config); + + let modules = this._init(); + + if (modules && !Array.isArray(modules)) { + modules = [modules]; + } + + this._modules = (modules as InstrumentationModuleDefinition[]) || []; + + if (this._modules.length === 0) { + this._logger.warn( + 'No modules instrumentation has been defined,' + + ' nothing will be patched' + ); + } + + if (this._config.enabled) { + this.enable(); + } + } + + private _isSupported(name: string, version: string): boolean { + for (const module of this._modules) { + if (module.name === name) { + if (!module.supportedVersions) { + return true; + } + + for (const supportedVersions of module.supportedVersions) { + if (semver.satisfies(version, supportedVersions)) { + return true; + } + } + } + } + + return false; + } + + private _onRequire( + module: InstrumentationModuleDefinition, + exports: T, + name: string, + baseDir?: string + ): T { + if (!baseDir) { + if (typeof module.patch === 'function') { + return module.patch(exports); + } + return exports; + } + + if (module.name === name) { + // main module + const version = require(path.join(baseDir, 'package.json')).version; + if (typeof version === 'string' && this._isSupported(name, version)) { + if (typeof module.patch === 'function') { + return module.patch(exports); + } + return exports; + } + } else { + // internal file + const files = module.files || []; + const file = files.find( + (file: InstrumentationModuleFile) => file.name === name + ); + if (file) { + return file.patch(exports); + } + } + return exports; + } + + public enable() { + for (const module of this._modules) { + this._hooks.push( + RequireInTheMiddle( + [module.name], + { internals: true }, + (exports, name, baseDir) => { + return this._onRequire( + (module as unknown) as InstrumentationModuleDefinition< + typeof exports + >, + exports, + name, + baseDir + ); + } + ) + ); + } + } + + public disable() { + this._hooks.forEach(hook => { + hook.unhook(); + }); + for (const module of this._modules) { + if (typeof module.unpatch === 'function') { + module.unpatch(); + } + for (const file of module.files) { + file.unpatch(); + } + } + } + + /** + * Init method in which plugin should define _modules and patches for + * methods + */ + protected abstract _init(): + | InstrumentationModuleDefinition + | InstrumentationModuleDefinition[]; +} diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleDefinition.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleDefinition.ts new file mode 100644 index 0000000000..9dc7d01dbc --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleDefinition.ts @@ -0,0 +1,34 @@ +/* + * 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 { + InstrumentationModuleDefinition, + InstrumentationModuleFile, +} from './types'; + +export class InstrumentationNodeModuleDefinition + implements InstrumentationModuleDefinition { + files: InstrumentationModuleFile[]; + constructor( + public name: string, + public supportedVersions: string[], + public patch?: (exports: T) => T, + public unpatch?: () => void, + files?: InstrumentationModuleFile[] + ) { + this.files = files || []; + } +} diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts new file mode 100644 index 0000000000..45ae81514f --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.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. + */ + +import { InstrumentationModuleFile } from './types'; + +export class InstrumentationNodeModuleFile + implements InstrumentationModuleFile { + constructor( + public name: string, + public patch: (exports: T) => T, + public unpatch: () => void + ) {} +} diff --git a/packages/opentelemetry-instrumentation/src/platform/node/require-in-the-middle.d.ts b/packages/opentelemetry-instrumentation/src/platform/node/require-in-the-middle.d.ts new file mode 100644 index 0000000000..93a766b5fb --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/require-in-the-middle.d.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +declare module 'require-in-the-middle' { + namespace hook { + type Options = { + internals?: boolean; + }; + type OnRequireFn = (exports: T, name: string, basedir?: string) => T; + type Hooked = { unhook(): void }; + } + function hook( + modules: string[] | null, + options: hook.Options | null, + onRequire: hook.OnRequireFn + ): hook.Hooked; + function hook( + modules: string[] | null, + onRequire: hook.OnRequireFn + ): hook.Hooked; + function hook(onRequire: hook.OnRequireFn): hook.Hooked; + export = hook; +} diff --git a/packages/opentelemetry-instrumentation/src/platform/node/types.ts b/packages/opentelemetry-instrumentation/src/platform/node/types.ts new file mode 100644 index 0000000000..a4d7c4cbb0 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/platform/node/types.ts @@ -0,0 +1,43 @@ +/* + * 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 interface InstrumentationModuleFile { + /** Name of file to be patched with relative path */ + name: string; + + /** Method to patch the instrumentation */ + patch(exports: T): T; + + /** Method to unpatch the instrumentation */ + unpatch(): void; +} + +export interface InstrumentationModuleDefinition { + /** Module name or path */ + name: string; + + /** Supported version of module */ + supportedVersions: string[]; + + /** Module internal files to be patched */ + files: InstrumentationModuleFile[]; + + /** Method to patch the instrumentation */ + patch?: (exports: T) => T; + + /** Method to unpatch the instrumentation */ + unpatch?: () => void; +} diff --git a/packages/opentelemetry-instrumentation-base/src/version.ts b/packages/opentelemetry-instrumentation/src/version.ts similarity index 95% rename from packages/opentelemetry-instrumentation-base/src/version.ts rename to packages/opentelemetry-instrumentation/src/version.ts index ea45ee2fc4..714520138d 100644 --- a/packages/opentelemetry-instrumentation-base/src/version.ts +++ b/packages/opentelemetry-instrumentation/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.10.2'; +export const VERSION = '0.11.0'; diff --git a/packages/opentelemetry-instrumentation/test/browser/index-webpack.ts b/packages/opentelemetry-instrumentation/test/browser/index-webpack.ts new file mode 100644 index 0000000000..99100a0f6e --- /dev/null +++ b/packages/opentelemetry-instrumentation/test/browser/index-webpack.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ +const testsContext = require.context('../browser', true, /test$/); +testsContext.keys().forEach(testsContext); + +const testsContextCommon = require.context('../common', true, /test$/); +testsContextCommon.keys().forEach(testsContextCommon); + +const srcContext = require.context('.', true, /src$/); +srcContext.keys().forEach(srcContext); diff --git a/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts new file mode 100644 index 0000000000..f900672c71 --- /dev/null +++ b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts @@ -0,0 +1,45 @@ +/* + * 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 assert from 'assert'; +import { BaseInstrumentation } from '../../src/instrumentation'; + +class TestInstrumentation extends BaseInstrumentation { + constructor() { + super('test', '1.0.0'); + } + enable() {} + disable() {} +} + +describe('BaseInstrumentation', () => { + let instrumentation: BaseInstrumentation; + beforeEach(() => { + instrumentation = new TestInstrumentation(); + }); + + it('should create an instance', () => { + assert.ok(instrumentation instanceof BaseInstrumentation); + }); + + it('should have a name', () => { + assert.deepStrictEqual(instrumentation.instrumentationName, 'test'); + }); + + it('should have a version', () => { + assert.deepStrictEqual(instrumentation.instrumentationVersion, '1.0.0'); + }); +}); diff --git a/packages/opentelemetry-instrumentation-base/tsconfig.json b/packages/opentelemetry-instrumentation/tsconfig.json similarity index 100% rename from packages/opentelemetry-instrumentation-base/tsconfig.json rename to packages/opentelemetry-instrumentation/tsconfig.json diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 4c8dfda4fa..3d6767aa3c 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -15,7 +15,8 @@ "precompile": "tsc --version", "version:update": "node ../../scripts/version-update.js", "compile": "npm run version:update && tsc -p .", - "prepare": "npm run compile" + "prepare": "npm run compile", + "watch": "tsc -w" }, "keywords": [ "opentelemetry", From 3ec58d9017a1b7d49308ec90a07bfe10ab0f099b Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 22:18:42 +0200 Subject: [PATCH 03/13] chore: updating readme --- .../trace/instrumentation/Instrumentation.ts | 5 - .../opentelemetry-instrumentation/README.md | 150 +++++++++++++++++- .../src/platform/browser/instrumentation.ts | 6 - 3 files changed, 146 insertions(+), 15 deletions(-) diff --git a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts index 3b416420a6..ad83b0434c 100644 --- a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts +++ b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts @@ -70,11 +70,6 @@ export interface InstrumentationConfig { logger?: Logger; - /** - * Request methods that match any string in ignoreMethods will not be traced. - */ - ignoreMethods?: string[]; - /** * Path of the trace plugin to load. * @default '@opentelemetry/plugin-http' in case of http. diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 29aae07536..c060c32b8e 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -1,10 +1,152 @@ -# `@opentelemetry/instrumentation-base` +# OpenTelemetry Instrumentation for web and node -> TODO: description +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + + +## Installation + +```bash +npm install --save @opentelemetry/instrumentation +``` ## Usage in Node -```javascript - const instrumentationBase = require('@opentelemetry/instrumentation'); +```typescript +import { + Instrumentation, + InstrumentationNodeModuleDefinition, + InstrumentationNodeModuleFile, +} from '@opentelemetry/instrumentation'; + +import * as plugin_name_to_be_pached from 'plugin_name_to_be_pached'; + +export class MyPlugin extends Instrumentation { + constructor(config: api.InstrumentationConfig = {}) { + super('MyPlugin', VERSION, config); + } + + // init method is default method that needs to be defined where + // definitions for patching should be defined. It will be then called + // before enabling the plugin and loading + protected _init() { + const module = new InstrumentationNodeModuleDefinition( + 'plugin_name_to_be_pached', + ['1.*'], + (exports) => { + this._wrap( + exports, + 'mainMethodName', + this._patchMainMethodName() + ); + }, + () => { + this._unwrap(exports, 'mainMethodName'); + } + ); + // in case you need to patch additional files - this is optional + module.files.push(this._addPatchingMethod()); + + return module; + } + + private _addPatchingMethod(): InstrumentationNodeModuleFile { + const file = new InstrumentationNodeModuleFile( + 'plugin_name_to_be_pached/src/some_file.js', + (exports: typeof plugin_name_to_be_pached) => { + this._wrap( + exports, + 'methodName', + this._patchMethodName() + ); + return exports; + }, + () => { + this._unwrap(exports, 'methodName'); + } + ); + return file; + } + + private _patchMethodName(): (original) => any { + const plugin = this; + return function methodName(original) { + return function patchMethodName(this: any): PromiseOrValue { + console.log('methodName', arguments); + return original.apply(this, arguments); + }; + }; + } + + private _patchMainMethodName(): (original) => any { + const plugin = this; + return function mainMethodName(original) { + return function patchMainMethodName(this: any): PromiseOrValue { + console.log('mainMethodName', arguments); + return original.apply(this, arguments); + }; + }; + } +} + +// Later + +const myPLugin = new MyPlugin(); +myPLugin.setTracerProvider(provider); +myPLugin.setMeterProvider(meterProvider); +myPLugin.enable(); ``` + ## Usage in Web + +```typescript +import { Instrumentation } from '@opentelemetry/instrumentation'; + +export class MyPlugin extends Instrumentation { + constructor(config: api.InstrumentationConfig = {}) { + super('MyPlugin', VERSION, config); + } + + private _patchOpen() { + return (original: OpenFunction): OpenFunction => { + const plugin = this; + return function patchOpen(this: XMLHttpRequest, ...args): void { + console.log('open', arguments); + return original.apply(this, args); + }; + }; + } + + public enable() { + this._wrap(XMLHttpRequest.prototype, 'open', this._patchOpen()); + } + public disable() { + this._unwrap(XMLHttpRequest.prototype, 'open'); + } +} + +// Later + +const myPLugin = new MyPlugin(); +myPLugin.setTracerProvider(provider); +myPLugin.setMeterProvider(meterProvider); +myPLugin.enable(); +``` + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-instrumentation +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-instrumentation +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-instrumentation&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation.svg diff --git a/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts index 99e5f47ba9..a8d90b3c33 100644 --- a/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts @@ -30,14 +30,8 @@ export abstract class Instrumentation ) { super(instrumentationName, instrumentationVersion, config); - this._init(); - if (this._config.enabled) { this.enable(); } } - - /** Init method that will be called during initialisation before - * instrumentation is enabled */ - protected _init() {} } From e4ba93ca54f6926b44dfc7a262dcf5ac4ed00093 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 22:29:53 +0200 Subject: [PATCH 04/13] chore: lint --- packages/opentelemetry-instrumentation/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index c060c32b8e..b87b76e2fe 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -6,7 +6,6 @@ [![devDependencies][devDependencies-image]][devDependencies-url] [![Apache License][license-image]][license-image] - ## Installation ```bash From 8ea7162671076c84d0e48f9d2a46e97b160caf2f Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 22:30:08 +0200 Subject: [PATCH 05/13] chore: missing noop logger --- packages/opentelemetry-api/src/index.ts | 1 + .../opentelemetry-api/src/trace/NoopLogger.ts | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 packages/opentelemetry-api/src/trace/NoopLogger.ts diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index 687dc40bc4..8ef623d924 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -38,6 +38,7 @@ export * from './trace/instrumentation/Plugin'; export * from './trace/instrumentation/Instrumentation'; export * from './trace/link_context'; export * from './trace/link'; +export * from './trace/NoopLogger'; export * from './trace/NoopSpan'; export * from './trace/NoopTracer'; export * from './trace/NoopTracerProvider'; diff --git a/packages/opentelemetry-api/src/trace/NoopLogger.ts b/packages/opentelemetry-api/src/trace/NoopLogger.ts new file mode 100644 index 0000000000..dae032e0ff --- /dev/null +++ b/packages/opentelemetry-api/src/trace/NoopLogger.ts @@ -0,0 +1,32 @@ +/* + * 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 { Logger } from '../common/Logger'; + +/** No-op implementation of Logger */ +export class NoopLogger implements Logger { + // By default does nothing + debug(message: string, ...args: unknown[]) {} + + // By default does nothing + error(message: string, ...args: unknown[]) {} + + // By default does nothing + warn(message: string, ...args: unknown[]) {} + + // By default does nothing + info(message: string, ...args: unknown[]) {} +} From 52dbd7520d27cfa37319a3c5a155e1a6cd12bdcf Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 22:38:47 +0200 Subject: [PATCH 06/13] chore: linting --- .../src/trace/instrumentation/Instrumentation.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts index ad83b0434c..262646d01e 100644 --- a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts +++ b/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts @@ -18,7 +18,6 @@ import { MeterProvider } from '../..'; import { Logger } from '../../common/Logger'; import { TracerProvider } from '../tracer_provider'; - /** Interface Instrumentation to apply patch. */ export interface Instrumentation { /** Instrumentation Name */ @@ -32,7 +31,7 @@ export interface Instrumentation { * as Instrumentation might patch different version of different modules, * or support different browsers etc. */ - instrumentationDescription?: string; + instrumentationDescription?: string; /** Method to disable the instrumentation */ disable(): void; @@ -47,7 +46,7 @@ export interface Instrumentation { setTracerProvider(tracerProvider: TracerProvider): void; /** Method to set meter provider */ - setMeterProvider(meterProvider: MeterProvider): void + setMeterProvider(meterProvider: MeterProvider): void; /** * Contains all supported versions. From 55204d9da43f0d3cfdcdc86aa68c65951f365ac0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 22:55:37 +0200 Subject: [PATCH 07/13] chore: updating readme with info about many modules --- packages/opentelemetry-instrumentation/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index b87b76e2fe..218264fc05 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -50,6 +50,8 @@ export class MyPlugin extends Instrumentation { module.files.push(this._addPatchingMethod()); return module; + // you can also define more modules then just return an array of modules + // return [module1, module2, ....] } private _addPatchingMethod(): InstrumentationNodeModuleFile { From d6d116986488a10c042e2ff839aaf23ff7264907 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 16 Sep 2020 23:47:05 +0200 Subject: [PATCH 08/13] chore: supporting calling enable and disable multiple times for node plugins --- .../opentelemetry-instrumentation/README.md | 34 ++++++------- .../src/platform/node/instrumentation.ts | 48 +++++++++++++++---- .../node/instrumentationNodeModuleFile.ts | 4 +- .../src/platform/node/types.ts | 14 ++++-- 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 218264fc05..10e8f09cfe 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -21,7 +21,7 @@ import { InstrumentationNodeModuleFile, } from '@opentelemetry/instrumentation'; -import * as plugin_name_to_be_pached from 'plugin_name_to_be_pached'; +import * as module_name_to_be_pached from 'module_name_to_be_pached'; export class MyPlugin extends Instrumentation { constructor(config: api.InstrumentationConfig = {}) { @@ -32,18 +32,18 @@ export class MyPlugin extends Instrumentation { // definitions for patching should be defined. It will be then called // before enabling the plugin and loading protected _init() { - const module = new InstrumentationNodeModuleDefinition( - 'plugin_name_to_be_pached', + const module = new InstrumentationNodeModuleDefinition( + 'module_name_to_be_pached', ['1.*'], - (exports) => { + (moduleExports: typeof module_name_to_be_pached) => { this._wrap( - exports, + moduleExports, 'mainMethodName', this._patchMainMethodName() ); }, - () => { - this._unwrap(exports, 'mainMethodName'); + (moduleExports: typeof module_name_to_be_pached) => { + this._unwrap(moduleExports, 'mainMethodName'); } ); // in case you need to patch additional files - this is optional @@ -54,19 +54,19 @@ export class MyPlugin extends Instrumentation { // return [module1, module2, ....] } - private _addPatchingMethod(): InstrumentationNodeModuleFile { - const file = new InstrumentationNodeModuleFile( - 'plugin_name_to_be_pached/src/some_file.js', - (exports: typeof plugin_name_to_be_pached) => { + private _addPatchingMethod(): InstrumentationNodeModuleFile { + const file = new InstrumentationNodeModuleFile( + 'module_name_to_be_pached/src/some_file.js', + (moduleExports: typeof module_name_to_be_pached) => { this._wrap( - exports, + moduleExports, 'methodName', this._patchMethodName() ); - return exports; + return moduleExports; }, - () => { - this._unwrap(exports, 'methodName'); + (moduleExports: typeof module_name_to_be_pached) => { + this._unwrap(moduleExports, 'methodName'); } ); return file; @@ -75,7 +75,7 @@ export class MyPlugin extends Instrumentation { private _patchMethodName(): (original) => any { const plugin = this; return function methodName(original) { - return function patchMethodName(this: any): PromiseOrValue { + return function patchMethodName(this: any): PromiseOrValue { console.log('methodName', arguments); return original.apply(this, arguments); }; @@ -85,7 +85,7 @@ export class MyPlugin extends Instrumentation { private _patchMainMethodName(): (original) => any { const plugin = this; return function mainMethodName(original) { - return function patchMainMethodName(this: any): PromiseOrValue { + return function patchMainMethodName(this: any): PromiseOrValue { console.log('mainMethodName', arguments); return original.apply(this, arguments); }; diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts index 4798d45da1..02925a6f78 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -32,6 +32,7 @@ export abstract class Instrumentation implements api.Instrumentation { private _modules: InstrumentationModuleDefinition[]; private _hooks: RequireInTheMiddle.Hooked[] = []; + private _enabled = false; constructor( instrumentationName: string, @@ -96,9 +97,11 @@ export abstract class Instrumentation const version = require(path.join(baseDir, 'package.json')).version; if (typeof version === 'string' && this._isSupported(name, version)) { if (typeof module.patch === 'function') { - return module.patch(exports); + module.moduleExports = exports; + if (this._enabled) { + return module.patch(exports); + } } - return exports; } } else { // internal file @@ -107,13 +110,36 @@ export abstract class Instrumentation (file: InstrumentationModuleFile) => file.name === name ); if (file) { - return file.patch(exports); + file.moduleExports = exports; + if (this._enabled) { + return file.patch(exports); + } } } return exports; } public enable() { + if (this._enabled) { + return; + } + this._enabled = true; + + // already hooked, just call patch again + if (this._hooks.length > 0) { + for (const module of this._modules) { + if (typeof module.patch === 'function' && module.moduleExports) { + module.patch(module.moduleExports); + } + for (const file of module.files) { + if (file.moduleExports) { + file.patch(file.moduleExports); + } + } + } + return; + } + for (const module of this._modules) { this._hooks.push( RequireInTheMiddle( @@ -135,15 +161,19 @@ export abstract class Instrumentation } public disable() { - this._hooks.forEach(hook => { - hook.unhook(); - }); + if (!this._enabled) { + return; + } + this._enabled = false; + for (const module of this._modules) { - if (typeof module.unpatch === 'function') { - module.unpatch(); + if (typeof module.unpatch === 'function' && module.moduleExports) { + module.unpatch(module.moduleExports); } for (const file of module.files) { - file.unpatch(); + if (file.moduleExports) { + file.unpatch(file.moduleExports); + } } } } diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts index 45ae81514f..52fec8f7ec 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentationNodeModuleFile.ts @@ -20,7 +20,7 @@ export class InstrumentationNodeModuleFile implements InstrumentationModuleFile { constructor( public name: string, - public patch: (exports: T) => T, - public unpatch: () => void + public patch: (moduleExports: T) => T, + public unpatch: (moduleExports?: T) => void ) {} } diff --git a/packages/opentelemetry-instrumentation/src/platform/node/types.ts b/packages/opentelemetry-instrumentation/src/platform/node/types.ts index a4d7c4cbb0..51091528eb 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/types.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/types.ts @@ -18,17 +18,23 @@ export interface InstrumentationModuleFile { /** Name of file to be patched with relative path */ name: string; + moduleExports?: T; + + /** Method to patch the instrumentation */ + patch(moduleExports: T): T; + /** Method to patch the instrumentation */ - patch(exports: T): T; /** Method to unpatch the instrumentation */ - unpatch(): void; + unpatch(moduleExports?: T): void; } export interface InstrumentationModuleDefinition { /** Module name or path */ name: string; + moduleExports?: T; + /** Supported version of module */ supportedVersions: string[]; @@ -36,8 +42,8 @@ export interface InstrumentationModuleDefinition { files: InstrumentationModuleFile[]; /** Method to patch the instrumentation */ - patch?: (exports: T) => T; + patch?: (moduleExports: T) => T; /** Method to unpatch the instrumentation */ - unpatch?: () => void; + unpatch?: (moduleExports: T) => void; } From 91a9fe0a07e46c9dd3a3a099dde3785f65e75128 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Tue, 22 Sep 2020 03:39:58 +0200 Subject: [PATCH 09/13] chore: simplifying readme example --- .../opentelemetry-instrumentation/README.md | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 10e8f09cfe..29cb755b82 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -21,30 +21,26 @@ import { InstrumentationNodeModuleFile, } from '@opentelemetry/instrumentation'; -import * as module_name_to_be_pached from 'module_name_to_be_pached'; +import type * as module_name_to_be_pached from 'module_name_to_be_pached'; export class MyPlugin extends Instrumentation { constructor(config: api.InstrumentationConfig = {}) { super('MyPlugin', VERSION, config); } - // init method is default method that needs to be defined where - // definitions for patching should be defined. It will be then called - // before enabling the plugin and loading + /** + * Init method will be called when the plugin is constructed. + * It returns an `InstrumentationNodeModuleDefinition` which describes + * the node module to be instrumented and patched. + * It may also return a list of `InstrumentationNodeModuleDefinition`s if + * the plugin should patch multiple modules or versions. + */ protected _init() { const module = new InstrumentationNodeModuleDefinition( 'module_name_to_be_pached', ['1.*'], - (moduleExports: typeof module_name_to_be_pached) => { - this._wrap( - moduleExports, - 'mainMethodName', - this._patchMainMethodName() - ); - }, - (moduleExports: typeof module_name_to_be_pached) => { - this._unwrap(moduleExports, 'mainMethodName'); - } + this._onPatchMain, + this._onUnPatchMain, ); // in case you need to patch additional files - this is optional module.files.push(this._addPatchingMethod()); @@ -54,24 +50,41 @@ export class MyPlugin extends Instrumentation { // return [module1, module2, ....] } + private _onPatchMain(moduleExports: typeof module_name_to_be_pached) { + this._wrap( + moduleExports, + 'mainMethodName', + this._patchMainMethodName() + ); + return moduleExports; + } + + private _onUnPatchMain(moduleExports: typeof module_name_to_be_pached) { + this._unwrap(moduleExports, 'mainMethodName'); + } + private _addPatchingMethod(): InstrumentationNodeModuleFile { const file = new InstrumentationNodeModuleFile( 'module_name_to_be_pached/src/some_file.js', - (moduleExports: typeof module_name_to_be_pached) => { - this._wrap( - moduleExports, - 'methodName', - this._patchMethodName() - ); - return moduleExports; - }, - (moduleExports: typeof module_name_to_be_pached) => { - this._unwrap(moduleExports, 'methodName'); - } + this._onPatchMethodName, + this._onUnPatchMethodName, ); return file; } + private _onPatchMethodName(moduleExports: typeof module_name_to_be_pached) { + this._wrap( + moduleExports, + 'methodName', + this._patchMethodName() + ); + return moduleExports; + } + + private _onUnPatchMethodName(moduleExports: typeof module_name_to_be_pached) { + this._unwrap(moduleExports, 'methodName'); + } + private _patchMethodName(): (original) => any { const plugin = this; return function methodName(original) { @@ -96,8 +109,8 @@ export class MyPlugin extends Instrumentation { // Later const myPLugin = new MyPlugin(); -myPLugin.setTracerProvider(provider); -myPLugin.setMeterProvider(meterProvider); +myPLugin.setTracerProvider(provider); // this is optional +myPLugin.setMeterProvider(meterProvider); // this is optional myPLugin.enable(); ``` From 5adbe25ee14b3717dae4650581351a118de3c92e Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Tue, 22 Sep 2020 03:44:49 +0200 Subject: [PATCH 10/13] chore: reviews --- packages/opentelemetry-instrumentation/README.md | 2 +- .../src/platform/node/instrumentation.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 29cb755b82..4c870f0506 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -35,7 +35,7 @@ export class MyPlugin extends Instrumentation { * It may also return a list of `InstrumentationNodeModuleDefinition`s if * the plugin should patch multiple modules or versions. */ - protected _init() { + protected init() { const module = new InstrumentationNodeModuleDefinition( 'module_name_to_be_pached', ['1.*'], diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts index 02925a6f78..a671873312 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -41,7 +41,7 @@ export abstract class Instrumentation ) { super(instrumentationName, instrumentationVersion, config); - let modules = this._init(); + let modules = this.init(); if (modules && !Array.isArray(modules)) { modules = [modules]; @@ -182,7 +182,7 @@ export abstract class Instrumentation * Init method in which plugin should define _modules and patches for * methods */ - protected abstract _init(): + protected abstract init(): | InstrumentationModuleDefinition | InstrumentationModuleDefinition[]; } From 417fc8d4cad6004543059e178aa89b463b277ddc Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Tue, 22 Sep 2020 17:18:18 +0200 Subject: [PATCH 11/13] chore: moving interface Instrumentation to package instrumentation --- packages/opentelemetry-api/src/index.ts | 1 - packages/opentelemetry-instrumentation/README.md | 16 +++++++++++----- .../opentelemetry-instrumentation/src/index.ts | 1 + .../src/instrumentation.ts | 9 +++++---- .../src/platform/browser/instrumentation.ts | 12 ++++++------ .../src/platform/node/instrumentation.ts | 12 ++++++------ .../src/types.ts} | 4 +--- .../test/common/Instrumentation.test.ts | 9 +++++---- 8 files changed, 35 insertions(+), 29 deletions(-) rename packages/{opentelemetry-api/src/trace/instrumentation/Instrumentation.ts => opentelemetry-instrumentation/src/types.ts} (94%) diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index 8ef623d924..12bb05f075 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -35,7 +35,6 @@ export * from './metrics/ObserverResult'; export * from './trace/attributes'; export * from './trace/Event'; export * from './trace/instrumentation/Plugin'; -export * from './trace/instrumentation/Instrumentation'; export * from './trace/link_context'; export * from './trace/link'; export * from './trace/NoopLogger'; diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 4c870f0506..7fc7684cbc 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -16,15 +16,16 @@ npm install --save @opentelemetry/instrumentation ```typescript import { - Instrumentation, + InstrumentationBase, + InstrumentationConfig, InstrumentationNodeModuleDefinition, InstrumentationNodeModuleFile, } from '@opentelemetry/instrumentation'; import type * as module_name_to_be_pached from 'module_name_to_be_pached'; -export class MyPlugin extends Instrumentation { - constructor(config: api.InstrumentationConfig = {}) { +export class MyPlugin extends InstrumentationBase { + constructor(config: InstrumentationConfig = {}) { super('MyPlugin', VERSION, config); } @@ -117,10 +118,15 @@ myPLugin.enable(); ## Usage in Web ```typescript +import { + InstrumentationBase, + InstrumentationConfig, +} from '@opentelemetry/instrumentation'; + import { Instrumentation } from '@opentelemetry/instrumentation'; -export class MyPlugin extends Instrumentation { - constructor(config: api.InstrumentationConfig = {}) { +export class MyPlugin extends InstrumentationBase { + constructor(config: InstrumentationConfig = {}) { super('MyPlugin', VERSION, config); } diff --git a/packages/opentelemetry-instrumentation/src/index.ts b/packages/opentelemetry-instrumentation/src/index.ts index f41f77b271..89e50179fc 100644 --- a/packages/opentelemetry-instrumentation/src/index.ts +++ b/packages/opentelemetry-instrumentation/src/index.ts @@ -15,3 +15,4 @@ */ export * from './platform/index'; +export * from './types'; diff --git a/packages/opentelemetry-instrumentation/src/instrumentation.ts b/packages/opentelemetry-instrumentation/src/instrumentation.ts index da1c75b271..e6ee7c77c5 100644 --- a/packages/opentelemetry-instrumentation/src/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/instrumentation.ts @@ -16,13 +16,14 @@ import * as api from '@opentelemetry/api'; import * as shimmer from 'shimmer'; +import * as types from './types'; /** * Base abstract internal class for instrumenting node and web plugins */ -export abstract class BaseInstrumentation - implements api.Instrumentation { - protected _config: api.InstrumentationConfig; +export abstract class InstrumentationAbstract + implements types.Instrumentation { + protected _config: types.InstrumentationConfig; private _tracer: api.Tracer; private _meter: api.Meter; @@ -31,7 +32,7 @@ export abstract class BaseInstrumentation constructor( public readonly instrumentationName: string, public readonly instrumentationVersion: string, - config: api.InstrumentationConfig = {} + config: types.InstrumentationConfig = {} ) { this._config = { enabled: true, diff --git a/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts index a8d90b3c33..0c900d9f28 100644 --- a/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/platform/browser/instrumentation.ts @@ -14,19 +14,19 @@ * limitations under the License. */ -import * as api from '@opentelemetry/api'; -import { BaseInstrumentation } from '../../instrumentation'; +import { InstrumentationAbstract } from '../../instrumentation'; +import * as types from '../../types'; /** * Base abstract class for instrumenting web plugins */ -export abstract class Instrumentation - extends BaseInstrumentation - implements api.Instrumentation { +export abstract class InstrumentationBase + extends InstrumentationAbstract + implements types.Instrumentation { constructor( readonly instrumentationName: string, readonly instrumentationVersion: string, - config: api.InstrumentationConfig = {} + config: types.InstrumentationConfig = {} ) { super(instrumentationName, instrumentationVersion, config); diff --git a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts index a671873312..a9a58757bc 100644 --- a/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import * as api from '@opentelemetry/api'; +import * as types from '../../types'; import * as path from 'path'; import * as RequireInTheMiddle from 'require-in-the-middle'; import * as semver from 'semver'; -import { BaseInstrumentation } from '../../instrumentation'; +import { InstrumentationAbstract } from '../../instrumentation'; import { InstrumentationModuleDefinition, InstrumentationModuleFile, @@ -27,9 +27,9 @@ import { /** * Base abstract class for instrumenting node plugins */ -export abstract class Instrumentation - extends BaseInstrumentation - implements api.Instrumentation { +export abstract class InstrumentationBase + extends InstrumentationAbstract + implements types.Instrumentation { private _modules: InstrumentationModuleDefinition[]; private _hooks: RequireInTheMiddle.Hooked[] = []; private _enabled = false; @@ -37,7 +37,7 @@ export abstract class Instrumentation constructor( instrumentationName: string, instrumentationVersion: string, - config: api.InstrumentationConfig = {} + config: types.InstrumentationConfig = {} ) { super(instrumentationName, instrumentationVersion, config); diff --git a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts b/packages/opentelemetry-instrumentation/src/types.ts similarity index 94% rename from packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts rename to packages/opentelemetry-instrumentation/src/types.ts index 262646d01e..6c564ebbed 100644 --- a/packages/opentelemetry-api/src/trace/instrumentation/Instrumentation.ts +++ b/packages/opentelemetry-instrumentation/src/types.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { MeterProvider } from '../..'; -import { Logger } from '../../common/Logger'; -import { TracerProvider } from '../tracer_provider'; +import { Logger, MeterProvider, TracerProvider } from '@opentelemetry/api'; /** Interface Instrumentation to apply patch. */ export interface Instrumentation { diff --git a/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts index f900672c71..8244f01031 100644 --- a/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts +++ b/packages/opentelemetry-instrumentation/test/common/Instrumentation.test.ts @@ -15,9 +15,10 @@ */ import * as assert from 'assert'; -import { BaseInstrumentation } from '../../src/instrumentation'; +import { Instrumentation } from '../../src'; +import { InstrumentationAbstract } from '../../src/instrumentation'; -class TestInstrumentation extends BaseInstrumentation { +class TestInstrumentation extends InstrumentationAbstract { constructor() { super('test', '1.0.0'); } @@ -26,13 +27,13 @@ class TestInstrumentation extends BaseInstrumentation { } describe('BaseInstrumentation', () => { - let instrumentation: BaseInstrumentation; + let instrumentation: Instrumentation; beforeEach(() => { instrumentation = new TestInstrumentation(); }); it('should create an instance', () => { - assert.ok(instrumentation instanceof BaseInstrumentation); + assert.ok(instrumentation instanceof InstrumentationAbstract); }); it('should have a name', () => { From 5d3a456d192f47458ef61a9c3b51b939a0f72269 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Tue, 29 Sep 2020 20:55:54 +0200 Subject: [PATCH 12/13] chore: adding function for safe executing in plugins --- .../src/index.ts | 1 + .../src/types.ts | 6 --- .../src/utils.ts | 41 +++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 packages/opentelemetry-instrumentation/src/utils.ts diff --git a/packages/opentelemetry-instrumentation/src/index.ts b/packages/opentelemetry-instrumentation/src/index.ts index 89e50179fc..acb0986848 100644 --- a/packages/opentelemetry-instrumentation/src/index.ts +++ b/packages/opentelemetry-instrumentation/src/index.ts @@ -16,3 +16,4 @@ export * from './platform/index'; export * from './types'; +export * from './utils'; diff --git a/packages/opentelemetry-instrumentation/src/types.ts b/packages/opentelemetry-instrumentation/src/types.ts index 6c564ebbed..5ab42344be 100644 --- a/packages/opentelemetry-instrumentation/src/types.ts +++ b/packages/opentelemetry-instrumentation/src/types.ts @@ -37,9 +37,6 @@ export interface Instrumentation { /** Method to enable the instrumentation */ enable(): void; - /** Method to patch the instrumentation */ - // patch(exports: T, name: string, baseDir?: string): T; - /** Method to set tracer provider */ setTracerProvider(tracerProvider: TracerProvider): void; @@ -53,9 +50,6 @@ export interface Instrumentation { * If omitted, all versions of the module will be patched. */ supportedVersions?: string[]; - - /** Method to unpatch the instrumentation */ - // unpatch(): void; } export interface InstrumentationConfig { diff --git a/packages/opentelemetry-instrumentation/src/utils.ts b/packages/opentelemetry-instrumentation/src/utils.ts new file mode 100644 index 0000000000..04b36384e0 --- /dev/null +++ b/packages/opentelemetry-instrumentation/src/utils.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * function to execute patched function and being able to catch errors + * @param execute - function to be executed + * @param onFinish - callback to run when execute finishes + */ +export function safeExecuteInTheMiddle( + execute: () => T, + onFinish: (e: Error | undefined, result: T | undefined) => void +): T { + let error: Error | undefined; + let result: T | undefined; + try { + result = execute(); + } catch (e) { + error = e; + } finally { + onFinish(error, result); + if (error) { + // eslint-disable-next-line no-unsafe-finally + throw error; + } + // eslint-disable-next-line no-unsafe-finally + return result as T; + } +} From dddd15996f9531051eca0ae1f50f2625ef5b9c1b Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Tue, 29 Sep 2020 23:55:18 +0200 Subject: [PATCH 13/13] chore: fixing typo --- .../opentelemetry-instrumentation/README.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/opentelemetry-instrumentation/README.md b/packages/opentelemetry-instrumentation/README.md index 7fc7684cbc..9988303d16 100644 --- a/packages/opentelemetry-instrumentation/README.md +++ b/packages/opentelemetry-instrumentation/README.md @@ -22,7 +22,7 @@ import { InstrumentationNodeModuleFile, } from '@opentelemetry/instrumentation'; -import type * as module_name_to_be_pached from 'module_name_to_be_pached'; +import type * as module_name_to_be_patched from 'module_name_to_be_patched'; export class MyPlugin extends InstrumentationBase { constructor(config: InstrumentationConfig = {}) { @@ -37,8 +37,8 @@ export class MyPlugin extends InstrumentationBase { * the plugin should patch multiple modules or versions. */ protected init() { - const module = new InstrumentationNodeModuleDefinition( - 'module_name_to_be_pached', + const module = new InstrumentationNodeModuleDefinition( + 'module_name_to_be_patched', ['1.*'], this._onPatchMain, this._onUnPatchMain, @@ -51,7 +51,7 @@ export class MyPlugin extends InstrumentationBase { // return [module1, module2, ....] } - private _onPatchMain(moduleExports: typeof module_name_to_be_pached) { + private _onPatchMain(moduleExports: typeof module_name_to_be_patched) { this._wrap( moduleExports, 'mainMethodName', @@ -60,20 +60,20 @@ export class MyPlugin extends InstrumentationBase { return moduleExports; } - private _onUnPatchMain(moduleExports: typeof module_name_to_be_pached) { + private _onUnPatchMain(moduleExports: typeof module_name_to_be_patched) { this._unwrap(moduleExports, 'mainMethodName'); } - private _addPatchingMethod(): InstrumentationNodeModuleFile { - const file = new InstrumentationNodeModuleFile( - 'module_name_to_be_pached/src/some_file.js', + private _addPatchingMethod(): InstrumentationNodeModuleFile { + const file = new InstrumentationNodeModuleFile( + 'module_name_to_be_patched/src/some_file.js', this._onPatchMethodName, this._onUnPatchMethodName, ); return file; } - private _onPatchMethodName(moduleExports: typeof module_name_to_be_pached) { + private _onPatchMethodName(moduleExports: typeof module_name_to_be_patched) { this._wrap( moduleExports, 'methodName', @@ -82,14 +82,14 @@ export class MyPlugin extends InstrumentationBase { return moduleExports; } - private _onUnPatchMethodName(moduleExports: typeof module_name_to_be_pached) { + private _onUnPatchMethodName(moduleExports: typeof module_name_to_be_patched) { this._unwrap(moduleExports, 'methodName'); } private _patchMethodName(): (original) => any { const plugin = this; return function methodName(original) { - return function patchMethodName(this: any): PromiseOrValue { + return function patchMethodName(this: any): PromiseOrValue { console.log('methodName', arguments); return original.apply(this, arguments); }; @@ -99,7 +99,7 @@ export class MyPlugin extends InstrumentationBase { private _patchMainMethodName(): (original) => any { const plugin = this; return function mainMethodName(original) { - return function patchMainMethodName(this: any): PromiseOrValue { + return function patchMainMethodName(this: any): PromiseOrValue { console.log('mainMethodName', arguments); return original.apply(this, arguments); };