Can transactions be grouped?

I’ve just added performance monitoring to my node.js application (Nest.js using Express.js as engine) and it’s great, but GET requests with different URL parameters are getting logged as different transactions. So I get transactions like:

GET /api/v1/users/1/
GET /api/v1/users/2/
GET /api/v1/users/3/

You get the point. This makes them very hard to analyse as you can’t see how an endpoint is performing in general. Is there a way to define grouping in a simple way? I guess I could manually override Sentry and name transactions based on URL pattern when the request arrives, but honestly that sounds like a pretty crappy solution to me.

2 Likes

Are you already using the Express integration? There is an express integration that should help capture more spans and give better transaction names.

2 Likes

I also have the same issue, using the default integration for Express. Say an express route is set as app.get("/user/:id", method) then id is a parameter and all /user API calls should be grouped together. Looking at the docs, could not find anything on how to configure this. Any help would be great!

2 Likes

This feature is a bit useless if I’m getting 1000 different transactions for a url like
GET /project/12fe5eas
GET /project/5fcl0ra5
GET /project/3n2reg0

1 Like

Yep, Express integration is already in use and these are the results.

Same here, I’m using Laravel. Support has been useless on this.

We’re hashing our ids, so our routes look like
/v1/profile/bkrq0zm7domzg53e

@markstory have you given up on this thread?

No I haven’t, I’ve been busy with other things.

Transaction events are grouped by the transaction attribute in your events. The SDKs try to generalize URIs via framework integrations, but that doesn’t seem to be working for you folks.

You should be able to use an event processing hook to replace the generated transaction name with a more general URL template based on your routing system. This isn’t ideal but should let you get better results until the framework integration issues can be ironed out.

@markstory Really appreciate the input on this. I wanted to clarify a couple things:

  1. The performance stuff is new and so there’s still some stuff to be ironed out there?
  2. Is there event processing for Laravel? I don’t see it under the enriching menu here https://docs.sentry.io/platforms/php/guides/laravel/

beforeSend is equivalent, you can mutate and discard events in there: https://docs.sentry.io/platforms/php/guides/laravel/configuration/filtering/#using-beforesend

If you find bad transaction names (i.e. not matching route name with place holders for variables) I would file a bug against the SDK though, the forum is not read by every Sentry employee.

@untitaker - I don’t see the that before_send callback is used for transactions, only seems to be called for Events which are components of error reports, but not transactions…

@markstory - Not sure if anyone at Sentry is paying attention to this, but you must be aware that this makes the utility of this performance product extremely limited. Is there a plan to solve this issue?

Okay right. I would still file this issue against the laravel SDK. None of the people who know anything about that SDK read this forum. There is an API in most other SDKs to set the transaction name.

1 Like

Yes, we’re still evolving both the product aspects and the SDK integrations.

I agree that not having well grouped transactions does limit the performance product and improving that is something we want to do. The wide variety of routing systems and frameworks can make that challenging. For both express and laravel where we have integrations it would be helpful if we could learn more about the specific setups that lead to the integrations not being able to generalize transaction names.

1 Like

We use hashed id’s client side so we end up with a big list of stuff that looks like this:
image

What we’d prefer is a single entry like /v1/defendants/:id

I did set up a ‘before_send’ closure, but that doesn’t seem to get picked up… Not sure what I’d need to do in there at any rate, I’d really have to get my hands dirty with that before I’d know how to do the necessary transformation…

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’

Looks like the Sentry team addressed the issues that my team was experiencing with grouping of transaction in Laravel (specifically with the Apiato framework [apiato.io]) in this PR: https://github.com/getsentry/sentry-laravel/pull/408. :tada:

We’ve yet to implement that. Not exactly sure how the release cycle works with Sentry, so don’t know exactly when this will become available or if it even works.

1 Like