-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathkoa.ts
124 lines (112 loc) · 3.57 KB
/
koa.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa';
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
import {
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
captureException,
defineIntegration,
getDefaultIsolationScope,
getIsolationScope,
spanToJSON,
} from '@sentry/core';
import type { IntegrationFn, Span } from '@sentry/types';
import { logger } from '@sentry/utils';
import { DEBUG_BUILD } from '../../debug-build';
import { generateInstrumentOnce } from '../../otel/instrument';
import { ensureIsWrapped } from '../../utils/ensureIsWrapped';
const INTEGRATION_NAME = 'Koa';
export const instrumentKoa = generateInstrumentOnce(
INTEGRATION_NAME,
() =>
new KoaInstrumentation({
requestHook(span, info) {
addKoaSpanAttributes(span);
if (getIsolationScope() === getDefaultIsolationScope()) {
DEBUG_BUILD && logger.warn('Isolation scope is default isolation scope - skipping setting transactionName');
return;
}
const attributes = spanToJSON(span).data;
const route = attributes && attributes[ATTR_HTTP_ROUTE];
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const method: string = info?.context?.request?.method?.toUpperCase() || 'GET';
if (route) {
getIsolationScope().setTransactionName(`${method} ${route}`);
}
},
}),
);
const _koaIntegration = (() => {
return {
name: INTEGRATION_NAME,
setupOnce() {
instrumentKoa();
},
};
}) satisfies IntegrationFn;
/**
* Adds Sentry tracing instrumentation for [Koa](https://koajs.com/).
*
* If you also want to capture errors, you need to call `setupKoaErrorHandler(app)` after you set up your Koa server.
*
* For more information, see the [koa documentation](https://docs.sentry.io/platforms/javascript/guides/koa/).
*
* @example
* ```javascript
* const Sentry = require('@sentry/node');
*
* Sentry.init({
* integrations: [Sentry.koaIntegration()],
* })
* ```
*/
export const koaIntegration = defineIntegration(_koaIntegration);
/**
* Add an Koa error handler to capture errors to Sentry.
*
* The error handler must be before any other middleware and after all controllers.
*
* @param app The Express instances
* @param options {ExpressHandlerOptions} Configuration options for the handler
*
* @example
* ```javascript
* const Sentry = require('@sentry/node');
* const Koa = require("koa");
*
* const app = new Koa();
*
* Sentry.setupKoaErrorHandler(app);
*
* // Add your routes, etc.
*
* app.listen(3000);
* ```
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const setupKoaErrorHandler = (app: { use: (arg0: (ctx: any, next: any) => Promise<void>) => void }): void => {
app.use(async (ctx, next) => {
try {
await next();
} catch (error) {
captureException(error);
throw error;
}
});
ensureIsWrapped(app.use, 'koa');
};
function addKoaSpanAttributes(span: Span): void {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.http.otel.koa');
const attributes = spanToJSON(span).data || {};
// this is one of: middleware, router
const type = attributes['koa.type'];
if (type) {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, `${type}.koa`);
}
// Also update the name
const name = attributes['koa.name'];
if (typeof name === 'string') {
// Somehow, name is sometimes `''` for middleware spans
// See: https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2220
span.updateName(name || '< unknown >');
}
}