diff --git a/.changeset/fifty-papayas-look.md b/.changeset/fifty-papayas-look.md
new file mode 100644
index 00000000..a2c75c7c
--- /dev/null
+++ b/.changeset/fifty-papayas-look.md
@@ -0,0 +1,7 @@
+---
+'@hyperdx/api': patch
+'@hyperdx/app': patch
+---
+
+Fix Sentry exception rendering error in side panel, add Sentry SDK to API
+server.
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index fa25f4a9..66a7c6c7 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -176,6 +176,7 @@ services:
HDX_NODE_CONSOLE_CAPTURE: 1
HYPERDX_API_KEY: ${HYPERDX_API_KEY}
HYPERDX_LOG_LEVEL: ${HYPERDX_LOG_LEVEL}
+ SENTRY_DSN: ${SENTRY_DSN}
INGESTOR_API_URL: 'http://ingestor:8002'
MINER_API_URL: 'http://miner:5123'
MONGO_URI: 'mongodb://db:27017/hyperdx'
diff --git a/packages/api/package.json b/packages/api/package.json
index 9d06e132..c8d81b21 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -11,6 +11,7 @@
"@hyperdx/lucene": "^3.1.1",
"@hyperdx/node-logger": "^0.2.8",
"@hyperdx/node-opentelemetry": "^0.3.0",
+ "@sentry/node": "^7.85.0",
"@slack/webhook": "^6.1.0",
"compression": "^1.7.4",
"connect-mongo": "^4.6.0",
diff --git a/packages/api/src/api-app.ts b/packages/api/src/api-app.ts
index 053d59c6..9fb4a74d 100644
--- a/packages/api/src/api-app.ts
+++ b/packages/api/src/api-app.ts
@@ -1,3 +1,4 @@
+import * as Sentry from '@sentry/node';
import MongoStore from 'connect-mongo';
import compression from 'compression';
import express from 'express';
@@ -16,6 +17,22 @@ import { expressLogger } from './utils/logger';
const app: express.Application = express();
+if (config.SENTRY_DSN) {
+ Sentry.init({
+ dsn: config.SENTRY_DSN,
+ environment: config.NODE_ENV,
+ release: config.CODE_VERSION,
+ });
+
+ Sentry.setContext('hyperdx', {
+ serviceName: config.OTEL_SERVICE_NAME,
+ });
+}
+
+// RequestHandler creates a separate execution context using domains, so that every
+// transaction/span/breadcrumb is attached to its own Hub instance
+app.use(Sentry.Handlers.requestHandler());
+
const sess: session.SessionOptions & { cookie: session.CookieOptions } = {
resave: false,
saveUninitialized: false,
@@ -91,6 +108,9 @@ app.use('/webhooks', routers.webhooksRouter);
app.use('/api/v1', externalRoutersV1);
// ---------------------------------------------------------------------
+// The error handler must be before any other error middleware and after all controllers
+app.use(Sentry.Handlers.errorHandler());
+
// error handling
app.use(appErrorHandler);
diff --git a/packages/api/src/config.ts b/packages/api/src/config.ts
index 7720cc7c..7516fa7b 100644
--- a/packages/api/src/config.ts
+++ b/packages/api/src/config.ts
@@ -13,6 +13,7 @@ export const FRONTEND_URL = env.FRONTEND_URL as string;
export const HYPERDX_API_KEY = env.HYPERDX_API_KEY as string;
export const HYPERDX_LOG_LEVEL = env.HYPERDX_LOG_LEVEL as string;
export const INGESTOR_API_URL = env.INGESTOR_API_URL as string;
+export const SENTRY_DSN = env.SENTRY_DSN as string;
export const IS_CI = NODE_ENV === 'ci';
export const IS_DEV = NODE_ENV === 'development';
export const IS_PROD = NODE_ENV === 'production';
diff --git a/packages/app/src/LogSidePanel.tsx b/packages/app/src/LogSidePanel.tsx
index 27783a11..332adf05 100644
--- a/packages/app/src/LogSidePanel.tsx
+++ b/packages/app/src/LogSidePanel.tsx
@@ -492,7 +492,6 @@ function isExceptionSpan({ logData }: { logData: any }) {
function TraceSubpanel({
logData,
- isException,
onClose,
onPropertyAddClick,
generateChartUrl,
@@ -501,7 +500,6 @@ function TraceSubpanel({
toggleColumn,
}: {
logData: any;
- isException: boolean;
onClose: () => void;
generateSearchUrl: (query?: string, timeRange?: [Date, Date]) => string;
generateChartUrl: (config: {
@@ -585,6 +583,11 @@ function TraceSubpanel({
}
}, [selectedLogData]);
+ const isSelectedLogDataException = useMemo(
+ () => isExceptionSpan({ logData: selectedLogData }),
+ [selectedLogData],
+ );
+
// Clear search query when we close the panel
// TODO: This doesn't work because it breaks navigation to things like the sessions page,
// probably due to a race condition. Need to fix later.
@@ -681,7 +684,7 @@ function TraceSubpanel({
/>
)}
- {isException && (
+ {isSelectedLogDataException && (
{
console.error(err);
@@ -699,7 +702,7 @@ function TraceSubpanel({
/>
)}
- {!isException && (
+ {!isSelectedLogDataException && (
{
console.error(err);
@@ -2260,7 +2263,6 @@ export default function LogSidePanel({
>