diff --git a/README.md b/README.md
index 29b6585df0..4091bdd090 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,7 @@ OpenTelemetry can collect tracing data automatically using plugins. Vendors/User
- [@opentelemetry/plugin-express][otel-plugin-express]
- [@opentelemetry/plugin-dns][otel-plugin-dns]
- [@opentelemetry/hapi-instrumentation][otel-contrib-hapi-instrumentation]
-- [@opentelemetry/koa-instrumentation][otel-contrib-koa-instrumentation]
+- [@opentelemetry/instrumentation-koa][otel-contrib-instrumentation-koa]
- [@opentelemetry/instrumentation-graphql][otel-contrib-instrumentation-graphql]
### Web Plugins
@@ -135,5 +135,5 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[otel-plugin-express]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-plugin-express
[otel-plugins-node-core-and-contrib]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/metapackages/plugins-node-core-and-contrib
[otel-contrib-hapi-instrumentation]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-hapi-instrumentation
-[otel-contrib-koa-instrumentation]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-koa-instrumentation
+[otel-contrib-instrumentation-koa]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-koa
[otel-contrib-instrumentation-graphql]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-graphql
diff --git a/examples/koa/package.json b/examples/koa/package.json
index c72492ae61..eda6cdc073 100644
--- a/examples/koa/package.json
+++ b/examples/koa/package.json
@@ -35,9 +35,10 @@
"@opentelemetry/api": "^0.15.0",
"@opentelemetry/exporter-jaeger": "^0.15.0",
"@opentelemetry/exporter-zipkin": "^0.15.0",
- "@opentelemetry/koa-instrumentation": "^0.13.0",
+ "@opentelemetry/instrumentation": "^0.15.0",
+ "@opentelemetry/instrumentation-http": "^0.15.0",
+ "@opentelemetry/instrumentation-koa": "^0.13.1",
"@opentelemetry/node": "^0.15.0",
- "@opentelemetry/plugin-http": "^0.15.0",
"@opentelemetry/tracing": "^0.15.0",
"axios": "^0.19.0",
"koa": "^2.13.0"
diff --git a/examples/koa/server.js b/examples/koa/server.js
index 7bd3a1b2f1..3f7b6a1b36 100644
--- a/examples/koa/server.js
+++ b/examples/koa/server.js
@@ -1,7 +1,8 @@
'use strict';
-// eslint-disable-next-line
-const tracer = require('./tracer')('example-koa-server');
+const api = require('@opentelemetry/api');
+
+require('./tracer')('example-koa-server');
// Adding Koa router (if desired)
const router = require('@koa/router')();
@@ -28,7 +29,7 @@ const posts = ['post 0', 'post 1', 'post 2'];
function addPost(ctx) {
posts.push(`post ${posts.length}`);
- const currentSpan = tracer.getCurrentSpan();
+ const currentSpan = api.getSpan(api.context.active());
currentSpan.addEvent('Added post');
currentSpan.setAttribute('Date', new Date());
ctx.body = `Added post: ${posts[posts.length - 1]}`;
@@ -47,7 +48,7 @@ async function showNewPost(ctx) {
function runTest(ctx) {
console.log('runTest');
- const currentSpan = tracer.getCurrentSpan();
+ const currentSpan = api.getSpan(api.context.active());
const { traceId } = currentSpan.context();
console.log(`traceid: ${traceId}`);
console.log(`Jaeger URL: http://localhost:16686/trace/${traceId}`);
diff --git a/examples/koa/tracer.js b/examples/koa/tracer.js
index fec566dd21..a451dfbf04 100644
--- a/examples/koa/tracer.js
+++ b/examples/koa/tracer.js
@@ -1,6 +1,10 @@
'use strict';
-const opentelemetry = require('@opentelemetry/api');
+const { KoaInstrumentation } = require('@opentelemetry/instrumentation-koa');
+const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
+
+const api = require('@opentelemetry/api');
+const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { NodeTracerProvider } = require('@opentelemetry/node');
const { SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
@@ -9,19 +13,7 @@ const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');
const EXPORTER = process.env.EXPORTER || '';
module.exports = (serviceName) => {
- const provider = new NodeTracerProvider({
- plugins: {
- koa: {
- enabled: true,
- path: '@opentelemetry/koa-instrumentation',
- enhancedDatabaseReporting: true,
- },
- http: {
- enabled: true,
- path: '@opentelemetry/plugin-http',
- },
- },
- });
+ const provider = new NodeTracerProvider();
let exporter;
if (EXPORTER === 'jaeger') {
@@ -31,8 +23,16 @@ module.exports = (serviceName) => {
}
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
+ registerInstrumentations({
+ instrumentations: [
+ new KoaInstrumentation(),
+ new HttpInstrumentation(),
+ ],
+ tracerProvider: provider,
+ });
+
// Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings
provider.register();
- return opentelemetry.trace.getTracer('koa-example');
+ return api.trace.getTracer('koa-example');
};
diff --git a/package.json b/package.json
index 81f6198632..bec3521bf1 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,8 @@
"version": "0.13.1",
"description": "This is a repository for OpenTelemetry JavaScript contributions.",
"repository": {
- "type" : "git",
- "url" : "https://github.com/open-telemetry/opentelemetry-js-contrib.git"
+ "type": "git",
+ "url": "https://github.com/open-telemetry/opentelemetry-js-contrib.git"
},
"publishConfig": {
"access": "public"
diff --git a/plugins/node/opentelemetry-koa-instrumentation/.eslintignore b/plugins/node/opentelemetry-instrumentation-koa/.eslintignore
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/.eslintignore
rename to plugins/node/opentelemetry-instrumentation-koa/.eslintignore
diff --git a/plugins/node/opentelemetry-koa-instrumentation/.eslintrc.js b/plugins/node/opentelemetry-instrumentation-koa/.eslintrc.js
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/.eslintrc.js
rename to plugins/node/opentelemetry-instrumentation-koa/.eslintrc.js
diff --git a/plugins/node/opentelemetry-koa-instrumentation/.npmignore b/plugins/node/opentelemetry-instrumentation-koa/.npmignore
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/.npmignore
rename to plugins/node/opentelemetry-instrumentation-koa/.npmignore
diff --git a/plugins/node/opentelemetry-koa-instrumentation/LICENSE b/plugins/node/opentelemetry-instrumentation-koa/LICENSE
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/LICENSE
rename to plugins/node/opentelemetry-instrumentation-koa/LICENSE
diff --git a/plugins/node/opentelemetry-koa-instrumentation/README.md b/plugins/node/opentelemetry-instrumentation-koa/README.md
similarity index 60%
rename from plugins/node/opentelemetry-koa-instrumentation/README.md
rename to plugins/node/opentelemetry-instrumentation-koa/README.md
index 64b13fec20..edf30a7309 100644
--- a/plugins/node/opentelemetry-koa-instrumentation/README.md
+++ b/plugins/node/opentelemetry-instrumentation-koa/README.md
@@ -12,7 +12,7 @@ For automatic instrumentation see the
## Installation
```bash
-npm install --save @opentelemetry/koa-instrumentation
+npm install --save @opentelemetry/instrumentation-koa
```
### Supported Versions
- Koa `^2.0.0`
@@ -21,33 +21,47 @@ npm install --save @opentelemetry/koa-instrumentation
OpenTelemetry Koa Instrumentation allows the user to automatically collect trace data and export them to their backend of choice, to give observability to distributed systems.
-To load a specific instrumentation (Koa in this case), specify it in the Node Tracer's configuration.
+To load all of the [default supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use the below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules.
+
```js
const { NodeTracerProvider } = require('@opentelemetry/node');
-
-const provider = new NodeTracerProvider({
- plugins: {
- koa: {
- enabled: true,
- // You may use a package name or absolute path to the file.
- path: '@opentelemetry/koa-instrumentation',
- }
- }
+const provider = new NodeTracerProvider();
+const { registerInstrumentations } = require('@opentelemetry/instrumentation');
+registerInstrumentations({
+ tracerProvider: provider,
});
```
-To load all of the [supported instrumentations](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each instrumentation is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing instrumentations for unused modules.
+If instead you would just want to load a specific instrumentation only (**koa** in this case);
+
```js
const { NodeTracerProvider } = require('@opentelemetry/node');
+const { KoaInstrumentation } = require('@opentelemetry/instrumentation-koa');
+const provider = new NodeTracerProvider();
+const koaInstrumentation = new KoaInstrumentation();
+koaInstrumentation.setTracerProvider(provider);
+```
+
+You can combine loading default plugins and KoaInstrumentation at the same time:
+```js
+const { NodeTracerProvider } = require('@opentelemetry/node');
+const { KoaInstrumentation } = require('@opentelemetry/instrumentation-koa');
+const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const provider = new NodeTracerProvider();
+registerInstrumentations({
+ instrumentations: [
+ new KoaInstrumentation(),
+ ],
+ tracerProvider: provider,
+});
```
See [examples/koa](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/examples/koa) for a short example using both Koa and @koa/router
## Koa Packages
-This package provides automatic tracing for middleware added using either the core [`Koa`](https://github.com/koajs/koa) package or the [`@koa/router`](https://github.com/koajs/router) package.
+This package provides automatic tracing for middleware added using either the core [`Koa`](https://github.com/koajs/koa) package or the [`@koa/router`](https://github.com/koajs/router) package.
## Useful links
- For more information on OpenTelemetry, visit:
@@ -62,7 +76,7 @@ Apache 2.0 - See [LICENSE][license-url] for more information.
[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-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/status.svg?path=plugins/node/opentelemetry-koa-instrumentation
-[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins/node/opentelemetry-koa-instrumentation
-[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib/dev-status.svg?path=plugins/node/opentelemetry-koa-instrumentation
-[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins/node/opentelemetry-koa-instrumentation&type=dev
+[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib/status.svg?path=plugins/node/opentelemetry-instrumentation-koa
+[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins/node/opentelemetry-instrumentation-koa
+[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib/dev-status.svg?path=plugins/node/opentelemetry-instrumentation-koa
+[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js-contrib?path=plugins/node/opentelemetry-instrumentation-koa&type=dev
diff --git a/plugins/node/opentelemetry-koa-instrumentation/package.json b/plugins/node/opentelemetry-instrumentation-koa/package.json
similarity index 92%
rename from plugins/node/opentelemetry-koa-instrumentation/package.json
rename to plugins/node/opentelemetry-instrumentation-koa/package.json
index c0364e0299..d15676277e 100644
--- a/plugins/node/opentelemetry-koa-instrumentation/package.json
+++ b/plugins/node/opentelemetry-instrumentation-koa/package.json
@@ -1,5 +1,5 @@
{
- "name": "@opentelemetry/koa-instrumentation",
+ "name": "@opentelemetry/instrumentation-koa",
"version": "0.13.1",
"description": "OpenTelemetry Koa automatic instrumentation package.",
"main": "build/src/index.js",
@@ -51,7 +51,6 @@
"@types/koa__router": "8.0.2",
"@types/mocha": "7.0.2",
"@types/node": "12.12.47",
- "@types/shimmer": "1.0.1",
"codecov": "3.7.1",
"gts": "3.1.0",
"koa": "2.13.0",
@@ -67,7 +66,7 @@
"dependencies": {
"@opentelemetry/api": "^0.15.0",
"@opentelemetry/core": "^0.15.0",
- "@opentelemetry/semantic-conventions": "^0.15.0",
- "shimmer": "^1.2.1"
+ "@opentelemetry/instrumentation": "^0.15.0",
+ "@opentelemetry/semantic-conventions": "^0.15.0"
}
}
diff --git a/plugins/node/opentelemetry-koa-instrumentation/src/index.ts b/plugins/node/opentelemetry-instrumentation-koa/src/index.ts
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/src/index.ts
rename to plugins/node/opentelemetry-instrumentation-koa/src/index.ts
diff --git a/plugins/node/opentelemetry-koa-instrumentation/src/koa.ts b/plugins/node/opentelemetry-instrumentation-koa/src/koa.ts
similarity index 78%
rename from plugins/node/opentelemetry-koa-instrumentation/src/koa.ts
rename to plugins/node/opentelemetry-instrumentation-koa/src/koa.ts
index a90c3dfa84..47c9038e09 100644
--- a/plugins/node/opentelemetry-koa-instrumentation/src/koa.ts
+++ b/plugins/node/opentelemetry-instrumentation-koa/src/koa.ts
@@ -15,9 +15,14 @@
*/
import * as api from '@opentelemetry/api';
-import { BasePlugin } from '@opentelemetry/core';
+import {
+ isWrapped,
+ InstrumentationBase,
+ InstrumentationConfig,
+ InstrumentationNodeModuleDefinition,
+} from '@opentelemetry/instrumentation';
+
import type * as koa from 'koa';
-import * as shimmer from 'shimmer';
import {
KoaMiddleware,
KoaContext,
@@ -28,34 +33,35 @@ import { VERSION } from './version';
import { getMiddlewareMetadata } from './utils';
/** Koa instrumentation for OpenTelemetry */
-export class KoaInstrumentation extends BasePlugin {
+export class KoaInstrumentation extends InstrumentationBase {
static readonly component = KoaComponentName;
- readonly supportedVersions = ['^2.0.0'];
-
- constructor(readonly moduleName: string) {
- super('@opentelemetry/koa-instrumentation', VERSION);
- }
-
- /**
- * Patches Koa operations by wrapping the Koa.use function
- */
- protected patch(): typeof koa {
- this._logger.debug('Patching Koa');
- if (this._moduleExports == null) {
- return this._moduleExports;
- }
- this._logger.debug('Patching Koa.use');
- shimmer.wrap(this._moduleExports.prototype, 'use', this._getKoaUsePatch);
-
- return this._moduleExports;
+ constructor(config?: InstrumentationConfig) {
+ super('@opentelemetry/instrumentation-koa', VERSION, config);
}
-
- /**
- * Unpatches all Koa operations
- */
- protected unpatch(): void {
- this._logger.debug('Unpatching Koa');
- shimmer.unwrap(this._moduleExports.prototype, 'use');
+ protected init() {
+ return new InstrumentationNodeModuleDefinition(
+ 'koa',
+ ['^2.0.0'],
+ moduleExports => {
+ if (moduleExports == null) {
+ return moduleExports;
+ }
+ if (isWrapped(moduleExports.prototype.use)) {
+ this._unwrap(moduleExports.prototype, 'use');
+ }
+ this._wrap(
+ moduleExports.prototype,
+ 'use',
+ this._getKoaUsePatch.bind(this)
+ );
+ return moduleExports;
+ },
+ moduleExports => {
+ if (isWrapped(moduleExports.prototype.use)) {
+ this._unwrap(moduleExports.prototype, 'use');
+ }
+ }
+ );
}
/**
@@ -64,6 +70,7 @@ export class KoaInstrumentation extends BasePlugin {
* @param {KoaMiddleware} middleware - the original middleware function
*/
private _getKoaUsePatch(original: (middleware: KoaMiddleware) => koa) {
+ const plugin = this;
return function use(this: koa, middlewareFunction: KoaMiddleware) {
let patchedFunction: KoaMiddleware;
if (middlewareFunction.router) {
@@ -127,7 +134,7 @@ export class KoaInstrumentation extends BasePlugin {
isRouter,
layerPath
);
- const span = this._tracer.startSpan(metadata.name, {
+ const span = this.tracer.startSpan(metadata.name, {
attributes: metadata.attributes,
});
@@ -147,5 +154,3 @@ export class KoaInstrumentation extends BasePlugin {
};
}
}
-
-export const plugin = new KoaInstrumentation(KoaComponentName);
diff --git a/plugins/node/opentelemetry-koa-instrumentation/src/types.ts b/plugins/node/opentelemetry-instrumentation-koa/src/types.ts
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/src/types.ts
rename to plugins/node/opentelemetry-instrumentation-koa/src/types.ts
diff --git a/plugins/node/opentelemetry-koa-instrumentation/src/utils.ts b/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/src/utils.ts
rename to plugins/node/opentelemetry-instrumentation-koa/src/utils.ts
diff --git a/plugins/node/opentelemetry-koa-instrumentation/src/version.ts b/plugins/node/opentelemetry-instrumentation-koa/src/version.ts
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/src/version.ts
rename to plugins/node/opentelemetry-instrumentation-koa/src/version.ts
diff --git a/plugins/node/opentelemetry-koa-instrumentation/test/koa.test.ts b/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts
similarity index 64%
rename from plugins/node/opentelemetry-koa-instrumentation/test/koa.test.ts
rename to plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts
index 30eadc3c99..ba7db72aff 100644
--- a/plugins/node/opentelemetry-koa-instrumentation/test/koa.test.ts
+++ b/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-import { context, setSpan, NoopLogger } from '@opentelemetry/api';
+import * as KoaRouter from '@koa/router';
+import { context, setSpan } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/node';
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
import {
@@ -24,12 +25,16 @@ import {
import {
ExceptionAttribute,
ExceptionEventName,
+ HttpAttribute,
} from '@opentelemetry/semantic-conventions';
+
+import { KoaInstrumentation } from '../src';
+const plugin = new KoaInstrumentation();
+
import * as assert from 'assert';
import * as koa from 'koa';
import * as http from 'http';
import { AddressInfo } from 'net';
-import { plugin } from '../src';
import { AttributeNames, KoaLayerType } from '../src/types';
const httpRequest = {
@@ -51,12 +56,12 @@ const httpRequest = {
},
};
-describe('Koa Instrumentation - Core Tests', () => {
- const logger = new NoopLogger();
+describe('Koa Instrumentation', () => {
const provider = new NodeTracerProvider();
const memoryExporter = new InMemorySpanExporter();
const spanProcessor = new SimpleSpanProcessor(memoryExporter);
provider.addSpanProcessor(spanProcessor);
+ plugin.setTracerProvider(provider);
const tracer = provider.getTracer('default');
let contextManager: AsyncHooksContextManager;
let app: koa;
@@ -64,7 +69,11 @@ describe('Koa Instrumentation - Core Tests', () => {
let port: number;
before(() => {
- plugin.enable(koa, provider, logger);
+ plugin.enable();
+ });
+
+ after(() => {
+ plugin.disable();
});
beforeEach(async () => {
@@ -113,6 +122,130 @@ describe('Koa Instrumentation - Core Tests', () => {
throw new Error('I failed!');
};
+ describe('Instrumenting @koa/router calls', () => {
+ it('should create a child span for middlewares', async () => {
+ const rootSpan = tracer.startSpan('rootSpan');
+ app.use((ctx, next) =>
+ context.with(setSpan(context.active(), rootSpan), next)
+ );
+
+ const router = new KoaRouter();
+ router.get('/post/:id', ctx => {
+ ctx.body = `Post id: ${ctx.params.id}`;
+ });
+
+ app.use(router.routes());
+
+ await context.with(setSpan(context.active(), rootSpan), async () => {
+ await httpRequest.get(`http://localhost:${port}/post/0`);
+ rootSpan.end();
+
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
+ const requestHandlerSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name.includes('router - /post/:id'));
+ assert.notStrictEqual(requestHandlerSpan, undefined);
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
+ KoaLayerType.ROUTER
+ );
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
+ '/post/:id'
+ );
+
+ const exportedRootSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name === 'rootSpan');
+ assert.notStrictEqual(exportedRootSpan, undefined);
+ });
+ });
+
+ it('should correctly instrument nested routers', async () => {
+ const rootSpan = tracer.startSpan('rootSpan');
+ app.use((ctx, next) =>
+ context.with(setSpan(context.active(), rootSpan), next)
+ );
+
+ const router = new KoaRouter();
+ const nestedRouter = new KoaRouter();
+ nestedRouter.get('/post/:id', ctx => {
+ ctx.body = `Post id: ${ctx.params.id}`;
+ });
+
+ router.use('/:first', nestedRouter.routes());
+ app.use(router.routes());
+
+ await context.with(setSpan(context.active(), rootSpan), async () => {
+ await httpRequest.get(`http://localhost:${port}/test/post/0`);
+ rootSpan.end();
+
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
+ const requestHandlerSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name.includes('router - /:first/post/:id'));
+ assert.notStrictEqual(requestHandlerSpan, undefined);
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
+ KoaLayerType.ROUTER
+ );
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
+ '/:first/post/:id'
+ );
+
+ const exportedRootSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name === 'rootSpan');
+ assert.notStrictEqual(exportedRootSpan, undefined);
+ });
+ });
+
+ it('should correctly instrument prefixed routers', async () => {
+ const rootSpan = tracer.startSpan('rootSpan');
+ app.use((ctx, next) =>
+ context.with(setSpan(context.active(), rootSpan), next)
+ );
+
+ const router = new KoaRouter();
+ router.get('/post/:id', ctx => {
+ ctx.body = `Post id: ${ctx.params.id}`;
+ });
+ router.prefix('/:first');
+ app.use(router.routes());
+
+ await context.with(setSpan(context.active(), rootSpan), async () => {
+ await httpRequest.get(`http://localhost:${port}/test/post/0`);
+ rootSpan.end();
+
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
+ const requestHandlerSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name.includes('router - /:first/post/:id'));
+ assert.notStrictEqual(requestHandlerSpan, undefined);
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
+ KoaLayerType.ROUTER
+ );
+
+ assert.strictEqual(
+ requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
+ '/:first/post/:id'
+ );
+
+ const exportedRootSpan = memoryExporter
+ .getFinishedSpans()
+ .find(span => span.name === 'rootSpan');
+ assert.notStrictEqual(exportedRootSpan, undefined);
+ });
+ });
+ });
+
describe('Instrumenting core middleware calls', () => {
it('should create a child span for middlewares', async () => {
const rootSpan = tracer.startSpan('rootSpan');
@@ -126,7 +259,7 @@ describe('Koa Instrumentation - Core Tests', () => {
await context.with(setSpan(context.active(), rootSpan), async () => {
await httpRequest.get(`http://localhost:${port}`);
rootSpan.end();
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 8);
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 5);
assert.notStrictEqual(
memoryExporter
@@ -187,7 +320,7 @@ describe('Koa Instrumentation - Core Tests', () => {
await context.with(setSpan(context.active(), rootSpan), async () => {
await httpRequest.get(`http://localhost:${port}`);
rootSpan.end();
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 3);
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
const requestHandlerSpan = memoryExporter
.getFinishedSpans()
@@ -215,7 +348,7 @@ describe('Koa Instrumentation - Core Tests', () => {
assert.deepStrictEqual(res, 'Internal Server Error');
rootSpan.end();
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 3);
+ assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
const requestHandlerSpan = memoryExporter
.getFinishedSpans()
diff --git a/plugins/node/opentelemetry-koa-instrumentation/tsconfig.json b/plugins/node/opentelemetry-instrumentation-koa/tsconfig.json
similarity index 100%
rename from plugins/node/opentelemetry-koa-instrumentation/tsconfig.json
rename to plugins/node/opentelemetry-instrumentation-koa/tsconfig.json
diff --git a/plugins/node/opentelemetry-koa-instrumentation/test/koa-router.test.ts b/plugins/node/opentelemetry-koa-instrumentation/test/koa-router.test.ts
deleted file mode 100644
index d748522119..0000000000
--- a/plugins/node/opentelemetry-koa-instrumentation/test/koa-router.test.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { context, setSpan, NoopLogger } from '@opentelemetry/api';
-import { NodeTracerProvider } from '@opentelemetry/node';
-import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
-import {
- InMemorySpanExporter,
- SimpleSpanProcessor,
-} from '@opentelemetry/tracing';
-import * as assert from 'assert';
-import * as koa from 'koa';
-import * as KoaRouter from '@koa/router';
-import * as http from 'http';
-import { AddressInfo } from 'net';
-import { plugin } from '../src';
-import { AttributeNames, KoaLayerType } from '../src/types';
-import { HttpAttribute } from '@opentelemetry/semantic-conventions';
-
-const httpRequest = {
- get: (options: http.ClientRequestArgs | string) => {
- return new Promise((resolve, reject) => {
- return http.get(options, resp => {
- let data = '';
- resp.on('data', chunk => {
- data += chunk;
- });
- resp.on('end', () => {
- resolve(data);
- });
- resp.on('error', err => {
- reject(err);
- });
- });
- });
- },
-};
-
-describe('Koa Instrumentation - Router Tests', () => {
- const logger = new NoopLogger();
- const provider = new NodeTracerProvider();
- const memoryExporter = new InMemorySpanExporter();
- const spanProcessor = new SimpleSpanProcessor(memoryExporter);
- provider.addSpanProcessor(spanProcessor);
- const tracer = provider.getTracer('default');
- let contextManager: AsyncHooksContextManager;
- let app: koa;
- let server: http.Server;
- let port: number;
-
- before(() => {
- plugin.enable(koa, provider, logger);
- });
-
- beforeEach(async () => {
- contextManager = new AsyncHooksContextManager();
- context.setGlobalContextManager(contextManager.enable());
-
- app = new koa();
- server = http.createServer(app.callback());
- await new Promise(resolve => server.listen(0, resolve));
- port = (server.address() as AddressInfo).port;
- assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);
- });
-
- afterEach(() => {
- memoryExporter.reset();
- context.disable();
- server.close();
- });
-
- describe('Instrumenting @koa/router calls', () => {
- it('should create a child span for middlewares', async () => {
- const rootSpan = tracer.startSpan('rootSpan');
- app.use((ctx, next) =>
- context.with(setSpan(context.active(), rootSpan), next)
- );
-
- const router = new KoaRouter();
- router.get('/post/:id', ctx => {
- ctx.body = `Post id: ${ctx.params.id}`;
- });
-
- app.use(router.routes());
-
- await context.with(setSpan(context.active(), rootSpan), async () => {
- await httpRequest.get(`http://localhost:${port}/post/0`);
- rootSpan.end();
-
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
- const requestHandlerSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name.includes('router - /post/:id'));
- assert.notStrictEqual(requestHandlerSpan, undefined);
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
- KoaLayerType.ROUTER
- );
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
- '/post/:id'
- );
-
- const exportedRootSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name === 'rootSpan');
- assert.notStrictEqual(exportedRootSpan, undefined);
- });
- });
-
- it('should correctly instrument nested routers', async () => {
- const rootSpan = tracer.startSpan('rootSpan');
- app.use((ctx, next) =>
- context.with(setSpan(context.active(), rootSpan), next)
- );
-
- const router = new KoaRouter();
- const nestedRouter = new KoaRouter();
- nestedRouter.get('/post/:id', ctx => {
- ctx.body = `Post id: ${ctx.params.id}`;
- });
-
- router.use('/:first', nestedRouter.routes());
- app.use(router.routes());
-
- await context.with(setSpan(context.active(), rootSpan), async () => {
- await httpRequest.get(`http://localhost:${port}/test/post/0`);
- rootSpan.end();
-
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
- const requestHandlerSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name.includes('router - /:first/post/:id'));
- assert.notStrictEqual(requestHandlerSpan, undefined);
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
- KoaLayerType.ROUTER
- );
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
- '/:first/post/:id'
- );
-
- const exportedRootSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name === 'rootSpan');
- assert.notStrictEqual(exportedRootSpan, undefined);
- });
- });
-
- it('should correctly instrument prefixed routers', async () => {
- const rootSpan = tracer.startSpan('rootSpan');
- app.use((ctx, next) =>
- context.with(setSpan(context.active(), rootSpan), next)
- );
-
- const router = new KoaRouter();
- router.get('/post/:id', ctx => {
- ctx.body = `Post id: ${ctx.params.id}`;
- });
- router.prefix('/:first');
- app.use(router.routes());
-
- await context.with(setSpan(context.active(), rootSpan), async () => {
- await httpRequest.get(`http://localhost:${port}/test/post/0`);
- rootSpan.end();
-
- assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2);
- const requestHandlerSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name.includes('router - /:first/post/:id'));
- assert.notStrictEqual(requestHandlerSpan, undefined);
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE],
- KoaLayerType.ROUTER
- );
-
- assert.strictEqual(
- requestHandlerSpan?.attributes[HttpAttribute.HTTP_ROUTE],
- '/:first/post/:id'
- );
-
- const exportedRootSpan = memoryExporter
- .getFinishedSpans()
- .find(span => span.name === 'rootSpan');
- assert.notStrictEqual(exportedRootSpan, undefined);
- });
- });
- });
-});