or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

app-lifecycle.mddevelopment.mdindex.mdipc.mdmenu-system.mdnetwork-protocols.mdplatform-features.mdsecurity.mdsystem-integration.mdwindow-management.md
tile.json

development.mddocs/

Development & Debugging

Development tools, debugging utilities, crash reporting, and performance monitoring for building and maintaining Electron applications.

Capabilities

Crash Reporter

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();
  }
}

Content Tracing

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
}

Net Log

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
      });
    });
  });
}

Debugger

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);
  }
}

Types

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;
}