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; } } } |