mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
fix(ui): skip Sentry initialization when DSN is not configured (#9368)
This commit is contained in:
@@ -11,105 +11,110 @@
|
||||
import { browserTracingIntegration } from "@sentry/browser";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
const isDevelopment = process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT === "local";
|
||||
const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN;
|
||||
|
||||
/**
|
||||
* Initialize Sentry error tracking and performance monitoring
|
||||
*
|
||||
* This setup includes:
|
||||
* - Performance monitoring with Web Vitals tracking (LCP, FID, CLS, INP)
|
||||
* - Long task detection for UI-blocking operations
|
||||
* - beforeSend hook to filter noise
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
// Only initialize Sentry if DSN is configured
|
||||
if (SENTRY_DSN) {
|
||||
const isDevelopment = process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT === "local";
|
||||
|
||||
// 🌍 Environment - Separate dev errors from production
|
||||
environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT || "local",
|
||||
/**
|
||||
* Initialize Sentry error tracking and performance monitoring
|
||||
*
|
||||
* This setup includes:
|
||||
* - Performance monitoring with Web Vitals tracking (LCP, FID, CLS, INP)
|
||||
* - Long task detection for UI-blocking operations
|
||||
* - beforeSend hook to filter noise
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: SENTRY_DSN,
|
||||
|
||||
// 📦 Release - Track which version has the error
|
||||
release: process.env.NEXT_PUBLIC_PROWLER_RELEASE_VERSION,
|
||||
// 🌍 Environment - Separate dev errors from production
|
||||
environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT || "local",
|
||||
|
||||
// 🐛 Debug - Detailed logs in development console
|
||||
debug: isDevelopment,
|
||||
// 📦 Release - Track which version has the error
|
||||
release: process.env.NEXT_PUBLIC_PROWLER_RELEASE_VERSION,
|
||||
|
||||
// 📊 Sample Rates - Performance monitoring
|
||||
// 100% in dev (test everything), 50% in production (balance visibility with costs)
|
||||
tracesSampleRate: isDevelopment ? 1.0 : 0.5,
|
||||
profilesSampleRate: isDevelopment ? 1.0 : 0.5,
|
||||
// 🐛 Debug - Detailed logs in development console
|
||||
debug: isDevelopment,
|
||||
|
||||
// 🔌 Integrations
|
||||
integrations: [
|
||||
// 📊 Performance Monitoring: Core Web Vitals + RUM
|
||||
// Tracks LCP, FID, CLS, INP
|
||||
// Real User Monitoring captures actual user experience, not synthetic tests
|
||||
browserTracingIntegration({
|
||||
enableLongTask: true, // Detect tasks that block UI (>50ms)
|
||||
enableInp: true, // Interaction to Next Paint (Core Web Vital)
|
||||
}),
|
||||
],
|
||||
// 📊 Sample Rates - Performance monitoring
|
||||
// 100% in dev (test everything), 50% in production (balance visibility with costs)
|
||||
tracesSampleRate: isDevelopment ? 1.0 : 0.5,
|
||||
profilesSampleRate: isDevelopment ? 1.0 : 0.5,
|
||||
|
||||
// 🎣 beforeSend Hook - Filter or modify events before sending to Sentry
|
||||
ignoreErrors: [
|
||||
// Browser extensions
|
||||
"top.GLOBALS",
|
||||
// Random network errors
|
||||
"Network request failed",
|
||||
"NetworkError",
|
||||
"Failed to fetch",
|
||||
// User canceled actions
|
||||
"AbortError",
|
||||
"Non-Error promise rejection captured",
|
||||
// NextAuth expected errors
|
||||
"NEXT_REDIRECT",
|
||||
// ResizeObserver errors (common browser quirk, not real bugs)
|
||||
"ResizeObserver",
|
||||
],
|
||||
// 🔌 Integrations
|
||||
integrations: [
|
||||
// 📊 Performance Monitoring: Core Web Vitals + RUM
|
||||
// Tracks LCP, FID, CLS, INP
|
||||
// Real User Monitoring captures actual user experience, not synthetic tests
|
||||
browserTracingIntegration({
|
||||
enableLongTask: true, // Detect tasks that block UI (>50ms)
|
||||
enableInp: true, // Interaction to Next Paint (Core Web Vital)
|
||||
}),
|
||||
],
|
||||
|
||||
beforeSend(event, hint) {
|
||||
// Filter out noise: ResizeObserver errors (common browser quirk, not real bugs)
|
||||
if (event.message?.includes("ResizeObserver")) {
|
||||
return null; // Don't send to Sentry
|
||||
}
|
||||
// 🎣 beforeSend Hook - Filter or modify events before sending to Sentry
|
||||
ignoreErrors: [
|
||||
// Browser extensions
|
||||
"top.GLOBALS",
|
||||
// Random network errors
|
||||
"Network request failed",
|
||||
"NetworkError",
|
||||
"Failed to fetch",
|
||||
// User canceled actions
|
||||
"AbortError",
|
||||
"Non-Error promise rejection captured",
|
||||
// NextAuth expected errors
|
||||
"NEXT_REDIRECT",
|
||||
// ResizeObserver errors (common browser quirk, not real bugs)
|
||||
"ResizeObserver",
|
||||
],
|
||||
|
||||
// Filter out non-actionable errors
|
||||
if (event.exception) {
|
||||
const error = hint.originalException;
|
||||
|
||||
// Don't send cancelled requests
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"name" in error &&
|
||||
error.name === "AbortError"
|
||||
) {
|
||||
return null;
|
||||
beforeSend(event, hint) {
|
||||
// Filter out noise: ResizeObserver errors (common browser quirk, not real bugs)
|
||||
if (event.message?.includes("ResizeObserver")) {
|
||||
return null; // Don't send to Sentry
|
||||
}
|
||||
|
||||
// Add additional context for API errors
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string" &&
|
||||
error.message.includes("Request failed")
|
||||
) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "api_error",
|
||||
};
|
||||
// Filter out non-actionable errors
|
||||
if (event.exception) {
|
||||
const error = hint.originalException;
|
||||
|
||||
// Don't send cancelled requests
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"name" in error &&
|
||||
error.name === "AbortError"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add additional context for API errors
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string" &&
|
||||
error.message.includes("Request failed")
|
||||
) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "api_error",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return event; // Send to Sentry
|
||||
},
|
||||
});
|
||||
|
||||
// 👤 Set user context (identifies who experienced the error)
|
||||
// In production, this will be updated after authentication
|
||||
if (isDevelopment) {
|
||||
Sentry.setUser({
|
||||
id: "dev-user",
|
||||
return event; // Send to Sentry
|
||||
},
|
||||
});
|
||||
|
||||
// 👤 Set user context (identifies who experienced the error)
|
||||
// In production, this will be updated after authentication
|
||||
if (isDevelopment) {
|
||||
Sentry.setUser({
|
||||
id: "dev-user",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,14 @@
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
const SENTRY_DSN = process.env.SENTRY_DSN;
|
||||
|
||||
export async function register() {
|
||||
// Skip Sentry initialization if DSN is not configured
|
||||
if (!SENTRY_DSN) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The Sentry SDK automatically loads the appropriate config based on runtime
|
||||
if (process.env.NEXT_RUNTIME === "nodejs") {
|
||||
await import("./sentry/sentry.server.config");
|
||||
@@ -27,4 +34,7 @@ export async function register() {
|
||||
}
|
||||
}
|
||||
|
||||
export const onRequestError = Sentry.captureRequestError;
|
||||
// Only capture request errors if Sentry is configured
|
||||
export const onRequestError = SENTRY_DSN
|
||||
? Sentry.captureRequestError
|
||||
: undefined;
|
||||
|
||||
@@ -1,64 +1,69 @@
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
const isProduction = process.env.SENTRY_ENVIRONMENT === "pro";
|
||||
const SENTRY_DSN = process.env.SENTRY_DSN;
|
||||
|
||||
/**
|
||||
* Edge runtime Sentry configuration
|
||||
*
|
||||
* Edge runtime has stricter constraints than Node.js:
|
||||
* - Limited execution time (~10-30 seconds)
|
||||
* - Lower memory availability
|
||||
* - Reduced sample rates to minimize overhead
|
||||
* - No complex integrations
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
// Only initialize Sentry if DSN is configured
|
||||
if (SENTRY_DSN) {
|
||||
const isProduction = process.env.SENTRY_ENVIRONMENT === "pro";
|
||||
|
||||
// 🌍 Environment configuration
|
||||
environment: process.env.SENTRY_ENVIRONMENT || "local",
|
||||
/**
|
||||
* Edge runtime Sentry configuration
|
||||
*
|
||||
* Edge runtime has stricter constraints than Node.js:
|
||||
* - Limited execution time (~10-30 seconds)
|
||||
* - Lower memory availability
|
||||
* - Reduced sample rates to minimize overhead
|
||||
* - No complex integrations
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: SENTRY_DSN,
|
||||
|
||||
// 📦 Release tracking
|
||||
release: process.env.SENTRY_RELEASE,
|
||||
// 🌍 Environment configuration
|
||||
environment: process.env.SENTRY_ENVIRONMENT || "local",
|
||||
|
||||
// 📊 Sample Rates - Reduced for edge runtime constraints
|
||||
// 50% in dev, 25% in production (edge has lower overhead limits than server)
|
||||
tracesSampleRate: isProduction ? 0.25 : 0.5,
|
||||
// 📦 Release tracking
|
||||
release: process.env.SENTRY_RELEASE,
|
||||
|
||||
// 🔌 Integrations - Edge runtime doesn't support all integrations
|
||||
integrations: [],
|
||||
// 📊 Sample Rates - Reduced for edge runtime constraints
|
||||
// 50% in dev, 25% in production (edge has lower overhead limits than server)
|
||||
tracesSampleRate: isProduction ? 0.25 : 0.5,
|
||||
|
||||
// 🎣 Filter expected errors - Don't send noise to Sentry
|
||||
ignoreErrors: [
|
||||
// NextAuth redirect errors - Expected behavior in auth flow
|
||||
"NEXT_REDIRECT",
|
||||
"NEXT_NOT_FOUND",
|
||||
// Expected HTTP errors - Expected when users lack permissions
|
||||
"401", // Unauthorized - expected when token expires
|
||||
"403", // Forbidden - expected when no permissions
|
||||
"404", // Not Found - expected for missing resources
|
||||
],
|
||||
// 🔌 Integrations - Edge runtime doesn't support all integrations
|
||||
integrations: [],
|
||||
|
||||
beforeSend(event, hint) {
|
||||
// Add edge runtime context for debugging
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
runtime: "edge",
|
||||
};
|
||||
// 🎣 Filter expected errors - Don't send noise to Sentry
|
||||
ignoreErrors: [
|
||||
// NextAuth redirect errors - Expected behavior in auth flow
|
||||
"NEXT_REDIRECT",
|
||||
"NEXT_NOT_FOUND",
|
||||
// Expected HTTP errors - Expected when users lack permissions
|
||||
"401", // Unauthorized - expected when token expires
|
||||
"403", // Forbidden - expected when no permissions
|
||||
"404", // Not Found - expected for missing resources
|
||||
],
|
||||
|
||||
const error = hint.originalException;
|
||||
beforeSend(event, hint) {
|
||||
// Add edge runtime context for debugging
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
runtime: "edge",
|
||||
};
|
||||
|
||||
// Don't send NextAuth expected errors
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string" &&
|
||||
error.message.includes("NEXT_REDIRECT")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const error = hint.originalException;
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
// Don't send NextAuth expected errors
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string" &&
|
||||
error.message.includes("NEXT_REDIRECT")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,80 +1,85 @@
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
const isProduction = process.env.SENTRY_ENVIRONMENT === "pro";
|
||||
const SENTRY_DSN = process.env.SENTRY_DSN;
|
||||
|
||||
/**
|
||||
* Server-side Sentry configuration
|
||||
*
|
||||
* This setup includes:
|
||||
* - Performance monitoring for server-side operations
|
||||
* - Error tracking for API routes and server actions
|
||||
* - beforeSend hook to filter noise and add context
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
// Only initialize Sentry if DSN is configured
|
||||
if (SENTRY_DSN) {
|
||||
const isProduction = process.env.SENTRY_ENVIRONMENT === "pro";
|
||||
|
||||
// 🌍 Environment configuration
|
||||
environment: process.env.SENTRY_ENVIRONMENT || "local",
|
||||
/**
|
||||
* Server-side Sentry configuration
|
||||
*
|
||||
* This setup includes:
|
||||
* - Performance monitoring for server-side operations
|
||||
* - Error tracking for API routes and server actions
|
||||
* - beforeSend hook to filter noise and add context
|
||||
*/
|
||||
Sentry.init({
|
||||
// 📍 DSN - Data Source Name (identifies your Sentry project)
|
||||
dsn: SENTRY_DSN,
|
||||
|
||||
// 📦 Release tracking
|
||||
release: process.env.SENTRY_RELEASE,
|
||||
// 🌍 Environment configuration
|
||||
environment: process.env.SENTRY_ENVIRONMENT || "local",
|
||||
|
||||
// 📊 Sample Rates - Performance monitoring
|
||||
// 100% in dev (test everything), 50% in production (balance visibility with costs)
|
||||
tracesSampleRate: isProduction ? 0.5 : 1.0,
|
||||
profilesSampleRate: isProduction ? 0.5 : 1.0,
|
||||
// 📦 Release tracking
|
||||
release: process.env.SENTRY_RELEASE,
|
||||
|
||||
// 🔌 Integrations
|
||||
integrations: [
|
||||
Sentry.extraErrorDataIntegration({
|
||||
depth: 5, // Include up to 5 levels of nested objects
|
||||
}),
|
||||
],
|
||||
// 📊 Sample Rates - Performance monitoring
|
||||
// 100% in dev (test everything), 50% in production (balance visibility with costs)
|
||||
tracesSampleRate: isProduction ? 0.5 : 1.0,
|
||||
profilesSampleRate: isProduction ? 0.5 : 1.0,
|
||||
|
||||
// 🎣 Filter expected errors - Don't send noise to Sentry
|
||||
ignoreErrors: [
|
||||
// NextAuth redirect errors - Expected behavior
|
||||
"NEXT_REDIRECT",
|
||||
"NEXT_NOT_FOUND",
|
||||
// Expected HTTP errors - Expected when users lack permissions
|
||||
"401", // Unauthorized
|
||||
"403", // Forbidden
|
||||
"404", // Not Found
|
||||
],
|
||||
// 🔌 Integrations
|
||||
integrations: [
|
||||
Sentry.extraErrorDataIntegration({
|
||||
depth: 5, // Include up to 5 levels of nested objects
|
||||
}),
|
||||
],
|
||||
|
||||
beforeSend(event, hint) {
|
||||
// Add server context and tag errors appropriately
|
||||
if (event.exception) {
|
||||
const error = hint.originalException;
|
||||
// 🎣 Filter expected errors - Don't send noise to Sentry
|
||||
ignoreErrors: [
|
||||
// NextAuth redirect errors - Expected behavior
|
||||
"NEXT_REDIRECT",
|
||||
"NEXT_NOT_FOUND",
|
||||
// Expected HTTP errors - Expected when users lack permissions
|
||||
"401", // Unauthorized
|
||||
"403", // Forbidden
|
||||
"404", // Not Found
|
||||
],
|
||||
|
||||
// Tag API errors for better filtering in Sentry dashboard
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string"
|
||||
) {
|
||||
if (error.message.includes("Server error")) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "server_error",
|
||||
severity: "high",
|
||||
};
|
||||
} else if (error.message.includes("Request failed")) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "api_error",
|
||||
};
|
||||
}
|
||||
beforeSend(event, hint) {
|
||||
// Add server context and tag errors appropriately
|
||||
if (event.exception) {
|
||||
const error = hint.originalException;
|
||||
|
||||
// Don't send NextAuth expected errors
|
||||
if (error.message.includes("NEXT_REDIRECT")) {
|
||||
return null;
|
||||
// Tag API errors for better filtering in Sentry dashboard
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
"message" in error &&
|
||||
typeof error.message === "string"
|
||||
) {
|
||||
if (error.message.includes("Server error")) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "server_error",
|
||||
severity: "high",
|
||||
};
|
||||
} else if (error.message.includes("Request failed")) {
|
||||
event.tags = {
|
||||
...event.tags,
|
||||
error_type: "api_error",
|
||||
};
|
||||
}
|
||||
|
||||
// Don't send NextAuth expected errors
|
||||
if (error.message.includes("NEXT_REDIRECT")) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
return event;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user