Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(koa)!: use generic config hook types and move dep to dev #2303

Merged
merged 3 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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