-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathhelpers.ts
96 lines (87 loc) · 2.98 KB
/
helpers.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
import type { Span } from '@sentry/core';
import {
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
addNonEnumerableProperty,
withActiveSpan,
} from '@sentry/core';
import type { CatchTarget, InjectableTarget, NextFunction, Observable, Subscription } from './types';
const sentryPatched = 'sentryPatched';
/**
* Helper checking if a concrete target class is already patched.
*
* We already guard duplicate patching with isWrapped. However, isWrapped checks whether a file has been patched, whereas we use this check for concrete target classes.
* This check might not be necessary, but better to play it safe.
*/
export function isPatched(target: InjectableTarget | CatchTarget): boolean {
if (target.sentryPatched) {
return true;
}
addNonEnumerableProperty(target, sentryPatched, true);
return false;
}
/**
* Returns span options for nest middleware spans.
*/
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function getMiddlewareSpanOptions(target: InjectableTarget | CatchTarget, name: string | undefined = undefined) {
const span_name = name ?? target.name; // fallback to class name if no name is provided
return {
name: span_name,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.nestjs',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.middleware.nestjs',
},
};
}
/**
* Returns span options for nest event spans.
*/
export function getEventSpanOptions(event: string): {
name: string;
attributes: Record<string, string>;
forceTransaction: boolean;
} {
return {
name: `event ${event}`,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'event.nestjs',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.event.nestjs',
},
forceTransaction: true,
};
}
/**
* Adds instrumentation to a js observable and attaches the span to an active parent span.
*/
export function instrumentObservable(observable: Observable<unknown>, activeSpan: Span | undefined): void {
if (activeSpan) {
// eslint-disable-next-line @typescript-eslint/unbound-method
observable.subscribe = new Proxy(observable.subscribe, {
apply: (originalSubscribe, thisArgSubscribe, argsSubscribe) => {
return withActiveSpan(activeSpan, () => {
const subscription: Subscription = originalSubscribe.apply(thisArgSubscribe, argsSubscribe);
subscription.add(() => activeSpan.end());
return subscription;
});
},
});
}
}
/**
* Proxies the next() call in a nestjs middleware to end the span when it is called.
*/
export function getNextProxy(next: NextFunction, span: Span, prevSpan: undefined | Span): NextFunction {
return new Proxy(next, {
apply: (originalNext, thisArgNext, argsNext) => {
span.end();
if (prevSpan) {
return withActiveSpan(prevSpan, () => {
return Reflect.apply(originalNext, thisArgNext, argsNext);
});
} else {
return Reflect.apply(originalNext, thisArgNext, argsNext);
}
},
});
}