I’ve managed to solve this in Nest.js with a global interceptor. Here’s the code:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import * as Sentry from '@sentry/node';
import * as Constants from '@nestjs/common/constants';
import { Reflector } from '@nestjs/core';
@Injectable()
export class SentryInterceptor implements NestInterceptor {
constructor(private readonly reflector: Reflector) {}
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
const scope = Sentry.getCurrentHub().getScope();
if (scope) {
const transaction = scope.getTransaction();
if (transaction) {
const classPath: string = this.reflector.get<string>(Constants.PATH_METADATA, context.getClass());
const handlerPath: string = this.reflector.get<string>(Constants.PATH_METADATA, context.getHandler());
const method = context.switchToHttp().getRequest().method;
transaction.name = `${method} /api/v1/${classPath}/${handlerPath}`;
}
}
return next.handle();
}
}
I went a bit overboard with checks, but I don’t want misconfigured Sentry to bring down my whole app. I’m sure something extremely similar can be achieved with Express.js middleware. This turned routes like
‘GET /api/v1/locations/1/drivers/127/date-overview’
into
‘GET /api/v1/locations/:locationId/drivers/:id/date-overview’