Sentry error and performance monitoring [experimental]

This command is currently in the canary release. It will be fully available with Redwood v5.2.

Setup Sentry error and performance monitoring across your Redwood application.

From your command line, run:

yarn redwood experimental setup-sentry

This command installs and sets up @sentry/node and @sentry/react, enabling Prisma and Browser tracing to capture 100% of events. The following sections detail how you may further integrate Sentry in your Redwood application.

Sentry Envelop Plugin

The setup command will install and attempt to setup the @envelop/sentry plugin in your application’s GraphQL handler. If there is a problem installing it, the following can be used to do so manually.

import { useSentry } from '@envelop/sentry'

import { createGraphQLHandler } from '@redwoodjs/graphql-server'

import directives from 'src/directives/**/*.{js,ts}'
import sdls from 'src/graphql/**/*.sdl.{js,ts}'
import services from 'src/services/**/*.{js,ts}'

import 'src/lib/sentry'

...

export const handler = createGraphQLHandler({
  directives,
  sdls,
  services,
  extraPlugins: [useSentry()],
  ...
})

Setting the current user

You can associate error and performance events with a unique identity using Sentry.setUser. Below is an example of doing so on the API by setting the identity to the user returned by getCurrentUser.

import Sentry from 'src/lib/sentry'

export const getCurrentUser = async (...) => {
  const user = await db.user.findUnique(...)

  Sentry.setUser(user)

  ...
}

Below we set the current user on the web-side from within a layout. Note that the useEffect dependency array may vary depending on where you place Sentry.setUser in your own application.

import { useEffect } from 'react'

import { useAuth } from 'src/lib/auth'
import Sentry from 'src/lib/sentry'

const SentryLayout = ({ children }) => {
  const { currentUser } = useAuth()

  useEffect(() => Sentry.setUser(currentUser), [currentUser])

  return <>{children}</>
}

export default SentryLayout

Capturing exceptions

You can make use of Sentry to capture exceptions which occur while executing API Functions.

import Sentry from 'src/lib/sentry'

export const handler = async (event, context) => {
  try {
    ...
  } catch (err) {
    Sentry.captureException(err)
  }
}
1 Like

Seems to crash when setting up

❯ yarn redwood experimental setup-sentry
✔ Adding required api packages...
✔ Adding required web packages...
✔ Adding SENTRY_DSN var to .env...
✔ Setting up Sentry on the API and web sides
✖ contentLines.findLastIndex is not a function
◼ Replacing Redwood's Error boundary
◼ Adding config to redwood.toml...
◼ One more thing...
contentLines.findLastIndex is not a function

This probably doesn’t handle releases?

It also seems to import the deprecated BrowserTracing instead of the new one.

1 Like

@razzeee I’ve seen this error just the other day—are you on Node 16? The fix may be just using Node 18 locally

That seems to be the case, it then crashes on my current sentry implementation, but that’s fine.

[...]
✔ Implementing the Envelop plugin
✖ Unterminated regular expression. (50:3)
  48 |
  49 | export default App
  > 50 | </Sentry.ErrorBoundary>
  |   ^
◼ Adding config to redwood.toml...
◼ One more thing...
Unterminated regular expression. (50:3)
  48 |
  49 | export default App
> 50 | </Sentry.ErrorBoundary>
     |   ^
1 Like

I have just raised a PR to update the implementation to remove the deprecated tracing package as this is no longer its own package.

2 Likes

Reported an issue that prevents Sentry’s DSN from being loaded in production.

[Bug]: Sentry experimental setup in production · Issue #9978 · redwoodjs/redwood · GitHub

Thanks @Bigood, I see it in GitHub and we’ll triage and investigate there.

So I was able to get Sentry setup capturing issues, but am a little confused on how to setup the Replays feature.
Anyone manage to get that setup?

It looks like there’s a sentry.js in web/src/lib as well as api/src/lib.
The api side seems to work and send off issues, but the Replay from the web side seems to have problems.

This shows the API side event getting out, but not the Web side one:
sentry-error

With how Redwood is setup how should I be using the distributed tracing here as well where it uses “tracePropagationTargets”? This is how I have that setup for now in api/src/lib:


import { db as client } from 'src/lib/db'

Sentry.init({
  dsn: process?.env?.SENTRY_DSN,
  environment: process?.env?.NODE_ENV,
  integrations: [
    new Sentry.Integrations.Prisma({ client }),
    new Sentry.Integrations.Http({ tracing: true }),
  ],
  tracesSampleRate: 1.0,
  tracePropagationTargets: ['localhost:8910', /^https:\/\/localhost:8911/],
})

export default Sentry

with the whole setup in web/src/lib being:

import * as Sentry from '@sentry/react'

// let dsn = ''
let dsn =
  '__your_project_dsn__'

let environment = 'development'

if (!dsn) {
  console.error(
    'Missing SENTRY_DSN environment variable. Did you forget to add it to ' +
      'your redwood.toml file in `includeEnvironmentVariables`?'
  )
  console.info(`Copy this into your redwood.toml file:`)
  console.info(`
  includeEnvironmentVariables = [
    "SENTRY_DSN"
  ]

  `)
  console.error('Sentry is disabled for now')
} else {
  console.log('Sentry enabled')
}

Sentry.init({
  dsn: '__your_project's_dsn__',
  environment: 'development',

  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,

  integrations: [
    Sentry.replayIntegration({
      maskAllText: true,
      blockAllMedia: true,
    }),
  ],
})

export default Sentry

I am deployed to Vercel, but this is just trying to get things working locally
I have this included with the sentry.js in api/src/lib. but it’s a little confusing if that is the right place for the tracePropagationTargets:
Sentry Docs tracePropagationTargets

I also hit the process error @Bigood came across. To get around that for now I just used a hardcoded value for the project dsn and environment.

EDIT: So this actually worked, it just took me a while to get an error with what I had setup. You can see what the replay looks like here:

Kind of wild seeing the user interpolated mouse movements