-
-
Couldn't load subscription status.
- Fork 1.7k
Using Sentry v8 without HTTP autoinstrumentation #12982
-
Sentry v8 removed the very convenient Sentry.Handlers.requestHandler() that could be dropped easily into an Express application. Now, instrumentation is "automagical" and requires one to jump through some hoops to get it to work, particularly if you're running native ESM. In my case, it would require a pretty invasive restructuring of my application's bootstrapping process to ensure that Sentry could put its hooks into everything when it wants to. If, like me, you don't care about Sentry's performance/transaction features and just want it to reliably capture errors and their associated context, I've found that this little snippet will more or less give you a Sentry v7 experience in Express applications:
import * as Sentry from '@sentry/node'; import { stripUrlQueryAndFragment } from '@sentry/utils'; /** * Based on Sentry code that is not exported: * https://github.com/getsentry/sentry-javascript/blob/602703652959b581304a7849cb97117f296493bc/packages/utils/src/requestdata.ts#L102 */ function extractTransaction(req: any) { const method = req.method?.toUpperCase() || ''; const path = stripUrlQueryAndFragment(req.originalUrl || req.url || ''); let name = ''; if (method) { name += method; } if (method && path) { name += ' '; } if (path) { name += path; } return name; } export function requestHandler() { return (req: any, _res: any, next: any) => { Sentry.withIsolationScope((scope) => { scope.addEventProcessor((event) => { event.transaction = extractTransaction(req); return Sentry.addRequestDataToEvent(event, req); }); next(); }); }; }
This can then be used as Express middleware:
app.use(requestHandler()); // You'll still need to add an error handler after all your // application routes: app.use(Sentry.expressErrorHandler());
I hopes this helps anyone else that's in a similar boat!
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 2 replies
-
Now, instrumentation is "automagical" and requires one to jump through some hoops to get it to work
Unfortunately this is how Node.js has designed ESM to work - you have to use loaders to do auto-instrumentation (where we automatically wrap things). I understand it's not the best experience, we're trying to make changes in Node.js itself to make this better!
Three things to note from your snippet:
-
distributed tracing will not work (spans/transactions are separate to the tracing concept in Sentry). So if you wanted to associate errors between different micro-services instrumented with Sentry, or link your frontend session replay to your backend express errors, you'll still need to use the auto-instrumentation included with the default Sentry setup. Otherwise you'll have to manually do this: https://docs.sentry.io/platforms/javascript/guides/node/tracing/trace-propagation/custom-instrumentation/
-
event.transaction = extractTransaction(req);will set an un-parameterized name for the transaction name, because it parsesreq.originalUrl. This means you'll get something like/users/123/instead ofusers/:id, which means that grouping related issues by route is less effective. The default express instrumentation does some extended logic to generated a parameterized name - I recommend vendoring this in some way.
OTEL implementation: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/afccd0d62a0ea81afb8f5609f3ee802c038d11c6/plugins/node/opentelemetry-instrumentation-express/src/utils.ts#L153-L159
Old Sentry implementation:
- The
requestHandlerimplementation does not have logic around release health. You'll still need to useSentry.expressErrorHandlerto make sure aggregate sessions are being tracked properly:export function expressErrorHandler(options?: {
Beta Was this translation helpful? Give feedback.
All reactions
-
distributed tracing will not work
This is very much acceptable for me. As I called out in my post, I "don't care about Sentry's performance/transaction features and just want it to reliably capture errors and their associated context".
will set an un-parameterized name for the transaction name
This is actually an improvement for me over Sentry v7. Our application does something like the following:
const app = express(); const usersRouter = express.Router(); usersRouter.get('/', ...); app.use('/users', usersRouter);
In practice, this meant that the transaction name was reported as GET / or POST / no matter what the actual route was, presumably because Sentry was only looking at the last "layer" of the route stack.
I did see that Sentry tried to derive a parameterized transaction name based on the Express route and thought that might have had something to do with grouping on the Sentry backend. I tested out the non-parameterized transaction name and didn't see any immediate adverse affects in the Sentry UI.
You'll still need to use Sentry.expressErrorHandler to make sure aggregate sessions are being tracked properly.
Indeed, I was already doing that, I'll add that to my above code snippet so anyone landing here isn't mislead!
Beta Was this translation helpful? Give feedback.
All reactions
-
Unfortunately this is how Node.js has designed ESM to work - you have to use loaders to do auto-instrumentation (where we automatically wrap things).
Yep, I understand this from our other, direct usages of OTel. From what I can tell, there's no technical reason you couldn't have kept around Sentry.Handler.requestHandler() as an alternative option to auto-instrumentation of the HTTP module. I get that you're trying to make things easy for folks setting up Sentry for the first time. It's just a shame that the old, manual setup option wasn't retained as an "I know what I'm doing and am willing to add/keep an extra line of code in my application setup" option.
I understand it's not the best experience, we're trying to make changes in Node.js itself to make this better!
I'm very glad to hear you're advocating for that! I hope this will let us remove some annoying hacks we've used to work around this with our own OTel instrumentation.
Beta Was this translation helpful? Give feedback.