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
- 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
414 lines
9.2 KiB
Markdown
414 lines
9.2 KiB
Markdown
# 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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```html
|
|
<!-- 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**:
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
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**:
|
|
```javascript
|
|
// Report errors immediately
|
|
await tracker.report();
|
|
```
|
|
|
|
### tracker.getErrorGroups()
|
|
|
|
Get grouped errors.
|
|
|
|
**Returns**: `Array<ErrorGroup>`
|
|
|
|
**Example**:
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
const tracker = ErrorTracker.create({
|
|
filters: [
|
|
/Script error/i, // Filter out script errors
|
|
/ResizeObserver/i // Filter out ResizeObserver errors
|
|
]
|
|
});
|
|
```
|
|
|
|
### Filter by Function
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
const tracker = ErrorTracker.create({
|
|
sampleRate: 0.1 // Report only 10% of errors
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## beforeSend Hook
|
|
|
|
Modify errors before sending to backend:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
const tracker = ErrorTracker.create({
|
|
endpoint: '/api/errors',
|
|
enabled: true,
|
|
sampleRate: 1.0, // Track all errors in development
|
|
includeStack: true,
|
|
includeContext: true
|
|
});
|
|
```
|
|
|
|
### API Error Tracking
|
|
|
|
```javascript
|
|
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](event-bus.md) →
|
|
|