Files
michaelschiemer/docs/modules/error-tracking.md
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

9.2 KiB

Error Tracking Module

Centralized Error Tracking and Reporting

The Error Tracking Module provides comprehensive error tracking, grouping, and reporting capabilities for production applications.


Features

  • Error Collection - Automatically capture unhandled errors and promise rejections
  • Error Grouping - Group similar errors to reduce noise
  • Error Reporting - Send errors to backend for analysis
  • Error Analytics - Track error frequency and patterns
  • Integration with ErrorBoundary - Works with LiveComponent ErrorBoundary
  • Source Map Support - Map minified errors to source code
  • Error Filtering - Filter out known or irrelevant errors
  • Sampling - Control error reporting volume with sampling

Quick Start

Basic Usage

import { ErrorTracker } from './modules/error-tracking/index.js';

// Create error tracker
const tracker = ErrorTracker.create({
    endpoint: '/api/errors',
    enabled: true,
    sampleRate: 1.0 // Report 100% of errors
});

// Manually capture an error
try {
    // Some code that might throw
} catch (error) {
    tracker.captureException(error, {
        type: 'user-action',
        action: 'submit-form'
    });
}

Module System Integration

<!-- Enable global error tracking -->
<script type="module">
    import { init } from './modules/error-tracking/index.js';
    
    init({
        endpoint: '/api/errors',
        enabled: true,
        sampleRate: 0.1 // Report 10% of errors
    });
</script>

<!-- Access globally -->
<script>
    // Errors are automatically captured
    // Or manually capture:
    window.ErrorTracker.captureException(new Error('Something went wrong'), {
        context: { userId: 123 }
    });
</script>

API Reference

ErrorTracker.create(config)

Create a new ErrorTracker instance.

Parameters:

  • config.endpoint - Backend endpoint for error reporting (default: '/api/errors')
  • config.enabled - Enable error tracking (default: true)
  • config.sampleRate - Sampling rate 0.0 to 1.0 (default: 1.0)
  • config.maxErrors - Maximum errors to keep in memory (default: 100)
  • config.groupingWindow - Time window for error grouping in ms (default: 60000)
  • config.includeStack - Include stack traces (default: true)
  • config.includeContext - Include context information (default: true)
  • config.includeUserAgent - Include user agent (default: true)
  • config.includeUrl - Include current URL (default: true)
  • config.filters - Array of filter functions or regex patterns
  • config.beforeSend - Hook to modify errors before sending

Example:

const tracker = ErrorTracker.create({
    endpoint: '/api/errors',
    enabled: true,
    sampleRate: 0.5, // Report 50% of errors
    filters: [
        // Filter out specific errors
        /Script error/i,
        (error, context) => {
            // Custom filter logic
            return error.message.includes('ResizeObserver');
        }
    ],
    beforeSend: (errorData) => {
        // Add additional context
        errorData.userId = getCurrentUserId();
        errorData.sessionId = getSessionId();
        return errorData;
    }
});

tracker.captureException(error, context)

Manually capture an exception.

Parameters:

  • error - Error object or any value
  • context - Additional context information

Example:

try {
    // Some code
} catch (error) {
    tracker.captureException(error, {
        type: 'api-call',
        endpoint: '/api/users',
        method: 'POST'
    });
}

tracker.report()

Manually flush error reports to backend.

Example:

// Report errors immediately
await tracker.report();

tracker.getErrorGroups()

Get grouped errors.

Returns: Array<ErrorGroup>

Example:

const groups = tracker.getErrorGroups();
groups.forEach(group => {
    console.log(`${group.fingerprint}: ${group.count} occurrences`);
});

tracker.getErrors()

Get all captured errors.

Returns: Array<ErrorData>

tracker.clearErrors()

Clear all captured errors.


Integration with ErrorBoundary

import { ErrorTracker } from './modules/error-tracking/index.js';
import { ErrorBoundary } from './modules/livecomponent/ErrorBoundary.js';

const tracker = ErrorTracker.create({
    endpoint: '/api/errors'
});

// ErrorBoundary automatically captures errors
const errorBoundary = new ErrorBoundary(liveComponentManager);

// Listen for errors
window.addEventListener('error-tracker:error', (event) => {
    const errorData = event.detail;
    console.error('Error captured:', errorData);
    
    // Show user-friendly error message
    showErrorNotification(errorData.message);
});

Error Filtering

Filter by Regex

const tracker = ErrorTracker.create({
    filters: [
        /Script error/i, // Filter out script errors
        /ResizeObserver/i // Filter out ResizeObserver errors
    ]
});

Filter by Function

const tracker = ErrorTracker.create({
    filters: [
        (error, context) => {
            // Filter out errors from specific domains
            if (context.url && context.url.includes('localhost')) {
                return false; // Don't track localhost errors
            }
            return true; // Track other errors
        }
    ]
});

Error Sampling

Control error reporting volume with sampling:

const tracker = ErrorTracker.create({
    sampleRate: 0.1 // Report only 10% of errors
});

beforeSend Hook

Modify errors before sending to backend:

const tracker = ErrorTracker.create({
    beforeSend: (errorData) => {
        // Add user information
        errorData.user = {
            id: getCurrentUserId(),
            email: getCurrentUserEmail()
        };
        
        // Add session information
        errorData.session = {
            id: getSessionId(),
            startTime: getSessionStartTime()
        };
        
        // Remove sensitive data
        delete errorData.context.password;
        
        // Return modified error data
        return errorData;
        
        // Or return null/false to prevent sending
        // return null;
    }
});

Error Grouping

Errors are automatically grouped by:

  • Error name
  • Error message
  • Stack trace (first 3 lines)

Similar errors are grouped together to reduce noise:

const groups = tracker.getErrorGroups();
groups.forEach(group => {
    console.log(`Error: ${group.fingerprint}`);
    console.log(`Count: ${group.count}`);
    console.log(`First seen: ${new Date(group.firstSeen)}`);
    console.log(`Last seen: ${new Date(group.lastSeen)}`);
});

Backend Integration

The error tracker sends errors to the backend endpoint:

POST /api/errors
Content-Type: application/json

{
    "errors": [
        {
            "message": "Cannot read property 'x' of undefined",
            "name": "TypeError",
            "stack": "...",
            "timestamp": 1234567890,
            "type": "unhandled",
            "context": {
                "url": "https://example.com/page",
                "userAgent": "...",
                "viewport": { "width": 1920, "height": 1080 }
            }
        }
    ],
    "errorGroups": [
        {
            "fingerprint": "TypeError:Cannot read property...",
            "count": 5,
            "firstSeen": 1234567890,
            "lastSeen": 1234567900
        }
    ]
}

Use Cases

Production Error Tracking

const tracker = ErrorTracker.create({
    endpoint: '/api/errors',
    enabled: true,
    sampleRate: 0.1, // Sample 10% in production
    filters: [
        // Filter out known issues
        /ResizeObserver/i,
        /Script error/i
    ],
    beforeSend: (errorData) => {
        // Add user context
        errorData.userId = getCurrentUserId();
        return errorData;
    }
});

Development Error Tracking

const tracker = ErrorTracker.create({
    endpoint: '/api/errors',
    enabled: true,
    sampleRate: 1.0, // Track all errors in development
    includeStack: true,
    includeContext: true
});

API Error Tracking

async function apiCall(url, options) {
    try {
        const response = await fetch(url, options);
        if (!response.ok) {
            throw new Error(`API error: ${response.status}`);
        }
        return await response.json();
    } catch (error) {
        tracker.captureException(error, {
            type: 'api-error',
            url,
            method: options.method || 'GET',
            status: error.status
        });
        throw error;
    }
}

Best Practices

  1. Use Sampling in Production - Set sampleRate to 0.1 or lower to reduce backend load
  2. Filter Known Issues - Filter out errors you can't fix (e.g., browser extensions)
  3. Add Context - Use beforeSend to add user, session, or request context
  4. Group Errors - Let the tracker group similar errors automatically
  5. Monitor Error Groups - Track error frequency and patterns

Browser Support

  • Chrome/Edge: 90+
  • Firefox: 88+
  • Safari: 14+
  • Mobile: iOS 14+, Android Chrome 90+

Required Features:

  • ES2020 JavaScript
  • Fetch API
  • Promise support

Next: Event Bus Module