Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrate nestjs with sentry

I want to integrate sentry with nest.js + express but I just found raven version but that is deprecated. I follow the sentry docs for integrate with express but dont know how to handle the 'All controllers should live here' part.

const express = require('express');
const app = express();
const Sentry = require('@sentry/node');

Sentry.init({ dsn: 'https://[email protected]/1768434' });

// The request handler must be the first middleware on the app
app.use(Sentry.Handlers.requestHandler());

**// All controllers should live here
app.get('/', function rootHandler(req, res) {
  res.end('Hello world!');
});**

// The error handler must be before any other error middleware and after all controllers
app.use(Sentry.Handlers.errorHandler());

// Optional fallthrough error handler
app.use(function onError(err, req, res, next) {
  // The error id is attached to `res.sentry` to be returned
  // and optionally displayed to the user for support.
  res.statusCode = 500;
  res.end(res.sentry + "\n");
});

app.listen(3000);
like image 360
anthony willis muñoz Avatar asked Oct 04 '19 15:10

anthony willis muñoz


1 Answers

I just created a Sample Project on Github to answer this question:

https://github.com/ericjeker/nestjs-sentry-example

Below is a partial copy of the README file. Let me know if you have any questions.

Create the needed elements

Create Sentry module, service, and interceptor

$ nest g module sentry
$ nest g service sentry
$ nest g interceptor sentry/sentry

SentryModule

Create the SentryModule.forRoot() method and add the Sentry.init(options) in it.

Call the SentryModule.forRoot({...}) in the AppModule and integrate with your preferred configuration (I use ConfigModule and a .env file).

Add the call to the Express requestHandler middleware in the AppModule.configure().

  configure(consumer: MiddlewareConsumer): void {
    consumer.apply(Sentry.Handlers.requestHandler()).forRoutes({
      path: '*',
      method: RequestMethod.ALL,
    });
  }

It is important to use that middleware otherwise the current Hub will be global and you will run into conflicts as Sentry creates a Hub by thread and Node.js is not multi-threaded.

SentryService

We want to initialize the transaction in the constructor of the service. You can customize your main transaction there.

Note that because I inject the Express request, the service must be request scoped. You can read more about that here.

@Injectable({ scope: Scope.REQUEST })
export class SentryService {
  constructor(@Inject(REQUEST) private request: Request) {
    // ... etc ...
  }
}

SentryInterceptor

The SentryInterceptor will capture the exception and finish the transaction. Please also note that it must be request scoped as we inject the SentryService:

@Injectable({ scope: Scope.REQUEST })
export class SentryInterceptor implements NestInterceptor {
  constructor(private sentryService: SentryService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // ... etc ...
  }
}

As an example, I added a span. This is not necessary, but it will just make the trace nicer in the performance viewer of Sentry.

You can add more spans anywhere in your application simply by injecting the SentryService and calling startChild or by simply calling the startChild method of the current span.

like image 179
Eric Jeker Avatar answered Oct 25 '22 02:10

Eric Jeker