From 572ed665ea4ac93082c347f7179d67e9a8fe19b8 Mon Sep 17 00:00:00 2001 From: Agustin Daguerre Date: Fri, 19 Nov 2021 08:15:23 -0300 Subject: [PATCH] feat(koa): add a config option to allow layers to be ignored by type (#646) * feat(koa): Adds config option to allow selected layers to be ignored * Fixes linting errors --- .../README.md | 11 ++++ .../src/instrumentation.ts | 14 +++-- .../src/types.ts | 9 +++ .../src/utils.ts | 23 ++++++- .../test/utils.test.ts | 61 +++++++++++++++++++ 5 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-koa/test/utils.test.ts diff --git a/plugins/node/opentelemetry-instrumentation-koa/README.md b/plugins/node/opentelemetry-instrumentation-koa/README.md index 630901fccf..1037d8bbf9 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/README.md +++ b/plugins/node/opentelemetry-instrumentation-koa/README.md @@ -43,6 +43,17 @@ registerInstrumentations({ 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 Instrumentation Options + +| Options | Type | Example | Description | +| ------- | ---- | ------- | ----------- | +| `ignoreLayersType`| `KoaLayerType[]` | `['middleware']` | Ignore layers of specified type. | + +`ignoreLayersType` accepts an array of `KoaLayerType` which can take the following string values: + +- `router`, +- `middleware`. + ## 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. diff --git a/plugins/node/opentelemetry-instrumentation-koa/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-koa/src/instrumentation.ts index f4cc15beda..ac2028f6c1 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-koa/src/instrumentation.ts @@ -18,7 +18,6 @@ import * as api from '@opentelemetry/api'; import { isWrapped, InstrumentationBase, - InstrumentationConfig, InstrumentationNodeModuleDefinition, } from '@opentelemetry/instrumentation'; @@ -29,16 +28,17 @@ import { KoaComponentName, kLayerPatched, KoaLayerType, + KoaInstrumentationConfig, } from './types'; import { AttributeNames } from './enums/AttributeNames'; import { VERSION } from './version'; -import { getMiddlewareMetadata } from './utils'; +import { getMiddlewareMetadata, isLayerIgnored } from './utils'; import { getRPCMetadata, RPCType, setRPCMetadata } from '@opentelemetry/core'; /** Koa instrumentation for OpenTelemetry */ export class KoaInstrumentation extends InstrumentationBase { static readonly component = KoaComponentName; - constructor(config?: InstrumentationConfig) { + constructor(config?: KoaInstrumentationConfig) { super('@opentelemetry/instrumentation-koa', VERSION, config); } protected init() { @@ -126,7 +126,13 @@ export class KoaInstrumentation extends InstrumentationBase { isRouter: boolean, layerPath?: string ): KoaMiddleware { - if (middlewareLayer[kLayerPatched] === true) return middlewareLayer; + const layerType = isRouter ? KoaLayerType.ROUTER : KoaLayerType.MIDDLEWARE; + // Skip patching layer if its ignored in the config + if ( + middlewareLayer[kLayerPatched] === true || + isLayerIgnored(layerType, this._config) + ) + return middlewareLayer; middlewareLayer[kLayerPatched] = true; api.diag.debug('patching Koa middleware layer'); return async (context: KoaContext, next: koa.Next) => { diff --git a/plugins/node/opentelemetry-instrumentation-koa/src/types.ts b/plugins/node/opentelemetry-instrumentation-koa/src/types.ts index 6485be8ee8..1d65ebcdda 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-koa/src/types.ts @@ -16,6 +16,7 @@ import type { Middleware, ParameterizedContext, DefaultState } from 'koa'; import type { RouterParamContext } from '@koa/router'; import type * as Router from '@koa/router'; +import { InstrumentationConfig } from '@opentelemetry/instrumentation'; /** * This symbol is used to mark a Koa layer as being already instrumented @@ -30,6 +31,14 @@ export type KoaMiddleware = Middleware & { export type KoaContext = ParameterizedContext; +/** + * Options available for the Koa Instrumentation (see [documentation](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-Instrumentation-koa#koa-Instrumentation-options)) + */ +export interface KoaInstrumentationConfig extends InstrumentationConfig { + /** Ignore specific layers based on their type */ + ignoreLayersType?: KoaLayerType[]; +} + export enum KoaLayerType { ROUTER = 'router', MIDDLEWARE = 'middleware', diff --git a/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts b/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts index a58dc91fd2..2061392e3e 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { KoaContext, KoaMiddleware, KoaLayerType } from './types'; +import { + KoaContext, + KoaMiddleware, + KoaLayerType, + KoaInstrumentationConfig, +} from './types'; import { AttributeNames } from './enums/AttributeNames'; import { SpanAttributes } from '@opentelemetry/api'; import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; @@ -46,3 +51,19 @@ export const getMiddlewareMetadata = ( }; } }; + +/** + * Check whether the given request is ignored by configuration + * @param [list] List of ignore patterns + * @param [onException] callback for doing something when an exception has + * occurred + */ +export const isLayerIgnored = ( + type: KoaLayerType, + config?: KoaInstrumentationConfig +): boolean => { + return !!( + Array.isArray(config?.ignoreLayersType) && + config?.ignoreLayersType?.includes(type) + ); +}; diff --git a/plugins/node/opentelemetry-instrumentation-koa/test/utils.test.ts b/plugins/node/opentelemetry-instrumentation-koa/test/utils.test.ts new file mode 100644 index 0000000000..b9a1ab4160 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-koa/test/utils.test.ts @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as utils from '../src/utils'; +import * as assert from 'assert'; +import { KoaInstrumentationConfig, KoaLayerType } from '../src/types'; + +describe('Utils', () => { + describe('isLayerIgnored()', () => { + it('should not fail with invalid config', () => { + assert.strictEqual(utils.isLayerIgnored(KoaLayerType.MIDDLEWARE), false); + assert.strictEqual( + utils.isLayerIgnored( + KoaLayerType.MIDDLEWARE, + {} as KoaInstrumentationConfig + ), + false + ); + assert.strictEqual( + utils.isLayerIgnored(KoaLayerType.MIDDLEWARE, { + ignoreLayersType: {}, + } as KoaInstrumentationConfig), + false + ); + assert.strictEqual( + utils.isLayerIgnored(KoaLayerType.ROUTER, { + ignoreLayersType: {}, + } as KoaInstrumentationConfig), + false + ); + }); + + it('should ignore based on type', () => { + assert.strictEqual( + utils.isLayerIgnored(KoaLayerType.MIDDLEWARE, { + ignoreLayersType: [KoaLayerType.MIDDLEWARE], + }), + true + ); + assert.strictEqual( + utils.isLayerIgnored(KoaLayerType.ROUTER, { + ignoreLayersType: [KoaLayerType.MIDDLEWARE], + }), + false + ); + }); + }); +});