Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(node): Add docs for async context apis #6641

Merged
merged 4 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/platforms/node/common/configuration/async-context.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: Async Context
sidebar_order: 80
description: "Learn more about how to isolate Sentry scope and breadcrumbs across requests."
---

You can use the `runWithAsyncContext` method to isolate Sentry scope and breadcrumbs to a single request if you are using SDK v7.48.0 or higher. This is useful if you are finding that breadcrumbs and scope are leaking across requests.

```js
const Sentry = require("@sentry/node");

function requestHandlerMiddleware(req, res, next) {
// Any breadcrumbs or tags added will be isolated to the request
return Sentry.runWithAsyncContext(
() => {
return next(req, res);
},
{ emitters: [req, res] }
AbhiPrasad marked this conversation as resolved.
Show resolved Hide resolved
);
}
```

Under the hood, the SDK uses Node's [AsyncLocalStorage API](https://nodejs.org/api/async_context.html#class-asynclocalstorage) to perform the isolation.

On lower SDK versions you'll have to use [domains](https://nodejs.org/api/domain.html) to isolate Sentry scope and breadcrumbs to a single request.

```js
const domain = require("domain");

function myRequestHandler(req, res, next) {
const localDomain = domain.create();

localDomain.add(req);
localDomain.add(res);
AbhiPrasad marked this conversation as resolved.
Show resolved Hide resolved

return localDomain.bind(() => {
return next(req, res);
})();
}
```
2 changes: 1 addition & 1 deletion src/platforms/node/guides/express/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
AbhiPrasad marked this conversation as resolved.
Show resolved Hide resolved
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down
3 changes: 2 additions & 1 deletion src/platforms/node/guides/express/performance/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down Expand Up @@ -132,6 +132,7 @@ app.get("/success", function successHandler(req, res) {
## Connecting Services

If you are also using Performance Monitoring for [JavaScript](/platforms/javascript/performance/), depending on where your request originates, you can connect traces:

1. For requests that start in your backend, by [adding a meta tag](/platforms/javascript/performance/connect-services/#pageload) in your HTML template that contains tracing information.
2. For requests that start in JavaScript, by the SDK [setting a header](/platforms/javascript/performance/connect-services/#navigation-and-other-xhr-requests) on requests to your backend.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down
44 changes: 20 additions & 24 deletions src/platforms/node/guides/koa/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ const Sentry = require("@sentry/node");
const { stripUrlQueryAndFragment } = require("@sentry/utils");
const Koa = require("koa");
const app = new Koa();
const domain = require("domain");

Sentry.init({
dsn: "___PUBLIC_DSN___",
Expand All @@ -64,30 +63,25 @@ Sentry.init({
],
});

// not mandatory, but adding domains does help a lot with breadcrumbs
const requestHandler = (ctx, next) => {
return new Promise((resolve, reject) => {
const local = domain.create();
local.add(ctx);
local.on("error", err => {
ctx.status = err.status || 500;
ctx.body = err.message;
ctx.app.emit("error", err, ctx);
reject(err);
});
local.run(async () => {
Sentry.getCurrentHub().configureScope(scope =>
scope.addEventProcessor(event =>
Sentry.addRequestDataToEvent(event, ctx.request, {
include: {
user: false,
},
});
Sentry.runWithAsyncContext(
async hub => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question about this API: Why do we pass the hub as argument? Couldn't we just tell users to call Sentry.getCurrentHub() inside instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed offline and decided this was fine, since very few people are going to use this API anyway.

hub.configureScope(scope =>
scope.addEventProcessor(event =>
Sentry.addRequestDataToEvent(event, ctx.request, {
include: {
user: false,
},
})
)
);
);
await next();
resolve();
});

await next();
resolve();
},
{ emitters: [ctx] }
);
});
};

Expand All @@ -99,7 +93,9 @@ const tracingMiddleWare = async (ctx, next) => {
// connect to trace of upstream app
let traceparentData;
if (ctx.request.get("sentry-trace")) {
traceparentData = Sentry.extractTraceparentData(ctx.request.get("sentry-trace"));
traceparentData = Sentry.extractTraceparentData(
ctx.request.get("sentry-trace")
);
}

const transaction = Sentry.startTransaction({
Expand Down Expand Up @@ -136,7 +132,7 @@ app.use(tracingMiddleWare);

// usual error handler
app.on("error", (err, ctx) => {
Sentry.withScope((scope) => {
Sentry.withScope(scope => {
scope.addEventProcessor(event => {
return Sentry.addRequestDataToEvent(event, ctx.request);
});
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/node/guides/serverless-cloud/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Sentry.init({
// tracesSampleRate: parseFloat(params.SENTRY_TRACES_SAMPLE_RATE),
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
api.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down
2 changes: 1 addition & 1 deletion src/wizard/node/express.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down
2 changes: 1 addition & 1 deletion src/wizard/node/serverlesscloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Sentry.init({
// tracesSampleRate: parseFloat(params.SENTRY_TRACES_SAMPLE_RATE),
});

// RequestHandler creates a separate execution context using domains, so that every
// RequestHandler creates a separate execution context, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
api.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
Expand Down