feat(sentry): enhance Sentry integration with user tracking and error handling improvements

This commit is contained in:
sharath 2025-05-27 10:04:17 +00:00
parent eac741e867
commit 03c95fa346
No known key found for this signature in database
9 changed files with 99 additions and 15 deletions

View File

@ -1,6 +1,7 @@
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import sentry
from contextlib import asynccontextmanager
from agentpress.thread_manager import ThreadManager
from services.supabase import DBConnection
@ -12,18 +13,6 @@ from utils.logger import logger
import uuid
import time
from collections import OrderedDict
import sentry_sdk
import os
sentry_dsn = os.getenv("SENTRY_DSN", None)
if sentry_dsn:
sentry_sdk.init(
dsn=sentry_dsn,
send_default_pii=True,
_experiments={
"enable_logs": True,
},
)
# Import the agent API module
from agent import api as agent_api

View File

@ -1,3 +1,4 @@
import sentry
import asyncio
import json
import traceback
@ -56,6 +57,8 @@ async def run_agent_background(
"""Run the agent in the background using Redis for state."""
await initialize()
sentry.sentry.set_tag("thread_id", thread_id)
logger.info(f"Starting background agent run: {agent_run_id} for thread: {thread_id} (Instance: {instance_id})")
logger.info(f"🚀 Using model: {model_name} (thinking: {enable_thinking}, reasoning_effort: {reasoning_effort})")

17
backend/sentry.py Normal file
View File

@ -0,0 +1,17 @@
import sentry_sdk
from sentry_sdk.integrations.dramatiq import DramatiqIntegration
import os
sentry_dsn = os.getenv("SENTRY_DSN", None)
if sentry_dsn:
sentry_sdk.init(
dsn=sentry_dsn,
integrations=[DramatiqIntegration()],
traces_sample_rate=0.1,
send_default_pii=True,
_experiments={
"enable_logs": True,
},
)
sentry = sentry_sdk

View File

@ -1,3 +1,4 @@
import sentry
from fastapi import HTTPException, Request
from typing import Optional
import jwt
@ -45,7 +46,8 @@ async def get_current_user_id_from_jwt(request: Request) -> str:
detail="Invalid token payload",
headers={"WWW-Authenticate": "Bearer"}
)
sentry.sentry.set_user({ "id": user_id })
return user_id
except PyJWTError:
@ -119,6 +121,7 @@ async def get_user_id_from_stream_auth(
# For Supabase JWT, we just need to decode and extract the user ID
payload = jwt.decode(token, options={"verify_signature": False})
user_id = payload.get('sub')
sentry.sentry.set_user({ "id": user_id })
if user_id:
return user_id
except Exception:

View File

@ -24,6 +24,8 @@ RUN npm install
# Copy the frontend code
COPY . .
ENV NEXT_PUBLIC_VERCEL_ENV production
RUN npm run build
EXPOSE 3000

View File

@ -13,6 +13,7 @@ import { checkApiHealth } from '@/lib/api';
import { MaintenancePage } from '@/components/maintenance/maintenance-page';
import { DeleteOperationProvider } from '@/contexts/DeleteOperationContext';
import { StatusOverlay } from '@/components/ui/status-overlay';
import { VSentry } from '@/components/sentry';
interface DashboardLayoutProps {
children: React.ReactNode;
@ -99,6 +100,7 @@ export default function DashboardLayout({ children }: DashboardLayoutProps) {
onOpenChange={setShowMaintenanceAlert}
closeable={true}
/>
<VSentry />
{/* Status overlay for deletion operations */}
<StatusOverlay />

View File

@ -0,0 +1,45 @@
const SENTRY_URL = new URL(
process.env.NEXT_PUBLIC_SENTRY_DSN ?? 'https://example.com/abc',
);
const SENTRY_HOST = SENTRY_URL.hostname;
const SENTRY_PROJECT_ID = SENTRY_URL.pathname.split('/').pop();
export const POST = async (req: Request) => {
try {
if (!process.env.NEXT_PUBLIC_SENTRY_DSN) {
return Response.json(
{ error: 'Sentry is not configured' },
{ status: 500 },
);
}
const envelopeBytes = await req.arrayBuffer();
const envelope = new TextDecoder().decode(envelopeBytes);
const piece = envelope.split('\n')[0];
const header = JSON.parse(piece) as { dsn: string };
const dsn = new URL(header.dsn);
const project_id = dsn.pathname.replace('/', '');
if (dsn.hostname !== SENTRY_HOST) {
throw new Error(`Invalid sentry hostname: ${dsn.hostname}`);
}
if (project_id !== SENTRY_PROJECT_ID) {
throw new Error(`Invalid sentry project id: ${project_id}`);
}
const upstream_sentry_url = `https://${SENTRY_HOST}/api/${project_id}/envelope/`;
const response = await fetch(upstream_sentry_url, {
body: envelopeBytes,
method: 'POST',
});
return response;
} catch (e) {
console.error('error tunneling to sentry', e);
return Response.json(
{ error: 'error tunneling to sentry' },
{ status: 500 },
);
}
};

View File

@ -0,0 +1,17 @@
'use client';
import { useEffect } from 'react';
import * as Sentry from '@sentry/nextjs';
import { useAuth } from '../AuthProvider';
export const VSentry: React.FC = () => {
const { user } = useAuth();
useEffect(() => {
if (!document) return;
const scope = Sentry.getCurrentScope();
if (!user) scope.setUser(null);
else scope.setUser({ email: user.email, id: user.id });
}, [user]);
return null;
};

View File

@ -1,5 +1,11 @@
export const SentryConfig = {
import { consoleLoggingIntegration, type init } from '@sentry/nextjs';
type SentryConfig = Parameters<typeof init>[0];
export const SentryConfig: SentryConfig = {
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1,
tracesSampleRate: 0.1,
debug: false,
_experiments: { enableLogs: true },
integrations: [consoleLoggingIntegration()],
};