Skip to content

Commit 8a1be9f

Browse files
committed
Update sentry
1 parent bac7bd4 commit 8a1be9f

File tree

11 files changed

+805
-713
lines changed

11 files changed

+805
-713
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ SESSION_SECRET="super-duper-s3cret"
66
HONEYPOT_SECRET="super-duper-s3cret"
77
RESEND_API_KEY="re_blAh_blaHBlaHblahBLAhBlAh"
88
SENTRY_DSN="your-dsn"
9+
SENTRY_ENVIRONMENT="development"
910

1011
# this is set to a random value in the Dockerfile
1112
INTERNAL_COMMAND_TOKEN="some-made-up-token"

.github/workflows/deploy.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ jobs:
215215
if: ${{ github.ref == 'refs/heads/dev' }}
216216
run: |
217217
flyctl deploy \
218+
--env SENTRY_ENVIRONMENT=staging \
218219
--image "registry.fly.io/${{ steps.app_name.outputs.value }}-staging:${{ github.sha }}" \
219220
--app ${{ steps.app_name.outputs.value }}-staging
220221
env:
@@ -224,6 +225,18 @@ jobs:
224225
if: ${{ github.ref == 'refs/heads/main' }}
225226
run: |
226227
flyctl deploy \
228+
--env SENTRY_ENVIRONMENT=production \
227229
--image "registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.sha }}"
228230
env:
229231
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
232+
233+
- name: Create Sentry release
234+
env:
235+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
236+
# SENTRY_ORG: 'your sentry org id or slug'
237+
# SENTRY_PROJECT: 'your sentry project id or slug'
238+
if: ${{ env.SENTRY_AUTH_TOKEN }}
239+
uses: getsentry/action-release@v3
240+
with:
241+
environment:
242+
${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}

app/entry.client.tsx

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,44 @@
1+
import * as Sentry from '@sentry/react-router'
12
import { startTransition } from 'react'
23
import { hydrateRoot } from 'react-dom/client'
34
import { HydratedRouter } from 'react-router/dom'
45

5-
if (ENV.MODE === 'production' && ENV.SENTRY_DSN) {
6-
void import('./utils/monitoring.client.tsx').then(({ init }) => init())
7-
}
6+
Sentry.init({
7+
// Sentry will only send requests if SENTRY_DSN is defined
8+
dsn: ENV.MODE === 'production' ? ENV.SENTRY_DSN : undefined,
9+
// See https://spotlightjs.com/ for how to install the Spotlight Desktop app for local development
10+
spotlight: ENV.MODE === 'development',
11+
environment: ENV.MODE,
12+
beforeSend(event) {
13+
if (event.request?.url) {
14+
const url = new URL(event.request.url)
15+
if (
16+
url.protocol === 'chrome-extension:' ||
17+
url.protocol === 'moz-extension:'
18+
) {
19+
// This error is from a browser extension, ignore it
20+
return null
21+
}
22+
}
23+
return event
24+
},
25+
integrations: [
26+
Sentry.reactRouterTracingIntegration(),
27+
Sentry.replayIntegration(),
28+
],
29+
30+
// Set tracesSampleRate to 1.0 to capture 100%
31+
// of transactions for performance monitoring.
32+
// We recommend adjusting this value in production
33+
tracesSampleRate: 1.0,
34+
35+
// Capture Replay for 10% of all sessions,
36+
// plus for 100% of sessions with an error
37+
replaysSessionSampleRate: 0.1,
38+
replaysOnErrorSampleRate: 1.0,
39+
40+
enableLogs: true,
41+
})
842

943
startTransition(() => {
1044
hydrateRoot(document, <HydratedRouter />)

app/entry.server.tsx

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
import crypto from 'node:crypto'
22
import { PassThrough } from 'node:stream'
3-
import { styleText } from 'node:util'
43
import { contentSecurity } from '@nichtsam/helmet/content'
54
import { createReadableStreamFromReadable } from '@react-router/node'
65
import * as Sentry from '@sentry/react-router'
76
import { isbot } from 'isbot'
87
import { renderToPipeableStream } from 'react-dom/server'
9-
import {
10-
ServerRouter,
11-
type LoaderFunctionArgs,
12-
type ActionFunctionArgs,
13-
type HandleDocumentRequestFunction,
14-
} from 'react-router'
8+
import { type HandleDocumentRequestFunction, ServerRouter } from 'react-router'
159
import { getEnv, init } from './utils/env.server.ts'
1610
import { getInstanceInfo } from './utils/litefs.server.ts'
1711
import { NonceProvider } from './utils/nonce-provider.ts'
@@ -26,7 +20,7 @@ const MODE = process.env.NODE_ENV ?? 'development'
2620

2721
type DocRequestArgs = Parameters<HandleDocumentRequestFunction>
2822

29-
export default async function handleRequest(...args: DocRequestArgs) {
23+
async function handleRequest(...args: DocRequestArgs) {
3024
const [request, responseStatusCode, responseHeaders, reactRouterContext] =
3125
args
3226
const { currentInstance, primaryInstance } = await getInstanceInfo()
@@ -96,7 +90,8 @@ export default async function handleRequest(...args: DocRequestArgs) {
9690
status: didError ? 500 : responseStatusCode,
9791
}),
9892
)
99-
pipe(body)
93+
// this enables distributed tracing between client and server!
94+
pipe(Sentry.getMetaTagTransformer(body))
10095
},
10196
onShellError: (err: unknown) => {
10297
reject(err)
@@ -122,21 +117,6 @@ export async function handleDataRequest(response: Response) {
122117
return response
123118
}
124119

125-
export function handleError(
126-
error: unknown,
127-
{ request }: LoaderFunctionArgs | ActionFunctionArgs,
128-
): void {
129-
// Skip capturing if the request is aborted as Remix docs suggest
130-
// Ref: https://remix.run/docs/en/main/file-conventions/entry.server#handleerror
131-
if (request.signal.aborted) {
132-
return
133-
}
134-
135-
if (error instanceof Error) {
136-
console.error(styleText('red', String(error.stack)))
137-
} else {
138-
console.error(error)
139-
}
120+
export const handleError = Sentry.createSentryHandleError({ logErrors: true })
140121

141-
Sentry.captureException(error)
142-
}
122+
export default Sentry.wrapSentryHandleRequest(handleRequest)

app/utils/monitoring.client.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.

instrument.server.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { nodeProfilingIntegration } from '@sentry/profiling-node'
2+
import * as Sentry from '@sentry/react-router'
3+
4+
Sentry.init({
5+
release: process.env.COMMIT_SHA,
6+
// Sentry will only send requests if the dsn is defined
7+
dsn:
8+
process.env.NODE_ENV === 'production' ? process.env.SENTRY_DSN : undefined,
9+
// See https://spotlightjs.com/ for how to install the Spotlight Desktop app for local development
10+
spotlight: process.env.NODE_ENV === 'development',
11+
environment: process.env.SENTRY_ENVIRONMENT,
12+
denyUrls: [
13+
/\/resources\/healthcheck/,
14+
/\/favicons\//,
15+
/\/img\//,
16+
/\/fonts\//,
17+
/\/favicon.ico/,
18+
/\/site\.webmanifest/,
19+
],
20+
integrations: [
21+
Sentry.prismaIntegration(),
22+
Sentry.httpIntegration(),
23+
nodeProfilingIntegration(),
24+
Sentry.consoleLoggingIntegration(),
25+
],
26+
tracesSampler(samplingContext) {
27+
// ignore healthcheck transactions by other services (consul, etc.)
28+
if (samplingContext.request?.url?.includes('/resources/healthcheck')) {
29+
return 0
30+
}
31+
return 1
32+
},
33+
beforeSendTransaction(event) {
34+
// ignore all healthcheck related transactions
35+
// note that name of header here is case-sensitive
36+
if (event.request?.headers?.['x-healthcheck'] === 'true') {
37+
return null
38+
}
39+
40+
return event
41+
},
42+
// Enable logs to be sent to Sentry
43+
enableLogs: true,
44+
})

0 commit comments

Comments
 (0)