Adviseer mij over geavanceerde Capacitor app foutafhandeling en logging
description
Met deze prompt kan ik mijn Capacitor app voorzien van een geavanceerd systeem voor foutafhandeling en logging, wat bijdraagt aan betere stabiliteit, eenvoudiger debuggen en snellere probleemoplossing. Dit is effectiever dan basis foutafhandeling omdat het ook externe services en configuraties omvat voor diepgaand inzicht.
prompt
Help mij een robuust foutafhandelings- en loggingsysteem te ontwerpen voor mijn Capacitor app. Beschrijf hoe ik foutmeldingen effectief kan opvangen en loggen, inclusief het gebruik van externe logging services of lokale opslag ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Een robuust foutafhandelings- en loggingsysteem voor je Capacitor-app op iOS kan je betrouwbaarheid en onderhoudbaarheid aanzienlijk verbeteren. Hier zijn stappen en voorbeelden om dit te realiseren:
1. Vervang console.log door een gestructureerde loggingstrategie
2. Gebruik externe logging services voor centrale monitoring
3. Log ook lokale fouten zodat ze niet verloren gaan
4. Integreer foutafhandeling in je app-levenscyclus en API-calls
---
### 1. Logging bibliotheek kiezen
Gebruik bijvoorbeeld een populaire logging library zoals [Winston](https://github.com/winstonjs/winston) of [loglevel](https://github.com/pimterry/loglevel), of maak een eenvoudige wrapper:
```typescript
// log.ts
export enum LogLevel {
DEBUG,
INFO,
WARN,
ERROR,
}
export class Logger {
static logLevel: LogLevel = LogLevel.INFO;
static log(level: LogLevel, message: string, data?: any) {
if (level >= this.logLevel) {
const prefix = LogLevel[level];
console.log(`[${prefix}] ${message}`, data || '');
}
// Hier kan je ook een externe service aanroepen
}
static error(message: string, error?: any) {
this.log(LogLevel.ERROR, message, error);
// Voeg hier externe logging toe
sendErrorToService(message, error);
}
static info(message: string, data?: any) {
this.log(LogLevel.INFO, message, data);
}
}
function sendErrorToService(message: string, error?: any) {
// Voorbeeld: Log naar een externe service zoals Sentry, Loggly, etc.
// Hier moet je de SDK integreren
}
```
---
### 2. Externe logging service integreren
Voor iOS kun je bijvoorbeeld Sentry gebruiken:
```bash
npm install @sentry/capacitor
npx cap sync
```
In je app initialiseren:
```typescript
import * as Sentry from '@sentry/capacitor';
Sentry.init({
dsn: 'JE_DSN_URL', // vervang door jouw DSN
tracesSampleRate: 1.0,
});
```
En voor het loggen van fouten:
```typescript
async function sendErrorToService(message: string, error?: any) {
try {
await Sentry.captureException(error || new Error(message));
} catch (e) {
// fallback: log naar lokale opslag
LocalErrorLogger.log(error || new Error(message));
}
}
```
---
### 3. Lokale opslag voor foutmeldingen
Gebruik bijvoorbeeld [Capacitor Storage](https://capacitorjs.com/docs/apis/storage) om fouten lokaal op te slaan:
```typescript
import { Storage } from '@capacitor/storage';
class LocalErrorLogger {
static async log(error: any) {
const timestamp = new Date().toISOString();
const errorEntry = {
timestamp,
message: error.message || error.toString(),
stack: error.stack || null,
};
const existing = await Storage.get({ key: 'errorLogs' });
let logs = [];
if (existing.value) {
logs = JSON.parse(existing.value);
}
logs.push(errorEntry);
await Storage.set({
key: 'errorLogs',
value: JSON.stringify(logs),
});
}
static async getLogs() {
const { value } = await Storage.get({ key: 'errorLogs' });
return value ? JSON.parse(value) : [];
}
static async clearLogs() {
await Storage.remove({ key: 'errorLogs' });
}
}
```
---
### 4. Foutafhandeling in je app
Gebruik try/catch blokken en centraliseer foutmeldingen:
```typescript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
Logger.error('Fout tijdens fetchData', error);
}
}
```
---
### 5. Gecombineerde aanpak
- Vervang `console.log` door `Logger` met niveaus
- Fouten worden gelogd naar externe services en lokaal
- Bij app crashes of onopgevangen fouten: registreer global error handler:
```typescript
window.onerror = (message, source, lineno, colno, error) => {
Logger.error('Onverwachte fout', error);
return false; // of true om te voorkomen dat de standaard alert verschijnt
};
```
---
### Samenvatting
- Gebruik een gestructureerde logger
- Integreer een externe service zoals Sentry voor centrale monitoring
- Log ook fouten lokaal om gegevens niet te verliezen
- Implementeer global error handlers
- Test je systeem door fouten bewust op te roepen
Met deze aanpak maak je je foutafhandeling veel robuuster en krijg je waardevolle inzichten in problemen in je iOS Capacitor app.
provider: deepseek
model: deepseek-chat
Zeker! Hier is een robuust foutafhandelings- en loggingsysteem voor je Capacitor iOS app:
## 1. Basis Foutafhandelingsstructuur
### Globale Error Handler
```typescript
// src/utils/errorHandler.ts
class ErrorHandler {
private isInitialized = false;
init() {
if (this.isInitialized) return;
// Vang onafhandelde Promise rejections
window.addEventListener('unhandledrejection', (event) => {
this.logError('UNHANDLED_PROMISE_REJECTION', {
reason: event.reason,
stack: event.reason?.stack
});
});
// Vang globale JavaScript errors
window.addEventListener('error', (event) => {
this.logError('GLOBAL_ERROR', {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error
});
});
this.isInitialized = true;
}
async handleError(error: any, context?: string) {
const errorInfo = {
message: error?.message || 'Unknown error',
stack: error?.stack,
context: context || 'Unknown context',
timestamp: new Date().toISOString(),
platform: 'ios',
appVersion: await this.getAppVersion()
};
await this.logError('HANDLED_ERROR', errorInfo);
return errorInfo;
}
private async getAppVersion(): Promise<string> {
try {
const { getAppInfo } = await import('@capacitor/app');
const info = await getAppInfo();
return `${info.version} (${info.build})`;
} catch {
return 'unknown';
}
}
}
export const errorHandler = new ErrorHandler();
```
## 2. Logging Service met Meerdere Backends
```typescript
// src/services/logger.ts
import { Preferences } from '@capacitor/preferences';
import { Filesystem, Directory } from '@capacitor/filesystem';
interface LogEntry {
level: 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
message: string;
timestamp: string;
context?: string;
extraData?: any;
}
class Logger {
private readonly MAX_LOCAL_LOGS = 1000;
private readonly LOG_FILE = 'app_logs.json';
async log(level: LogEntry['level'], message: string, context?: string, extraData?: any) {
const entry: LogEntry = {
level,
message,
timestamp: new Date().toISOString(),
context,
extraData
};
// Console logging (alleen in development)
if (import.meta.env.DEV) {
this.consoleLog(entry);
}
// Lokale opslag
await this.saveToLocalStorage(entry);
// File systeem logging voor persistente opslag
await this.saveToFileSystem(entry);
// Externe service (bij productie errors)
if (level === 'ERROR' && !import.meta.env.DEV) {
await this.sendToExternalService(entry);
}
}
private consoleLog(entry: LogEntry) {
const styles = {
ERROR: 'color: red; font-weight: bold;',
WARN: 'color: orange; font-weight: bold;',
INFO: 'color: blue;',
DEBUG: 'color: gray;'
};
console.log(
`%c[${entry.level}] ${entry.timestamp}${entry.context ? ` [${entry.context}]` : ''}: ${entry.message}`,
styles[entry.level]
);
if (entry.extraData) {
console.log('Extra data:', entry.extraData);
}
}
private async saveToLocalStorage(entry: LogEntry) {
try {
const { value } = await Preferences.get({ key: 'app_logs' });
const logs: LogEntry[] = value ? JSON.parse(value) : [];
logs.push(entry);
// Beperk het aantal logs
if (logs.length > this.MAX_LOCAL_LOGS) {
logs.splice(0, logs.length - this.MAX_LOCAL_LOGS);
}
await Preferences.set({
key: 'app_logs',
value: JSON.stringify(logs)
});
} catch (error) {
console.error('Failed to save log to localStorage:', error);
}
}
private async saveToFileSystem(entry: LogEntry) {
try {
// Check of bestand bestaat
let existingLogs: LogEntry[] = [];
try {
const contents = await Filesystem.readFile({
path: this.LOG_FILE,
directory: Directory.Data
});
existingLogs = JSON.parse(contents.data);
} catch {
// Bestand bestaat niet - normaal bij eerste run
}
existingLogs.push(entry);
// Beperk file logs
if (existingLogs.length > this.MAX_LOCAL_LOGS) {
existingLogs.splice(0, existingLogs.length - this.MAX_LOCAL_LOGS);
}
await Filesystem.writeFile({
path: this.LOG_FILE,
data: JSON.stringify(existingLogs),
directory: Directory.Data,
encoding: 'utf8'
});
} catch (error) {
console.error('Failed to save log to filesystem:', error);
}
}
private async sendToExternalService(entry: LogEntry) {
try {
// Voorbeeld: Sentry integratie
if (typeof window !== 'undefined' && (window as any).Sentry) {
(window as any).Sentry.captureException(new Error(entry.message), {
extra: {
context: entry.context,
timestamp: entry.timestamp,
...entry.extraData
}
});
}
// Of je eigen backend
await fetch('https://your-logging-service.com/api/logs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...entry,
deviceInfo: await this.getDeviceInfo()
})
});
} catch (error) {
console.warn('Failed to send log to external service:', error);
}
}
private async getDeviceInfo() {
const { getDeviceInfo } = await import('@capacitor/device');
return await getDeviceInfo();
}
// Helper methods voor verschillende log levels
async error(message: string, context?: string, extraData?: any) {
await this.log('ERROR', message, context, extraData);
}
async warn(message: string, context?: string, extraData?: any) {
await this.log('WARN', message, context, extraData);
}
async info(message: string, context?: string, extraData?: any) {
await this.log('INFO', message, context, extraData);
}
async debug(message: string, context?: string, extraData?: any) {
await this.log('DEBUG', message, context, extraData);
}
// Log retrieval methods
async getLocalLogs(): Promise<LogEntry[]> {
try {
const { value } = await Preferences.get({ key: 'app_logs' });
return value ? JSON.parse(value) : [];
} catch {
return [];
}
}
async getFileLogs(): Promise<LogEntry[]> {
try {
const contents = await Filesystem.readFile({
path: this.LOG_FILE,
directory: Directory.Data
});
return JSON.parse(contents.data);
} catch {
return [];
}
}
async clearLogs() {
await Preferences.remove({ key: 'app_logs' });
try {
await Filesystem.deleteFile({
path: this.LOG_FILE,
directory: Directory.Data
});
} catch {
// Bestand bestaat niet
}
}
}
export const logger = new Logger();
```
## 3. Gebruik in je App
### Initialisatie
```typescript
// src/main.ts of App.vue
import { errorHandler } from './utils/errorHandler';
import { logger } from './services/logger';
// Initialiseer error handling
errorHandler.init();
// Voorbeeld: App start logging
logger.info('App gestart', 'AppInitialization');
```
### Gebruik in Components
```typescript
// In je Vue component
import { logger, errorHandler } from '../services/logger';
export default {
methods: {
async fetchData() {
try {
logger.info('Start data fetch', 'DataService');
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
logger.info('Data succesvol opgehaald', 'DataService', { itemCount: data.length });
return data;
} catch (error) {
const errorInfo = await errorHandler.handleError(error, 'fetchData');
logger.error('Data fetch gefaald', 'DataService', errorInfo);
// Toon gebruikersvriendelijke foutmelding
this.showError('Kon data niet ophalen. Probeer het later opnieuw.');
}
},
showError(message: string) {
// Gebruik Capacitor Toast of eigen modal
import('@capacitor/toast').then(({ Toast }) => {
Toast.show({ text: message, duration: 'long' });
});
}
}
}
```
## 4. Capacitor Configuratie
### capacitor.config.ts
```typescript
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.jouwapp.app',
appName: 'Jouw App',
webDir: 'dist',
server: {
androidScheme: 'https'
},
plugins: {
Preferences: {},
Filesystem: {},
Toast: {
text: 'Hello!',
duration: 'short'
}
}
};
export default config;
```
## 5. Externe Logging Services
### Sentry Configuratie
```typescript
// src/utils/sentry.ts
import * as Sentry from '@sentry/capacitor';
import * as SentryVue from '@sentry/vue';
export const initSentry = (app: any) => {
if (!import.meta.env.DEV) {
Sentry.init({
app,
dsn: 'JOUW_SENTRY_DSN_HIER',
integrations: [
new SentryVue.BrowserTracing({
trackComponents: true,
}),
],
tracesSampleRate: 0.1, // 10% van requests
});
}
};
```
## 6. Log Viewer voor Development
```typescript
// src/utils/logViewer.ts (alleen voor development)
import { logger } from '../services/logger';
export const setupLogViewer = () => {
if (import.meta.env.DEV) {
// Maak logger globaal beschikbaar in development
(window as any).$logger = logger;
console.log('🔍 Logger is beschikbaar als window.$logger');
console.log('Beschikbare commands:');
console.log(' - $logger.getLocalLogs()');
console.log(' - $logger.getFileLogs()');
console.log(' - $logger.clearLogs()');
}
};
```
## Gebruik:
1. **Initialiseer** in je main.ts:
```typescript
errorHandler.init();
setupLogViewer();
```
2. **Log errors** in je code:
```typescript
try {
// je code
} catch (error) {
await logger.error('Operation failed', 'ComponentName', { userId: 123 });
}
```
3. **Log informatie**:
```typescript
await logger.info('User action', 'ButtonClick', { buttonId: 'submit' });
```
Dit systeem biedt:
- ✅ Meerdere logging backends (console, localStorage, filesystem, extern)
- ✅ Automatische error capturing
- ✅ Gebruikersvriendelijke foutmeldingen
- ✅ Persistente log opslag
- ✅ Development tools
- ✅ Schaalbaar voor productie gebruik
Je kunt eenvoudig externe services zoals Sentry, LogRocket of je eigen backend toevoegen via de `sendToExternalService` methode.