Skip to content

Commit

Permalink
Merge pull request #14581 from artsy/DIA-835-force-setup-sentry-perfo…
Browse files Browse the repository at this point in the history
…rmance-dashboard

feat(dia-835): setup sentry performance dashboard
  • Loading branch information
damassi authored Oct 2, 2024
2 parents a98e32a + 88f34ae commit 27ad7c4
Show file tree
Hide file tree
Showing 10 changed files with 684 additions and 150 deletions.
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,9 @@
"@loadable/component": "5.15.2",
"@loadable/server": "5.15.2",
"@segment/consent-manager": "5.7.0",
"@sentry/browser": "6.7.1",
"@sentry/integrations": "^6.7.2",
"@sentry/node": "^6.7.1",
"@sentry/tracing": "^6.7.1",
"@sentry/browser": "^8.32.0",
"@sentry/node": "^8.32.0",
"@sentry/profiling-node": "^8.32.0",
"@stripe/react-stripe-js": "1.10.0",
"@stripe/stripe-js": "^4.1.0",
"@styled-system/theme-get": "5.1.2",
Expand Down
1 change: 1 addition & 0 deletions src/Server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export const SEGMENT_WRITE_KEY_SERVER: any = null
export const SEGMENT_WRITE_KEY: any = null
export const SENTRY_PRIVATE_DSN: any = null
export const SENTRY_PUBLIC_DSN: any = null
export const SENTRY_TRACING_ENABLED: any = false
export const SESSION_COOKIE_KEY: any = "force.sess"
export const SESSION_COOKIE_MAX_AGE: any = 31536000000
export const SESSION_LOCAL_INSECURE: boolean = false
Expand Down
16 changes: 9 additions & 7 deletions src/Server/setupSentryClient.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import * as Sentry from "@sentry/browser"
import { Integrations } from "@sentry/tracing"
import { Dedupe } from "@sentry/integrations"
import {
init,
browserTracingIntegration,
dedupeIntegration,
} from "@sentry/browser"
import {
ALLOWED_URLS,
DENIED_URLS,
IGNORED_ERRORS,
} from "./analytics/sentryFilters"

export function setupSentryClient(sd) {
Sentry.init({
export function setupSentryClient(sentryPublicDSN: string) {
init({
allowUrls: ALLOWED_URLS,
denyUrls: DENIED_URLS,
dsn: sd.SENTRY_PUBLIC_DSN,
dsn: sentryPublicDSN,
ignoreErrors: IGNORED_ERRORS,
integrations: [new Integrations.BrowserTracing(), new Dedupe()],
integrations: [browserTracingIntegration(), dedupeIntegration()],
})
}
4 changes: 2 additions & 2 deletions src/Server/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import withGracefulShutdown from "http-shutdown"
import { once } from "lodash"
import { initializeArtsyXapp } from "./artsyXapp"
import { errorHandlerMiddleware } from "./middleware/errorHandler"
import * as Sentry from "@sentry/node"
import { APP_URL, NODE_ENV, PORT } from "Server/config"
import { setupExpressErrorHandler } from "@sentry/node"

const { HEADERS_TIMEOUT_SECONDS, KEEPALIVE_TIMEOUT_SECONDS } = process.env

Expand Down Expand Up @@ -55,7 +55,7 @@ export async function startServer(app) {

function setupErrorHandling(app) {
// Setup exception reporting
app.use(Sentry.Handlers.errorHandler())
setupExpressErrorHandler(app)

// And error handling
app.get("*", (req, res, next) => {
Expand Down
2 changes: 1 addition & 1 deletion src/System/Boot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const Boot = track(undefined, {
document.body.setAttribute("data-test", "AppReady") //

if (getENV("NODE_ENV") === "production") {
setupSentryClient(sd)
setupSentryClient(sd.SENTRY_PUBLIC_DSN)
}
}, [])

Expand Down
27 changes: 27 additions & 0 deletions src/System/Router/serverRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as Sentry from "@sentry/node"
import { ArtsyRequest, ArtsyResponse } from "Server/middleware/artsyExpress"
import { createRelaySSREnvironment } from "System/Relay/createRelaySSREnvironment"
import { RouteProps } from "System/Router/Route"
Expand Down Expand Up @@ -123,6 +124,16 @@ export const setupServerRouter = async ({
relayEnvironment,
})

// Sentry names transactions according to their Express route.
// Overwrite this with the matched React route.
const pathname = farceResult.element.props?.renderArgs?.location?.pathname
const params = farceResult.element.props?.renderArgs?.params
const transactionName =
pathname && params ? nameSentryTransaction(pathname, params) : undefined
if (transactionName) {
Sentry.getCurrentScope().setTransactionName(transactionName)
}

const result = {
headTags,
html,
Expand All @@ -149,3 +160,19 @@ const isRedirect = (

export const __TEST_INTERNAL_SERVER_APP__ =
typeof jest !== "undefined" ? Symbol() : null

const nameSentryTransaction = <T extends Record<string, string>>(
path: string,
params: T
): string | undefined => {
try {
return Object.entries(params).reduce((result, [key, value]) => {
if (!value) return result
const regex = new RegExp(value, "g")
return result.replace(regex, `:${key}`)
}, path)
} catch (error) {
console.error(error)
return undefined
}
}
18 changes: 18 additions & 0 deletions src/instrument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as Sentry from "@sentry/node"
import { nodeProfilingIntegration } from "@sentry/profiling-node"
import { IGNORED_ERRORS } from "Server/analytics/sentryFilters"
import { SENTRY_PRIVATE_DSN, SENTRY_TRACING_ENABLED } from "Server/config"

const TRACING_CONFIG: Sentry.NodeOptions = {
integrations: [nodeProfilingIntegration()],
profilesSampleRate: 1.0, // Capture 100% of the transactions
tracesSampleRate: 1.0, // Capture 100% of the transactions
}

if (SENTRY_PRIVATE_DSN) {
Sentry.init({
dsn: SENTRY_PRIVATE_DSN,
ignoreErrors: IGNORED_ERRORS,
...(SENTRY_TRACING_ENABLED ? TRACING_CONFIG : {}),
})
}
17 changes: 0 additions & 17 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,8 @@ import {
SEGMENT_WRITE_KEY_SERVER,
IP_DENYLIST,
NODE_ENV,
SENTRY_PRIVATE_DSN,
} from "./Server/config"

// NOTE: Previoiusly, when deploying new Sentry SDK to prod we quickly start to
// see errors like "`CURRENT_USER` is undefined". We need more investigation
// because this only appears in prod, under load, and seems fine on staging.
import * as Sentry from "@sentry/node"

import { morganMiddleware } from "./Server/middleware/morgan"
import { ensureSslMiddleware } from "./Server/middleware/ensureSsl"
import { hstsMiddleware } from "./Server/middleware/hsts"
Expand All @@ -56,7 +50,6 @@ import { hardcodedRedirectsMiddleware } from "./Server/middleware/hardcodedRedir
import { localsMiddleware } from "./Server/middleware/locals"
import { sameOriginMiddleware } from "./Server/middleware/sameOrigin"
import { serverTimingHeaders } from "./Server/middleware/serverTimingHeaders"
import { IGNORED_ERRORS } from "./Server/analytics/sentryFilters"
import { featureFlagMiddleware } from "./Server/middleware/featureFlagMiddleware"
import {
UnleashFeatureFlagService,
Expand All @@ -71,16 +64,6 @@ export function initializeMiddleware(app) {

app.set("trust proxy", true)

// Setup error handling
if (SENTRY_PRIVATE_DSN) {
Sentry.init({
dsn: SENTRY_PRIVATE_DSN,
ignoreErrors: IGNORED_ERRORS,
})

app.use(Sentry.Handlers.requestHandler())
}

// Cookie parser
app.use(cookieParser())

Expand Down
2 changes: 2 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "instrument"

import { renderServerApp } from "System/Router/renderServerApp"
import express from "express"
import type {
Expand Down
Loading

0 comments on commit 27ad7c4

Please sign in to comment.