Development tools, debugging utilities, crash reporting, and performance monitoring for building and maintaining Electron applications.
Crash reporting system for collecting and submitting crash information.
/**
* Submit crash reports to a remote server
*/
interface CrashReporter {
/** Starts crash reporting */
start(options: CrashReporterStartOptions): void;
/** Returns the last crash report */
getLastCrashReport(): CrashReport | null;
/** Returns all uploaded crash reports */
getUploadedReports(): CrashReport[];
/** Returns the date and ID of the last crash report */
getUploadToServer(): boolean;
/** Sets extra key-value pairs that will be sent along with crash reports */
addExtraParameter(key: string, value: string): void;
/** Removes an extra parameter that was set with addExtraParameter */
removeExtraParameter(key: string): void;
/** Returns an object with all extra parameters that will be sent with crash reports */
getParameters(): Record<string, string>;
}
declare const crashReporter: CrashReporter;Usage Examples:
const { crashReporter, app } = require('electron');
// Setup crash reporting
function setupCrashReporting() {
crashReporter.start({
productName: 'MyElectronApp',
companyName: 'MyCompany',
submitURL: 'https://crashes.myapp.com/submit',
uploadToServer: true,
ignoreSystemCrashHandler: false,
rateLimit: true,
compress: true,
extra: {
'app-version': app.getVersion(),
'platform': process.platform,
'user-id': getUserId(),
'session-id': getSessionId()
}
});
console.log('Crash reporting initialized');
}
// Add runtime information
function addCrashMetadata() {
crashReporter.addExtraParameter('memory-usage', process.memoryUsage().heapUsed.toString());
crashReporter.addExtraParameter('uptime', process.uptime().toString());
crashReporter.addExtraParameter('node-version', process.version);
crashReporter.addExtraParameter('electron-version', process.versions.electron);
}
// Get crash reports
function getCrashReports() {
const lastReport = crashReporter.getLastCrashReport();
if (lastReport) {
console.log('Last crash:', lastReport);
}
const uploadedReports = crashReporter.getUploadedReports();
console.log('Uploaded crash reports:', uploadedReports.length);
return { lastReport, uploadedReports };
}
// Simulate crash for testing
function simulateCrash() {
if (process.env.NODE_ENV === 'development') {
process.crash();
}
}Performance tracing and profiling for analyzing application performance.
/**
* Collect tracing data from Chromium's content module for finding performance bottlenecks and slow operations
*/
interface ContentTracing {
/** Get a set of category groups */
getCategories(): Promise<string[]>;
/** Start recording on all processes */
startRecording(options: TraceCategoriesAndOptions | TraceConfig): Promise<void>;
/** Stop recording on all processes */
stopRecording(resultFilePath?: string): Promise<string>;
/** Start monitoring on all processes */
startMonitoring(options: TraceCategoriesAndOptions): Promise<void>;
/** Stop monitoring on all processes */
stopMonitoring(): Promise<void>;
/** Capture monitoring snapshot on all processes */
captureMonitoringSnapshot(resultFilePath?: string): Promise<string>;
/** Get the maximum usage across processes of trace buffer as a percentage of the full state */
getTraceBufferUsage(): Promise<TraceBufferUsageReturnValue>;
}
declare const contentTracing: ContentTracing;Usage Examples:
const { contentTracing } = require('electron');
const fs = require('fs');
const path = require('path');
// Performance profiling
async function startPerformanceProfiling() {
try {
// Get available categories
const categories = await contentTracing.getCategories();
console.log('Available trace categories:', categories);
// Start recording with specific categories
await contentTracing.startRecording({
categoryFilter: 'blink,cc,gpu,renderer.scheduler,v8,disabled-by-default-devtools.timeline',
traceOptions: 'record-continuously,enable-sampling,enable-systrace'
});
console.log('Performance tracing started');
// Run for 10 seconds then stop
setTimeout(async () => {
await stopPerformanceProfiling();
}, 10000);
} catch (error) {
console.error('Failed to start tracing:', error);
}
}
async function stopPerformanceProfiling() {
try {
const tracePath = path.join(__dirname, 'traces', `trace-${Date.now()}.json`);
const resultPath = await contentTracing.stopRecording(tracePath);
console.log('Performance trace saved to:', resultPath);
// Analyze trace file
analyzePerfTrace(resultPath);
} catch (error) {
console.error('Failed to stop tracing:', error);
}
}
// Memory monitoring
async function monitorMemoryUsage() {
try {
await contentTracing.startMonitoring({
categoryFilter: 'blink.console,disabled-by-default-memory-infra',
traceOptions: 'record-continuously'
});
console.log('Memory monitoring started');
// Capture snapshots every 5 seconds
const interval = setInterval(async () => {
try {
const snapshotPath = path.join(__dirname, 'memory-snapshots', `memory-${Date.now()}.json`);
await contentTracing.captureMonitoringSnapshot(snapshotPath);
console.log('Memory snapshot saved:', snapshotPath);
} catch (error) {
console.error('Failed to capture memory snapshot:', error);
}
}, 5000);
// Stop after 1 minute
setTimeout(async () => {
clearInterval(interval);
await contentTracing.stopMonitoring();
console.log('Memory monitoring stopped');
}, 60000);
} catch (error) {
console.error('Failed to start memory monitoring:', error);
}
}
// Check trace buffer usage
async function checkTraceBufferUsage() {
try {
const usage = await contentTracing.getTraceBufferUsage();
console.log('Trace buffer usage:', usage);
if (usage.percentFull > 80) {
console.warn('Trace buffer is getting full!');
}
return usage;
} catch (error) {
console.error('Failed to get trace buffer usage:', error);
return null;
}
}
// Analyze performance trace
function analyzePerfTrace(tracePath) {
try {
const traceData = JSON.parse(fs.readFileSync(tracePath, 'utf8'));
// Basic analysis
const events = traceData.traceEvents || [];
const totalEvents = events.length;
const timespan = getTraceTimespan(events);
console.log(`Trace analysis:
- Total events: ${totalEvents}
- Timespan: ${timespan}ms
- Categories: ${getUniqueCategories(events).join(', ')}`);
// Find slow operations
const slowOperations = findSlowOperations(events);
if (slowOperations.length > 0) {
console.log('Slow operations detected:', slowOperations);
}
} catch (error) {
console.error('Failed to analyze trace:', error);
}
}
function getTraceTimespan(events) {
if (events.length === 0) return 0;
const timestamps = events.map(e => e.ts).filter(ts => ts);
return (Math.max(...timestamps) - Math.min(...timestamps)) / 1000;
}
function getUniqueCategories(events) {
const categories = new Set();
events.forEach(event => {
if (event.cat) {
event.cat.split(',').forEach(cat => categories.add(cat.trim()));
}
});
return Array.from(categories);
}
function findSlowOperations(events, threshold = 16) {
return events
.filter(event => event.dur && event.dur > threshold * 1000) // Convert to microseconds
.map(event => ({
name: event.name,
category: event.cat,
duration: event.dur / 1000, // Convert to milliseconds
timestamp: event.ts
}))
.sort((a, b) => b.duration - a.duration)
.slice(0, 10); // Top 10 slowest operations
}Network logging for debugging network issues.
/**
* Logging network events for a session
*/
interface NetLog {
/** Starts recording network events to path */
startLogging(path: string, options?: NetLogStartLoggingOptions): Promise<void>;
/** Stops recording network events */
stopLogging(): Promise<void>;
/** Returns whether there is currently a network log being recorded */
currentlyLogging: boolean;
/** A string property that returns the path to the current log file */
currentlyLoggingPath: string;
}Usage Examples:
const { session } = require('electron');
const path = require('path');
// Network debugging
async function startNetworkLogging() {
const netLog = session.defaultSession.netLog;
if (netLog.currentlyLogging) {
console.log('Network logging already active');
return;
}
try {
const logPath = path.join(__dirname, 'logs', `network-${Date.now()}.json`);
await netLog.startLogging(logPath, {
captureMode: 'everything',
maxFileSize: 100 * 1024 * 1024 // 100MB
});
console.log('Network logging started:', logPath);
// Stop after 5 minutes
setTimeout(async () => {
await stopNetworkLogging();
}, 5 * 60 * 1000);
} catch (error) {
console.error('Failed to start network logging:', error);
}
}
async function stopNetworkLogging() {
const netLog = session.defaultSession.netLog;
if (!netLog.currentlyLogging) {
console.log('Network logging not active');
return;
}
try {
await netLog.stopLogging();
console.log('Network logging stopped');
} catch (error) {
console.error('Failed to stop network logging:', error);
}
}
// Debug specific network issues
function debugNetworkIssues() {
const { webContents } = require('electron');
// Monitor all webContents for network events
webContents.getAllWebContents().forEach(contents => {
contents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
console.error('Failed to load:', {
url: validatedURL,
error: errorCode,
description: errorDescription
});
});
contents.on('did-fail-provisional-load', (event, errorCode, errorDescription, validatedURL) => {
console.error('Provisional load failed:', {
url: validatedURL,
error: errorCode,
description: errorDescription
});
});
contents.on('certificate-error', (event, url, error, certificate) => {
console.error('Certificate error:', {
url: url,
error: error,
issuer: certificate.issuer
});
});
});
}Chrome DevTools debugging interface.
/**
* An alternate transport for Chrome's remote debugging protocol
*/
interface Debugger extends EventEmitter {
/** Attaches the debugger to the webContents */
attach(protocolVersion?: string): void;
/** Returns whether a debugger is attached to the webContents */
isAttached(): boolean;
/** Detaches the debugger from the webContents */
detach(): void;
/** Send given command to the debugging target */
sendCommand(method: string, commandParams?: any): Promise<any>;
}Usage Examples:
const { BrowserWindow } = require('electron');
// Debug a specific window
function setupDebugger(window) {
const debugger = window.webContents.debugger;
try {
debugger.attach('1.3');
console.log('Debugger attached');
} catch (error) {
console.error('Failed to attach debugger:', error);
return;
}
// Handle debugger events
debugger.on('detach', (event, reason) => {
console.log('Debugger detached:', reason);
});
debugger.on('message', (event, method, params) => {
if (method === 'Network.responseReceived') {
console.log('Network response:', params);
}
});
// Enable network domain
debugger.sendCommand('Network.enable').then(() => {
console.log('Network domain enabled');
});
// Enable runtime domain
debugger.sendCommand('Runtime.enable').then(() => {
console.log('Runtime domain enabled');
});
return debugger;
}
// CPU profiling
async function profileCPU(window, duration = 10000) {
const debugger = window.webContents.debugger;
try {
if (!debugger.isAttached()) {
debugger.attach('1.3');
}
// Enable profiler
await debugger.sendCommand('Profiler.enable');
// Start profiling
await debugger.sendCommand('Profiler.start');
console.log('CPU profiling started');
// Stop after specified duration
setTimeout(async () => {
try {
const profile = await debugger.sendCommand('Profiler.stop');
// Save profile
const fs = require('fs');
const profilePath = `cpu-profile-${Date.now()}.json`;
fs.writeFileSync(profilePath, JSON.stringify(profile.profile, null, 2));
console.log('CPU profile saved:', profilePath);
} catch (error) {
console.error('Failed to stop profiling:', error);
}
}, duration);
} catch (error) {
console.error('Failed to start CPU profiling:', error);
}
}
// Memory heap snapshot
async function takeHeapSnapshot(window) {
const debugger = window.webContents.debugger;
try {
if (!debugger.isAttached()) {
debugger.attach('1.3');
}
// Enable heap profiler
await debugger.sendCommand('HeapProfiler.enable');
// Take snapshot
await debugger.sendCommand('HeapProfiler.takeHeapSnapshot');
console.log('Heap snapshot taken');
// Listen for snapshot data
debugger.on('message', (event, method, params) => {
if (method === 'HeapProfiler.addHeapSnapshotChunk') {
// Process snapshot chunk
console.log('Received heap snapshot chunk');
}
});
} catch (error) {
console.error('Failed to take heap snapshot:', error);
}
}interface CrashReporterStartOptions {
productName: string;
companyName: string;
submitURL: string;
uploadToServer?: boolean;
ignoreSystemCrashHandler?: boolean;
rateLimit?: boolean;
compress?: boolean;
extra?: Record<string, string>;
crashesDirectory?: string;
}
interface CrashReport {
id: string;
date: Date;
productName: string;
productVersion: string;
process: string;
reason: string;
extra: Record<string, string>;
}
interface TraceCategoriesAndOptions {
categoryFilter: string;
traceOptions: string;
}
interface TraceConfig {
recording_mode?: 'record-until-full' | 'record-continuously' | 'record-as-much-as-possible' | 'trace-to-console';
enable_sampling?: boolean;
enable_systrace?: boolean;
enable_argument_filter?: boolean;
included_categories?: string[];
excluded_categories?: string[];
synthetic_delays?: string[];
memory_dump_config?: Record<string, any>;
}
interface TraceBufferUsageReturnValue {
value: number;
percentage: number;
percentFull: number;
}
interface NetLogStartLoggingOptions {
captureMode?: 'default' | 'includeCookiesAndCredentials' | 'includeSocketBytes' | 'everything';
maxFileSize?: number;
}