Koa
Add @sentry/node
as a dependency:
Copied
npm install --save @sentry/node @sentry/utils
Initialize the Sentry SDK and install the on error hook:
Copied
import Koa from "koa";
import * as Sentry from "@sentry/node";
// or using CommonJS
// const Koa = require('koa');
// const Sentry = require('@sentry/node');
const app = new Koa();
Sentry.init({ dsn: "https://examplePublicKey@o0.ingest.sentry.io/0" });
app.on("error", (err, ctx) => {
Sentry.withScope((scope) => {
scope.setSDKProcessingMetadata({ request: ctx.request });
Sentry.captureException(err);
});
});
app.listen(3000);
Create and attach a transaction to each request:
Copied
const Sentry = require("@sentry/node");
const { stripUrlQueryAndFragment } = require("@sentry/utils");
const Koa = require("koa");
const app = new Koa();
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
integrations: [
// Automatically instrument Node.js libraries and frameworks
...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),
],
});
const requestHandler = (ctx, next) => {
Sentry.runWithAsyncContext(() => {
const scope = Sentry.getCurrentScope();
scope.addEventProcessor((event) =>
Sentry.addRequestDataToEvent(event, ctx.request, {
include: {
user: false,
},
})
);
next();
});
};
// this tracing middleware creates a transaction per request
const tracingMiddleWare = (ctx, next) => {
const reqMethod = (ctx.method || "").toUpperCase();
const reqUrl = ctx.url && stripUrlQueryAndFragment(ctx.url);
// connect to trace of upstream app
let traceparentData;
if (ctx.request.get("sentry-trace")) {
traceparentData = Sentry.extractTraceparentData(
ctx.request.get("sentry-trace")
);
}
const transaction = Sentry.startTransaction({
name: `${reqMethod} ${reqUrl}`,
op: "http.server",
...traceparentData,
});
ctx.__sentry_transaction = transaction;
// We put the transaction on the scope so users can attach children to it
Sentry.getCurrentScope().setSpan(transaction);
ctx.res.on("finish", () => {
// Push `transaction.finish` to the next event loop so open spans have a chance to finish before the transaction closes
setImmediate(() => {
// if using koa router, a nicer way to capture transaction using the matched route
if (ctx._matchedRoute) {
const mountPath = ctx.mountPath || "";
transaction.setName(`${reqMethod} ${mountPath}${ctx._matchedRoute}`);
}
transaction.setHttpStatus(ctx.status);
transaction.finish();
});
});
next();
};
app.use(requestHandler);
app.use(tracingMiddleWare);
// usual error handler
app.on("error", (err, ctx) => {
Sentry.withScope((scope) => {
scope.addEventProcessor((event) => {
return Sentry.addRequestDataToEvent(event, ctx.request);
});
Sentry.captureException(err);
});
});
// the rest of your app
The following example creates a span for a part of the code that contains an expensive operation and sends the result to Sentry. You will need to use the transaction stored in the context.
Copied
const myMiddleware = async (ctx, next) => {
let span;
const transaction = ctx.__sentry_transaction;
if (transaction) {
span = transaction.startChild({
description: route,
op: "myMiddleware",
});
}
await myExpensiveOperation();
if (span) {
span.finish();
}
return next();
};
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").