sentry-desktop-setup
Configure Sentry for comprehensive desktop application monitoring including crash reporting, error tracking, performance monitoring, and release health. This skill sets up Sentry SDK integration for Electron and native desktop applications with source maps, session tracking, and custom instrumentation.
Capabilities
- Configure Sentry SDK for Electron (main + renderer processes)
- Set up native crash reporting with minidump support
- Configure source map uploads for readable stack traces
- Implement performance monitoring and tracing
- Set up release tracking with commit integration
- Configure session tracking for release health
- Implement custom error boundaries and handlers
- Set up user feedback collection
- Configure environment-specific DSNs and sampling
Input Schema
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Path to the desktop application project"
},
"framework": {
"enum": ["electron", "tauri", "qt", "wpf", "macos-native"],
"default": "electron"
},
"sentryConfig": {
"type": "object",
"properties": {
"dsn": { "type": "string", "description": "Sentry DSN (or use env variable)" },
"organization": { "type": "string" },
"project": { "type": "string" },
"environment": { "type": "string", "default": "production" }
},
"required": ["organization", "project"]
},
"features": {
"type": "array",
"items": {
"enum": [
"crashReporting",
"errorTracking",
"performanceMonitoring",
"sessionTracking",
"releaseHealth",
"sourceMaps",
"userFeedback",
"customContext",
"breadcrumbs",
"nativeCrashes"
]
},
"default": ["crashReporting", "errorTracking", "performanceMonitoring", "sourceMaps"]
},
"sampling": {
"type": "object",
"properties": {
"tracesSampleRate": { "type": "number", "default": 0.1 },
"errorSampleRate": { "type": "number", "default": 1.0 },
"profilesSampleRate": { "type": "number", "default": 0.1 }
}
},
"privacy": {
"type": "object",
"properties": {
"scrubData": { "type": "boolean", "default": true },
"scrubFields": { "type": "array", "items": { "type": "string" } },
"ipAddress": { "enum": ["auto", "off"], "default": "off" }
}
},
"ci": {
"type": "object",
"properties": {
"generateWorkflow": { "type": "boolean", "default": true },
"provider": { "enum": ["github-actions", "azure-devops", "circleci"] }
}
}
},
"required": ["projectPath", "sentryConfig"]
}
Output Schema
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"type": { "enum": ["config", "main", "renderer", "utils", "ci"] }
}
}
},
"commands": {
"type": "object",
"properties": {
"uploadSourceMaps": { "type": "string" },
"createRelease": { "type": "string" },
"testIntegration": { "type": "string" }
}
},
"envVariables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"description": { "type": "string" }
}
}
}
},
"required": ["success", "files"]
}
Generated File Structure
src/
main/
sentry/
sentry-main.ts # Main process Sentry init
crash-reporter.ts # Native crash handling
ipc-handlers.ts # Sentry IPC handlers
renderer/
sentry/
sentry-renderer.ts # Renderer Sentry init
error-boundary.tsx # React error boundary
user-feedback.ts # Feedback dialog
shared/
sentry-config.ts # Shared configuration
context-utils.ts # Context helpers
scripts/
sentry-release.js # Release script
.github/workflows/
sentry-release.yml # CI workflow
Code Templates
Main Process Sentry Configuration
// src/main/sentry/sentry-main.ts
import * as Sentry from '@sentry/electron/main';
import { app } from 'electron';
export function initSentryMain() {
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'production',
release: `${app.getName()}@${app.getVersion()}`,
// Performance monitoring
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
profilesSampleRate: 0.1,
// Session tracking
autoSessionTracking: true,
// Native crash reporting
enableNative: true,
// Privacy
beforeSend(event) {
// Scrub sensitive data
if (event.user) {
delete event.user.ip_address;
}
return event;
},
// Integrations
integrations: [
Sentry.electronMinidumpIntegration(),
Sentry.mainProcessIntegration(),
],
});
// Set app context
Sentry.setContext('app', {
name: app.getName(),
version: app.getVersion(),
platform: process.platform,
arch: process.arch,
electron: process.versions.electron,
});
}
export function captureMainException(error: Error, context?: Record<string, unknown>) {
Sentry.withScope((scope) => {
scope.setTag('process', 'main');
if (context) {
scope.setExtras(context);
}
Sentry.captureException(error);
});
}
Renderer Process Sentry Configuration
// src/renderer/sentry/sentry-renderer.ts
import * as Sentry from '@sentry/electron/renderer';
import { init as sentryReactInit, browserTracingIntegration } from '@sentry/react';
export function initSentryRenderer() {
sentryReactInit({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'production',
release: window.electronAPI.getAppVersion(),
// Performance
tracesSampleRate: 0.1,
// Integrations
integrations: [
browserTracingIntegration(),
Sentry.electronRendererIntegration(),
],
// Breadcrumbs
beforeBreadcrumb(breadcrumb) {
// Filter out noisy breadcrumbs
if (breadcrumb.category === 'console' && breadcrumb.level === 'debug') {
return null;
}
return breadcrumb;
},
});
// Add custom context
Sentry.setTag('renderer', 'main-window');
}
// React Error Boundary wrapper
export function withSentryErrorBoundary<P extends object>(
Component: React.ComponentType<P>,
fallback: React.ReactNode
) {
return Sentry.withErrorBoundary(Component, {
fallback,
showDialog: true,
});
}
React Error Boundary
// src/renderer/sentry/error-boundary.tsx
import React from 'react';
import * as Sentry from '@sentry/react';
interface Props {
children: React.ReactNode;
fallback?: React.ReactNode;
}
interface State {
hasError: boolean;
eventId: string | null;
}
export class ErrorBoundary extends React.Component<Props, State> {
state: State = { hasError: false, eventId: null };
static getDerivedStateFromError(): State {
return { hasError: true, eventId: null };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
Sentry.withScope((scope) => {
scope.setExtras({
componentStack: errorInfo.componentStack,
});
const eventId = Sentry.captureException(error);
this.setState({ eventId });
});
}
handleReportClick = () => {
if (this.state.eventId) {
Sentry.showReportDialog({ eventId: this.state.eventId });
}
};
handleReload = () => {
window.location.reload();
};
render() {
if (this.state.hasError) {
return (
this.props.fallback || (
<div className="error-boundary">
<h2>Something went wrong</h2>
<p>We've been notif