Description
openedon Mar 20, 2024
Is there an existing issue for this?
- I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- I have reviewed the documentation https://docs.sentry.io/
- I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/node
SDK Version
7.107
Framework Version
No response
Link to Sentry event
No response
SDK Setup
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.2,
integrations: excludeFalsy([
new Sentry.Integrations.Anr({ captureStackTrace: true }),
new Sentry.Integrations.Hapi({ server }),
new Sentry.Integrations.Postgres(),
]),
});
Steps to Reproduce
- Enable Sentry Hapi integration.
- Let our Hapi service handle some async requests (e.g., database queries).
Expected Result
Database queries are correctly correlated with their HTTP requests.
Actual Result
Requests may be mismatched.
Sentry's hapiTracingPlugin uses onPreHandler
and onPostHandler
events to try to narrow the scope of the Sentry span to just a single Hapi request. However, that doesn't ensure handling of async operations within the request handler itself.
I tried figuring out a solution to this. If I'm understanding Sentry's API correctly, it expects you to use withScope
or withIsolationScope
to wrap the request handler. However, I don't see how to make that work with hapiTracingPlugin's design of onPreHandler
and onPostHandler
events. If Sentry had some sort of startIsolationScope
and endIsoluationScope
method, then pre- and post- events could probably work. Otherwise, the only solution I can think of would be to more invasively patch / instrument a Hapi application to wrap the request handlers themselves. (I believe that's the approach used by OpenTelemetry's Hapi instrumentation.)
Test case: The following demo starts a Hapi service on a random port, with an asynchronous route handler, and fires off 4 requests to the service, separated by 100ms intervals. Each request should have its own timestamp and span ID, and none of the requests should include an HTTP status (because the requests haven't finished at the time they're logged), but they're all the same.
'use strict';
const Sentry = require('@sentry/node');
const Hapi = require('@hapi/hapi');
const { setTimeout } = require('node:timers/promises');
const init = async () => {
const server = Hapi.server({
host: 'localhost'
});
Sentry.init({
// Enable Spotlight to allow running without a DSN.
spotlight: true,
integrations: [
new Sentry.Integrations.Hapi({ server }),
]
})
server.route({
method: 'GET',
path: '/',
handler: async () => {
await setTimeout(2000);
console.log(Sentry.getActiveSpan().toJSON());
return 'Hello World!';
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
return server.info.uri;
};
async function main() {
const url = await init();
for (let i = 0; i < 4; i++) {
fetch(url).then((res) => res.text()).then(console.log);
await setTimeout(100);
}
}
main();
Metadata
Assignees
Type
Projects
Status
Waiting for: Community
Status
Waiting for: Community
Activity