106 lines
3.2 KiB
TypeScript
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();
|
|
}
|
|
}
|
|
};
|