From 9aeec87e961b17f8d3b98a7c270e92cf422ff115 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 24 Mar 2021 00:38:26 +0100 Subject: [PATCH] chore: adding meta package for web (#391) * chore: adding meta package for web * chore: undo comment --- examples/web/examples/meta/index.html | 39 ++++ examples/web/examples/meta/index.js | 86 ++++++++ examples/web/package.json | 2 + examples/web/webpack.config.js | 1 + .../auto-instrumentations-node/README.md | 2 +- .../auto-instrumentations-web/.eslintignore | 2 + .../auto-instrumentations-web/.eslintrc.js | 8 + .../auto-instrumentations-web/.npmignore | 4 + .../auto-instrumentations-web/LICENSE | 201 ++++++++++++++++++ .../auto-instrumentations-web/README.md | 64 ++++++ .../auto-instrumentations-web/karma.conf.js | 24 +++ .../auto-instrumentations-web/package.json | 65 ++++++ .../auto-instrumentations-web/src/index.ts | 17 ++ .../auto-instrumentations-web/src/utils.ts | 72 +++++++ .../test/index-webpack.ts | 20 ++ .../test/utils.test.ts | 95 +++++++++ .../auto-instrumentations-web/tsconfig.json | 12 ++ .../src/documentLoad.ts | 2 +- 18 files changed, 714 insertions(+), 2 deletions(-) create mode 100644 examples/web/examples/meta/index.html create mode 100644 examples/web/examples/meta/index.js create mode 100644 metapackages/auto-instrumentations-web/.eslintignore create mode 100644 metapackages/auto-instrumentations-web/.eslintrc.js create mode 100644 metapackages/auto-instrumentations-web/.npmignore create mode 100644 metapackages/auto-instrumentations-web/LICENSE create mode 100644 metapackages/auto-instrumentations-web/README.md create mode 100644 metapackages/auto-instrumentations-web/karma.conf.js create mode 100644 metapackages/auto-instrumentations-web/package.json create mode 100644 metapackages/auto-instrumentations-web/src/index.ts create mode 100644 metapackages/auto-instrumentations-web/src/utils.ts create mode 100644 metapackages/auto-instrumentations-web/test/index-webpack.ts create mode 100644 metapackages/auto-instrumentations-web/test/utils.test.ts create mode 100644 metapackages/auto-instrumentations-web/tsconfig.json diff --git a/examples/web/examples/meta/index.html b/examples/web/examples/meta/index.html new file mode 100644 index 0000000000..6862dcc0d7 --- /dev/null +++ b/examples/web/examples/meta/index.html @@ -0,0 +1,39 @@ + + + + + + User Interaction Example + + + + + + + + + + Example of using Web Tracer with meta package and with console exporter and collector exporter + +
+ +
+
+
+
+
+
+
+
+ + + + diff --git a/examples/web/examples/meta/index.js b/examples/web/examples/meta/index.js new file mode 100644 index 0000000000..0a0f824847 --- /dev/null +++ b/examples/web/examples/meta/index.js @@ -0,0 +1,86 @@ +import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; +import { WebTracerProvider } from '@opentelemetry/web'; +import { ZoneContextManager } from '@opentelemetry/context-zone'; +import { CollectorTraceExporter } from '@opentelemetry/exporter-collector'; +import { B3Propagator } from '@opentelemetry/propagator-b3'; +import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; +import { registerInstrumentations } from '@opentelemetry/instrumentation'; + +const providerWithZone = new WebTracerProvider(); + +providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new CollectorTraceExporter())); + +providerWithZone.register({ + contextManager: new ZoneContextManager(), + propagator: new B3Propagator(), +}); +const instrumentations = getWebAutoInstrumentations({ + '@opentelemetry/instrumentation-xml-http-request': { + ignoreUrls: [/localhost/], + propagateTraceHeaderCorsUrls: [ + 'http://localhost:8090', + ], + }, +}); + +registerInstrumentations({ + instrumentations, + tracerProvider: providerWithZone, +}); + +let lastButtonId = 0; + +function btnAddClick() { + lastButtonId++; + const btn = document.createElement('button'); + // for easier testing of element xpath + let navigate = false; + if (lastButtonId % 2 === 0) { + btn.setAttribute('id', `button${lastButtonId}`); + navigate = true; + } + btn.setAttribute('class', `buttonClass${lastButtonId}`); + btn.append(document.createTextNode(`Click ${lastButtonId}`)); + btn.addEventListener('click', onClick.bind(this, navigate)); + document.querySelector('#buttons').append(btn); +} + +function prepareClickEvents() { + for (let i = 0; i < 5; i++) { + btnAddClick(); + } + const btnAdd = document.getElementById('btnAdd'); + btnAdd.addEventListener('click', btnAddClick); +} + +function onClick(navigate) { + if (navigate) { + history.pushState({ test: 'testing' }, '', `${location.pathname}`); + history.pushState({ test: 'testing' }, '', `${location.pathname}#foo=bar1`); + } + getData('https://httpbin.org/get?a=1').then(() => { + getData('https://httpbin.org/get?a=1').then(() => { + console.log('data downloaded 2'); + }); + getData('https://httpbin.org/get?a=1').then(() => { + console.log('data downloaded 3'); + }); + console.log('data downloaded 1'); + }); +} + +function getData(url, resolve) { + return new Promise(async (resolve, reject) => { + const req = new XMLHttpRequest(); + req.open('GET', url, true); + req.setRequestHeader('Content-Type', 'application/json'); + req.setRequestHeader('Accept', 'application/json'); + req.send(); + req.onload = function () { + resolve(); + }; + }); +} + +window.addEventListener('load', prepareClickEvents); diff --git a/examples/web/package.json b/examples/web/package.json index 1603686a70..8299371bc7 100644 --- a/examples/web/package.json +++ b/examples/web/package.json @@ -34,6 +34,8 @@ "webpack-merge": "^4.2.2" }, "dependencies": { + "@opentelemetry/api": "^0.18.0", + "@opentelemetry/auto-instrumentations-web": "^0.14.0", "@opentelemetry/context-zone": "^0.18.0", "@opentelemetry/core": "^0.18.0", "@opentelemetry/exporter-collector": "^0.18.0", diff --git a/examples/web/webpack.config.js b/examples/web/webpack.config.js index 8d921d0b6a..a431e9e2b6 100644 --- a/examples/web/webpack.config.js +++ b/examples/web/webpack.config.js @@ -10,6 +10,7 @@ const common = { mode: 'development', entry: { 'document-load': 'examples/document-load/index.js', + 'meta': 'examples/meta/index.js', 'user-interaction': 'examples/user-interaction/index.js', }, output: { diff --git a/metapackages/auto-instrumentations-node/README.md b/metapackages/auto-instrumentations-node/README.md index a0c60fb676..5d34e37929 100644 --- a/metapackages/auto-instrumentations-node/README.md +++ b/metapackages/auto-instrumentations-node/README.md @@ -1,4 +1,4 @@ -#OpenTelemetry Meta Packages for Node +# OpenTelemetry Meta Packages for Node [![NPM Published Version][npm-img]][npm-url] [![dependencies][dependencies-image]][dependencies-url] [![devDependencies][devDependencies-image]][devDependencies-url] diff --git a/metapackages/auto-instrumentations-web/.eslintignore b/metapackages/auto-instrumentations-web/.eslintignore new file mode 100644 index 0000000000..03db8f9b34 --- /dev/null +++ b/metapackages/auto-instrumentations-web/.eslintignore @@ -0,0 +1,2 @@ +build +.eslintrc.js diff --git a/metapackages/auto-instrumentations-web/.eslintrc.js b/metapackages/auto-instrumentations-web/.eslintrc.js new file mode 100644 index 0000000000..fe91e21049 --- /dev/null +++ b/metapackages/auto-instrumentations-web/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + "env": { + "commonjs": true, + "node": true, + "mocha": true, + }, + ...require('../../eslint.config.js') +} diff --git a/metapackages/auto-instrumentations-web/.npmignore b/metapackages/auto-instrumentations-web/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/metapackages/auto-instrumentations-web/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/metapackages/auto-instrumentations-web/LICENSE b/metapackages/auto-instrumentations-web/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/metapackages/auto-instrumentations-web/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/metapackages/auto-instrumentations-web/README.md b/metapackages/auto-instrumentations-web/README.md new file mode 100644 index 0000000000..4535f6c15a --- /dev/null +++ b/metapackages/auto-instrumentations-web/README.md @@ -0,0 +1,64 @@ +# OpenTelemetry Meta Packages for Web +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-url] + +## Installation + +```bash +npm install --save @opentelemetry/auto-instrumentations-web +``` + +## Usage + +```javascript +const { WebTracerProvider } = require('@opentelemetry/web'); +const { getWebAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-web'); +const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector'); +const { SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); +const { ZoneContextManager } = require('@opentelemetry/context-zone'); +const { B3Propagator } = require('@opentelemetry/propagator-b3'); + +const exporter = new CollectorTraceExporter({ + serviceName: 'auto-instrumentations-web', +}); + +const provider = new WebTracerProvider(); +provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); +provider.register({ + contextManager: new ZoneContextManager(), + propagator: new B3Propagator(), +}); + +registerInstrumentations({ + instrumentations: [ + getWebAutoInstrumentations({ + // load custom configuration for xml-http-request instrumentation + "@opentelemetry/instrumentation-xml-http-request": { + clearTimingResources: true, + }, + }), + ], +}); + +``` + +## Useful links + +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: + +## License + +APACHE 2.0 - See [LICENSE][license-url] for more information. + +[license-url]: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib.svg?path=packages%2Fauto-instrumentations-web +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=packages%2Fauto-instrumentations-web +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib.svg?path=packages%2Fauto-instrumentations-web&type=dev +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=packages%2Fauto-instrumentations-web&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-web +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fauto-instrumentations-web.svg diff --git a/metapackages/auto-instrumentations-web/karma.conf.js b/metapackages/auto-instrumentations-web/karma.conf.js new file mode 100644 index 0000000000..edcd9f055f --- /dev/null +++ b/metapackages/auto-instrumentations-web/karma.conf.js @@ -0,0 +1,24 @@ +/*! + * Copyright 2020, 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/metapackages/auto-instrumentations-web/package.json b/metapackages/auto-instrumentations-web/package.json new file mode 100644 index 0000000000..5e65a8e914 --- /dev/null +++ b/metapackages/auto-instrumentations-web/package.json @@ -0,0 +1,65 @@ +{ + "name": "@opentelemetry/auto-instrumentations-web", + "version": "0.14.0", + "description": "Metapackage which bundles opentelemetry node core and contrib instrumentations", + "author": "OpenTelemetry Authors", + "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib#readme", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "repository": "open-telemetry/opentelemetry-js-contrib", + "scripts": { + "clean": "tsc --build --clean", + "codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "compile": "tsc --build", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "precompile": "tsc --version", + "prepare": "npm run compile", + "test:browser": "nyc karma start --single-run", + "version": "node ../../scripts/version-update.js", + "watch": "tsc --build --watch" + }, + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js-contrib/issues" + }, + "devDependencies": { + "@babel/core": "7.12.10", + "@types/mocha": "8.2.0", + "@types/node": "14.0.27", + "@types/sinon": "9.0.10", + "@types/webpack-env": "1.16.0", + "babel-loader": "8.2.2", + "codecov": "3.8.1", + "gts": "3.1.0", + "istanbul-instrumenter-loader": "3.0.1", + "karma": "5.2.3", + "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.2.3", + "ts-loader": "8.0.14", + "ts-mocha": "8.0.0", + "ts-node": "9.1.1", + "typescript": "4.1.3", + "webpack": "4.46.0", + "webpack-cli": "4.3.1", + "webpack-merge": "5.7.3" + }, + "dependencies": { + "@opentelemetry/api": "^0.18.0", + "@opentelemetry/instrumentation": "^0.18.0", + "@opentelemetry/instrumentation-document-load": "^0.14.0", + "@opentelemetry/instrumentation-fetch": "^0.18.0", + "@opentelemetry/instrumentation-user-interaction": "^0.14.0", + "@opentelemetry/instrumentation-xml-http-request": "^0.18.0" + } +} diff --git a/metapackages/auto-instrumentations-web/src/index.ts b/metapackages/auto-instrumentations-web/src/index.ts new file mode 100644 index 0000000000..65640412e6 --- /dev/null +++ b/metapackages/auto-instrumentations-web/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 { getWebAutoInstrumentations, InstrumentationConfigMap } from './utils'; diff --git a/metapackages/auto-instrumentations-web/src/utils.ts b/metapackages/auto-instrumentations-web/src/utils.ts new file mode 100644 index 0000000000..e76cea6ef9 --- /dev/null +++ b/metapackages/auto-instrumentations-web/src/utils.ts @@ -0,0 +1,72 @@ +/* + * 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 { diag } from '@opentelemetry/api'; +import { Instrumentation } from '@opentelemetry/instrumentation'; +import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'; +import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; +import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction'; +import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; + +const InstrumentationMap = { + '@opentelemetry/instrumentation-document-load': DocumentLoadInstrumentation, + '@opentelemetry/instrumentation-fetch': FetchInstrumentation, + '@opentelemetry/instrumentation-user-interaction': UserInteractionInstrumentation, + '@opentelemetry/instrumentation-xml-http-request': XMLHttpRequestInstrumentation, +}; + +// Config types inferred automatically from the first argument of the constructor +type ConfigArg = T extends new (...args: infer U) => unknown ? U[0] : never; +export type InstrumentationConfigMap = { + [Name in keyof typeof InstrumentationMap]?: ConfigArg< + typeof InstrumentationMap[Name] + >; +}; + +export function getWebAutoInstrumentations( + inputConfigs: InstrumentationConfigMap = {} +): Instrumentation[] { + for (const name of Object.keys(inputConfigs)) { + if (!Object.prototype.hasOwnProperty.call(InstrumentationMap, name)) { + diag.error(`Provided instrumentation name "${name}" not found`); + continue; + } + } + + const instrumentations: Instrumentation[] = []; + + for (const name of Object.keys(InstrumentationMap) as Array< + keyof typeof InstrumentationMap + >) { + const Instance = InstrumentationMap[name]; + // Defaults are defined by the instrumentation itself + const userConfig = inputConfigs[name] ?? {}; + + if (userConfig.enabled === false) { + diag.debug(`Disabling instrumentation for ${name}`); + continue; + } + + try { + diag.debug(`Loading instrumentation for ${name}`); + instrumentations.push(new Instance(userConfig)); + } catch (e) { + diag.error(e); + } + } + + return instrumentations; +} diff --git a/metapackages/auto-instrumentations-web/test/index-webpack.ts b/metapackages/auto-instrumentations-web/test/index-webpack.ts new file mode 100644 index 0000000000..061a48ccfa --- /dev/null +++ b/metapackages/auto-instrumentations-web/test/index-webpack.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. + */ +const testsContext = require.context('.', true, /test$/); +testsContext.keys().forEach(testsContext); + +const srcContext = require.context('.', true, /src$/); +srcContext.keys().forEach(srcContext); diff --git a/metapackages/auto-instrumentations-web/test/utils.test.ts b/metapackages/auto-instrumentations-web/test/utils.test.ts new file mode 100644 index 0000000000..4ee9a9425b --- /dev/null +++ b/metapackages/auto-instrumentations-web/test/utils.test.ts @@ -0,0 +1,95 @@ +/* + * 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 { diag } from '@opentelemetry/api'; +import { XMLHttpRequestInstrumentationConfig } from '@opentelemetry/instrumentation-xml-http-request'; +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import { getWebAutoInstrumentations } from '../src'; + +describe('utils', () => { + describe('getWebAutoInstrumentations', () => { + it('should load default instrumentations', () => { + const instrumentations = getWebAutoInstrumentations(); + const expectedInstrumentations = [ + '@opentelemetry/instrumentation-document-load', + '@opentelemetry/instrumentation-fetch', + '@opentelemetry/instrumentation-user-interaction', + '@opentelemetry/instrumentation-xml-http-request', + ]; + assert.strictEqual(instrumentations.length, 4); + for (let i = 0, j = instrumentations.length; i < j; i++) { + assert.strictEqual( + instrumentations[i].instrumentationName, + expectedInstrumentations[i], + `Instrumentation ${expectedInstrumentations[i]}, not loaded` + ); + } + }); + + it('should use user config', () => { + const clearTimingResources = true; + + const instrumentations = getWebAutoInstrumentations({ + '@opentelemetry/instrumentation-xml-http-request': { + clearTimingResources, + }, + }); + const instrumentation = instrumentations.find( + instr => + instr.instrumentationName === + '@opentelemetry/instrumentation-xml-http-request' + ) as any; + const config = instrumentation._config as XMLHttpRequestInstrumentationConfig; + + assert.strictEqual(config.clearTimingResources, clearTimingResources); + }); + + it('should not return disabled instrumentation', () => { + const instrumentations = getWebAutoInstrumentations({ + '@opentelemetry/instrumentation-xml-http-request': { + enabled: false, + }, + }); + const instrumentation = instrumentations.find( + instr => + instr.instrumentationName === + '@opentelemetry/instrumentation-xml-http-request' + ); + assert.strictEqual(instrumentation, undefined); + }); + + it('should show error for none existing instrumentation', () => { + const spy = sinon.stub(diag, 'error'); + const name = '@opentelemetry/instrumentation-http2'; + const instrumentations = getWebAutoInstrumentations({ + // @ts-expect-error verify that wrong name works + [name]: { + enabled: false, + }, + }); + const instrumentation = instrumentations.find( + instr => instr.instrumentationName === name + ); + assert.strictEqual(instrumentation, undefined); + + assert.strictEqual( + spy.args[0][0], + `Provided instrumentation name "${name}" not found` + ); + }); + }); +}); diff --git a/metapackages/auto-instrumentations-web/tsconfig.json b/metapackages/auto-instrumentations-web/tsconfig.json new file mode 100644 index 0000000000..e1baf4c16d --- /dev/null +++ b/metapackages/auto-instrumentations-web/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build", + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts index e98fa90502..7a55e65b9d 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts @@ -52,7 +52,7 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { * @param config */ constructor(config: InstrumentationConfig = {}) { - super('@opentelemetry/plugin-document-load', VERSION, config); + super('@opentelemetry/instrumentation-document-load', VERSION, config); } init() {}