Files
Schnappix/src/services/logger.ts
T

106 lines
3.2 KiB
TypeScript

import * as FileSystem from 'expo-file-system/legacy';
const logFileUri = FileSystem.documentDirectory + 'app_logs.txt';
// Queue to serialize file operations and prevent race conditions
const logQueue: string[] = [];
let isWriting = false;
const processLogQueue = async () => {
if (isWriting) return;
isWriting = true;
while (logQueue.length > 0) {
const logLine = logQueue.shift();
if (!logLine) continue;
try {
if (logFileUri) {
const fileInfo = await FileSystem.getInfoAsync(logFileUri);
if (!fileInfo.exists) {
await FileSystem.writeAsStringAsync(logFileUri, '', { encoding: FileSystem.EncodingType.UTF8 });
}
const current = await FileSystem.readAsStringAsync(logFileUri, { encoding: FileSystem.EncodingType.UTF8 });
let newContent = current + logLine;
if (newContent.length > 100000) {
newContent = newContent.slice(-100000);
}
await FileSystem.writeAsStringAsync(logFileUri, newContent, { encoding: FileSystem.EncodingType.UTF8 });
}
} catch (e) {
console.warn('Failed to write to log file:', e);
}
}
isWriting = false;
};
const waitForQueueDrain = async () => {
while (isWriting || logQueue.length > 0) {
await new Promise(resolve => setTimeout(resolve, 50));
}
};
const enqueueWrite = async (logLine: string) => {
logQueue.push(logLine);
processLogQueue(); // Intentionally unawaited to run in background
};
export const logger = {
log: async (message: string) => {
const timestamp = new Date().toISOString();
const logLine = `[INFO] ${timestamp}: ${message}\n`;
console.log(logLine.trim());
return enqueueWrite(logLine);
},
error: async (message: string, error?: any) => {
const timestamp = new Date().toISOString();
let errorString = '';
if (error) {
if (error instanceof Error) {
errorString = `\n Name: ${error.name}\n Message: ${error.message}\n Stack: ${error.stack}`;
} else if (typeof error === 'object') {
errorString = `\n Object: ${JSON.stringify(error)}`;
} else {
errorString = `\n Value: ${String(error)}`;
}
}
const logLine = `[ERROR] ${timestamp}: ${message}${errorString}\n`;
console.error(logLine.trim());
return enqueueWrite(logLine);
},
readLogs: async (): Promise<string> => {
try {
// Wait for pending writes to finish
await waitForQueueDrain();
isWriting = true; // lock the queue while reading
try {
const fileInfo = await FileSystem.getInfoAsync(logFileUri);
if (!fileInfo.exists) return 'Keine Logs vorhanden.';
return await FileSystem.readAsStringAsync(logFileUri, { encoding: FileSystem.EncodingType.UTF8 });
} finally {
isWriting = false;
processLogQueue();
}
} catch (e) {
return `Fehler beim Lesen der Logs: ${e}`;
}
},
clearLogs: async () => {
await waitForQueueDrain();
isWriting = true; // lock the queue while clearing
try {
await FileSystem.deleteAsync(logFileUri, { idempotent: true });
} catch (e) {
console.warn('Failed to clear logs:', e);
} finally {
isWriting = false;
processLogQueue();
}
}
};