Skip to content

Commit

Permalink
fix(koa)!: use generic config hook types and move dep to dev (#2303)
Browse files Browse the repository at this point in the history
* fix!(instrumentation-koa): use feneric config hook types and move dep to dev

* chore: lint fix

---------

Co-authored-by: Marc Pichler <marc.pichler@dynatrace.com>
  • Loading branch information
blumamir and pichlermarc authored Jun 27, 2024
1 parent 16bff40 commit d9d558f
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 61 deletions.
98 changes: 67 additions & 31 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions plugins/node/opentelemetry-instrumentation-koa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,18 @@ Note that generator-based middleware are deprecated and won't be instrumented.

Instrumentation configuration accepts a custom "hook" function which will be called for every instrumented Koa middleware layer involved in a request. Custom attributes can be set on the span or run any custom logic per layer.

```javascript
NOTE: `KoaRequestInfo.context` and `KoaRequestInfo.middlewareLayer` are typed as `any`. If you want type support make sure you have `@types/koa` and `@types/koa__router` installed then you can use the following type definitions:

```typescript
import { KoaInstrumentation } from "@opentelemetry/instrumentation-koa"
import type { Middleware, ParameterizedContext, DefaultState } from 'koa';
import type { RouterParamContext } from '@koa/router';

type KoaContext = ParameterizedContext<DefaultState, RouterParamContext>;
type KoaMiddleware = Middleware<DefaultState, KoaContext>;

const koaInstrumentation = new KoaInstrumentation({
requestHook: function (span: Span, info: KoaRequestInfo) {
requestHook: function (span: Span, info: KoaRequestInfo<KoaContext, KoaMiddleware>) {
span.setAttribute(
'http.method',
info.context.request.method
Expand Down
6 changes: 3 additions & 3 deletions plugins/node/opentelemetry-instrumentation-koa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
"@opentelemetry/instrumentation-http": "^0.52.0",
"@opentelemetry/sdk-trace-base": "^1.8.0",
"@opentelemetry/sdk-trace-node": "^1.8.0",
"@types/koa": "2.15.0",
"@types/koa__router": "12.0.4",
"@types/mocha": "7.0.2",
"@types/node": "18.6.5",
"@types/sinon": "10.0.18",
Expand All @@ -68,9 +70,7 @@
"dependencies": {
"@opentelemetry/core": "^1.8.0",
"@opentelemetry/instrumentation": "^0.52.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
"@types/koa": "2.14.0",
"@types/koa__router": "12.0.3"
"@opentelemetry/semantic-conventions": "^1.22.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-koa#readme"
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import {
} from '@opentelemetry/instrumentation';

import type * as koa from 'koa';
import { KoaContext, KoaLayerType, KoaInstrumentationConfig } from './types';
import { KoaLayerType, KoaInstrumentationConfig } from './types';
import { PACKAGE_NAME, PACKAGE_VERSION } from './version';
import { getMiddlewareMetadata, isLayerIgnored } from './utils';
import { getRPCMetadata, RPCType } from '@opentelemetry/core';
import {
kLayerPatched,
KoaContext,
KoaMiddleware,
KoaPatchedMiddleware,
} from './internal-types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Middleware, DefaultState } from 'koa';
import { KoaContext } from './types';
import type { Middleware, ParameterizedContext, DefaultState } from 'koa';
import type * as Router from '@koa/router';

export type KoaContext = ParameterizedContext<
DefaultState,
Router.RouterParamContext
>;
export type KoaMiddleware = Middleware<DefaultState, KoaContext> & {
router?: Router;
};
Expand Down
48 changes: 37 additions & 11 deletions plugins/node/opentelemetry-instrumentation-koa/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Middleware, ParameterizedContext, DefaultState } from 'koa';
import type { RouterParamContext } from '@koa/router';
import { Span } from '@opentelemetry/api';
import { InstrumentationConfig } from '@opentelemetry/instrumentation';

Expand All @@ -23,11 +21,30 @@ export enum KoaLayerType {
MIDDLEWARE = 'middleware',
}

export type KoaContext = ParameterizedContext<DefaultState, RouterParamContext>;

export type KoaRequestInfo = {
context: KoaContext;
middlewareLayer: Middleware<DefaultState, KoaContext>;
/**
* Information about the current Koa middleware layer
* The middleware layer type is any by default.
* One can install koa types packages `@types/koa` and `@types/koa__router`
* with compatible versions to the koa version used in the project
* to get more specific types for the middleware layer property.
*
* Example use in a custom attribute function:
* ```ts
* import type { Middleware, ParameterizedContext, DefaultState } from 'koa';
* import type { RouterParamContext } from '@koa/router';
*
* type KoaContext = ParameterizedContext<DefaultState, RouterParamContext>;
* type KoaMiddleware = Middleware<DefaultState, KoaContext>;
*
* const koaConfig: KoaInstrumentationConfig<KoaContext, KoaMiddleware> = {
* requestHook: (span: Span, info: KoaRequestInfo<KoaContext, KoaMiddleware>) => {
* // custom typescript code that can access the typed into.middlewareLayer and info.context
* }
*
*/
export type KoaRequestInfo<KoaContextType = any, KoaMiddlewareType = any> = {
context: KoaContextType;
middlewareLayer: KoaMiddlewareType;
layerType: KoaLayerType;
};

Expand All @@ -36,16 +53,25 @@ export type KoaRequestInfo = {
* @param span - The Express middleware layer span.
* @param context - The current KoaContext.
*/
export interface KoaRequestCustomAttributeFunction {
(span: Span, info: KoaRequestInfo): void;
export interface KoaRequestCustomAttributeFunction<
KoaContextType = any,
KoaMiddlewareType = any
> {
(span: Span, info: KoaRequestInfo<KoaContextType, KoaMiddlewareType>): void;
}

/**
* 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 {
export interface KoaInstrumentationConfig<
KoaContextType = any,
KoaMiddlewareType = any
> extends InstrumentationConfig {
/** Ignore specific layers based on their type */
ignoreLayersType?: KoaLayerType[];
/** Function for adding custom attributes to each middleware layer span */
requestHook?: KoaRequestCustomAttributeFunction;
requestHook?: KoaRequestCustomAttributeFunction<
KoaContextType,
KoaMiddlewareType
>;
}
4 changes: 2 additions & 2 deletions plugins/node/opentelemetry-instrumentation-koa/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { KoaContext, KoaLayerType, KoaInstrumentationConfig } from './types';
import { KoaMiddleware } from './internal-types';
import { KoaLayerType, KoaInstrumentationConfig } from './types';
import { KoaContext, KoaMiddleware } from './internal-types';
import { AttributeNames } from './enums/AttributeNames';
import { Attributes } from '@opentelemetry/api';
import { SEMATTRS_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
Expand Down
27 changes: 18 additions & 9 deletions plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

import type { Middleware, ParameterizedContext, DefaultState } from 'koa';
import type { RouterParamContext } from '@koa/router';
import * as KoaRouter from '@koa/router';
import { context, trace, Span, SpanKind } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
Expand All @@ -29,6 +31,9 @@ import {
SEMATTRS_HTTP_ROUTE,
} from '@opentelemetry/semantic-conventions';

type KoaContext = ParameterizedContext<DefaultState, RouterParamContext>;
type KoaMiddleware = Middleware<DefaultState, KoaContext>;

import { KoaInstrumentation } from '../src';
const plugin = new KoaInstrumentation();

Expand Down Expand Up @@ -594,11 +599,13 @@ describe('Koa Instrumentation', () => {
)
);

const requestHook = sinon.spy((span: Span, info: KoaRequestInfo) => {
span.setAttribute(SEMATTRS_HTTP_METHOD, info.context.request.method);
const requestHook = sinon.spy(
(span: Span, info: KoaRequestInfo<KoaContext, KoaMiddleware>) => {
span.setAttribute(SEMATTRS_HTTP_METHOD, info.context.request.method);

throw Error('error thrown in requestHook');
});
throw Error('error thrown in requestHook');
}
);

plugin.setConfig({
requestHook,
Expand Down Expand Up @@ -645,11 +652,13 @@ describe('Koa Instrumentation', () => {
)
);

const requestHook = sinon.spy((span: Span, info: KoaRequestInfo) => {
span.setAttribute('http.method', info.context.request.method);
span.setAttribute('app.env', info.context.app.env);
span.setAttribute('koa.layer', info.layerType);
});
const requestHook = sinon.spy(
(span: Span, info: KoaRequestInfo<KoaContext, KoaMiddleware>) => {
span.setAttribute('http.method', info.context.request.method);
span.setAttribute('app.env', info.context.app.env);
span.setAttribute('koa.layer', info.layerType);
}
);

plugin.setConfig({
requestHook,
Expand Down

0 comments on commit d9d558f

Please sign in to comment.