Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 1x 1x 1x 1x 3x 3x 1x | import { CallHandler, ExecutionContext, Injectable, NestInterceptor, Inject } from '@nestjs/common';
import { Observable, TimeoutError } from 'rxjs';
import { tap } from 'rxjs/operators';
import { SENTRY_TOKEN, InjectSentry } from '../common';
import { SentryService } from './sentry.service';
import { Scope } from '@sentry/hub';
import { HttpArgumentsHost, ContextType, WsArgumentsHost, RpcArgumentsHost } from '@nestjs/common/interfaces';
import { Handlers } from '@sentry/node';
import { SentryInterceptorOptions, SentryFilterFunction, SentryInterceptorOptionsFilter } from '../interfaces/sentry-interceptor.interface';
@Injectable()
export class SentryInterceptor implements NestInterceptor {
constructor(
@InjectSentry() private readonly client: SentryService,
private readonly options?: SentryInterceptorOptions) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
// first param would be for events, second is for errors
return next.handle().pipe(
tap(null, (exception) => {
if (this.shouldReport(exception)) {
this.client.instance().withScope((scope) => {
switch (context.getType<ContextType>()) {
case 'http':
return this.captureHttpException(
scope,
context.switchToHttp(),
exception
);
case 'rpc':
return this.captureRpcException(
scope,
context.switchToRpc(),
exception,
);
case 'ws':
return this.captureWsException(
scope,
context.switchToWs(),
exception,
);
}
})
}
})
);
}
private captureHttpException(scope: Scope, http: HttpArgumentsHost, exception: any): void {
const data = Handlers.parseRequest(<any>{},http.getRequest(), this.options);
scope.setExtra('req', data.request);
data.extra && scope.setExtras(data.extra);
if (data.user) scope.setUser(data.user);
this.captureException(scope, exception);
}
private captureRpcException(
scope: Scope,
rpc: RpcArgumentsHost,
exception: any,
): void {
scope.setExtra('rpc_data', rpc.getData());
this.captureException(scope, exception);
}
private captureWsException(
scope: Scope,
ws: WsArgumentsHost,
exception: any,
): void {
scope.setExtra('ws_client', ws.getClient());
scope.setExtra('ws_data', ws.getData());
this.captureException(scope, exception);
}
private captureException(scope: Scope, exception: any): void {
if (this.options) {
if (this.options.level) scope.setLevel(this.options.level);
if (this.options.fingerprint)
scope.setFingerprint(this.options.fingerprint);
if (this.options.extra) scope.setExtras(this.options.extra);
if (this.options.tags) scope.setTags(this.options.tags);
}
this.client.instance().captureException(exception);
}
private shouldReport(exception: any) {
if (this.options && !this.options.filters) return true;
// If all filters pass, then we do not report
if (this.options) {
const opts: SentryInterceptorOptions = this.options as {}
if (opts.filters) {
let filters: SentryInterceptorOptionsFilter[] = opts.filters
return filters.every(({ type, filter }) => {
return !(exception instanceof type && (!filter || filter(exception)));
});
}
} else {
return true;
}
}
}
|