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 all 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
33 changes: 33 additions & 0 deletions src/platforms/node/common/configuration/async-context.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
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);
});
}
```

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();
return localDomain.bind(() => {
return next(req, res);
})();
}
```
4 changes: 2 additions & 2 deletions src/platforms/node/guides/express/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
// RequestHandler creates a separate execution context, so that all
// transactions/spans/breadcrumbs are isolated across requests
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
app.use(Sentry.Handlers.tracingHandler());
Expand Down
5 changes: 3 additions & 2 deletions src/platforms/node/guides/express/performance/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
// RequestHandler creates a separate execution context, so that all
// transactions/spans/breadcrumbs are isolated across requests
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
app.use(Sentry.Handlers.tracingHandler());
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,8 +37,8 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
// RequestHandler creates a separate execution context, so that all
// transactions/spans/breadcrumbs are isolated across requests
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
app.use(Sentry.Handlers.tracingHandler());
Expand Down
26 changes: 10 additions & 16 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,27 +63,20 @@ 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 =>
Sentry.runWithAsyncContext(async () => {
const hub = Sentry.getCurrentHub();
hub.configureScope(scope =>
scope.addEventProcessor(event =>
Sentry.addRequestDataToEvent(event, ctx.request, {
include: {
user: false,
},
});
);
})
)
);

await next();
resolve();
});
Expand All @@ -99,7 +91,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 +130,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
4 changes: 2 additions & 2 deletions src/platforms/node/guides/serverless-cloud/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ Sentry.init({
// tracesSampleRate: parseFloat(params.SENTRY_TRACES_SAMPLE_RATE),
});

// RequestHandler creates a separate execution context using domains, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
// RequestHandler creates a separate execution context, so that all
// transactions/spans/breadcrumbs are isolated across requests
api.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
api.use(Sentry.Handlers.tracingHandler());
Expand Down
4 changes: 2 additions & 2 deletions src/wizard/node/express.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Sentry.init({
tracesSampleRate: 1.0,
});

// RequestHandler creates a separate execution context using domains, so that every
// transaction/span/breadcrumb is attached to its own Hub instance
// RequestHandler creates a separate execution context, so that all
// transactions/spans/breadcrumbs are isolated across requests
app.use(Sentry.Handlers.requestHandler());
// TracingHandler creates a trace for every incoming request
app.use(Sentry.Handlers.tracingHandler());
Expand Down
4 changes: 2 additions & 2 deletions src/wizard/node/serverlesscloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ Sentry.init({
// tracesSampleRate: parseFloat(params.SENTRY_TRACES_SAMPLE_RATE),
});

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