Skip to content

New Koa configuration #1804

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

Merged
merged 4 commits into from
Jun 29, 2020
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
### Koa

Creates and attach a transaction to each context

```javascript
const Sentry = require('@sentry/node')
const { Span } = require('@sentry/apm')
const Koa = require('koa')
const app = new Koa()
const domain = require('domain')

Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 0.25
})

// not mandatory, but adding domains do 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)
})
local.run(async() => {
Sentry.getCurrentHub().configureScope(scope =>
scope.addEventProcessor((event) => Sentry.Handlers.parseRequest(event, ctx.request, {user: false}))
)
await next()
resolve()
})
})
}

// this tracing middleware creates a transaction per request
const tracingMiddleWare = async (ctx, next) => {
// captures span of upstream app
const sentryTraceId = ctx.request.get('sentry-trace')
let traceId
let parentSpanId
if (sentryTraceId) {
const span = Span.fromTraceparent(sentryTraceId)
if (span) {
traceId = span.traceId
parentSpanId = span.parentSpanId
}
}
const transaction = Sentry.startTransaction({
name: `${ctx.method} ${ctx.url}`,
op: 'http.server',
parentSpanId,
traceId,
})
ctx.__sentry_transaction = transaction
await next()

// if using koa router, a nicer way to capture transaction using the matched route
if (ctx._matchedRoute) {
const mountPath = ctx.mountPath || ''
transaction.setName(`${ctx.method} ${mountPath}${ctx._matchedRoute}`)
}
transaction.setHttpStatus(ctx.status)
transaction.finish()
}

app.use(requestHandler)
app.use(tracingMiddleWare)

// usual error handler
app.on('error', (err, ctx) => {
Sentry.withScope(function (scope) {
scope.addEventProcessor(function (event) {
return Sentry.Handlers.parseRequest(event, ctx.request)
})
Sentry.captureException(err)
})
})
// the rest of your app
```

#### Subsequent manual child transactions

The following example creates a transaction 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

```javascript
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()
}
```