fix(crash-logging): migrate filesystem persistence to smartfs and stabilize crash log tests
This commit is contained in:
@@ -3,6 +3,8 @@ import * as paths from '../paths.js';
|
||||
import type { IProcessLog } from '../shared/protocol/ipc.types.js';
|
||||
import type { ProcessId } from '../shared/protocol/id.js';
|
||||
|
||||
const smartfs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
|
||||
|
||||
/**
|
||||
* Manages crash log storage for failed processes
|
||||
*/
|
||||
@@ -54,7 +56,7 @@ export class CrashLogManager {
|
||||
});
|
||||
|
||||
// Write crash log
|
||||
await plugins.smartfile.memory.toFs(crashReport, filepath);
|
||||
await smartfs.file(filepath).encoding('utf8').write(crashReport);
|
||||
|
||||
// Rotate old logs if needed
|
||||
await this.rotateOldLogs();
|
||||
@@ -193,7 +195,7 @@ export class CrashLogManager {
|
||||
* Ensure crash logs directory exists
|
||||
*/
|
||||
private async ensureCrashLogsDir(): Promise<void> {
|
||||
await plugins.smartfile.fs.ensureDir(this.crashLogsDir);
|
||||
await smartfs.directory(this.crashLogsDir).create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,17 +204,18 @@ export class CrashLogManager {
|
||||
private async rotateOldLogs(): Promise<void> {
|
||||
try {
|
||||
// Get all crash log files
|
||||
const files = await plugins.smartfile.fs.listFileTree(this.crashLogsDir, '*.log');
|
||||
|
||||
const entries = await smartfs.directory(this.crashLogsDir).list();
|
||||
const files = entries.filter(e => e.name.endsWith('.log'));
|
||||
|
||||
if (files.length <= this.MAX_CRASH_LOGS) {
|
||||
return; // No rotation needed
|
||||
}
|
||||
|
||||
// Get file stats and sort by modification time (oldest first)
|
||||
const fileStats = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const filepath = plugins.path.join(this.crashLogsDir, file);
|
||||
const stats = await plugins.smartfile.fs.stat(filepath);
|
||||
files.map(async (entry) => {
|
||||
const filepath = plugins.path.join(this.crashLogsDir, entry.name);
|
||||
const stats = await smartfs.file(filepath).stat();
|
||||
return { filepath, mtime: stats.mtime.getTime() };
|
||||
})
|
||||
);
|
||||
@@ -222,7 +225,7 @@ export class CrashLogManager {
|
||||
// Delete oldest files to stay under limit
|
||||
const filesToDelete = fileStats.length - this.MAX_CRASH_LOGS;
|
||||
for (let i = 0; i < filesToDelete; i++) {
|
||||
await plugins.smartfile.fs.remove(fileStats[i].filepath);
|
||||
await smartfs.file(fileStats[i].filepath).delete();
|
||||
console.log(`Rotated old crash log: ${plugins.path.basename(fileStats[i].filepath)}`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -236,8 +239,9 @@ export class CrashLogManager {
|
||||
public async getCrashLogsForProcess(processId: ProcessId): Promise<string[]> {
|
||||
try {
|
||||
await this.ensureCrashLogsDir();
|
||||
const files = await plugins.smartfile.fs.listFileTree(this.crashLogsDir, `*_${processId}_*.log`);
|
||||
return files.map(file => plugins.path.join(this.crashLogsDir, file));
|
||||
const entries = await smartfs.directory(this.crashLogsDir).list();
|
||||
const files = entries.filter(e => e.name.endsWith('.log') && e.name.includes(`_${processId}_`));
|
||||
return files.map(entry => plugins.path.join(this.crashLogsDir, entry.name));
|
||||
} catch (error) {
|
||||
console.error(`Failed to get crash logs for process ${processId}:`, error);
|
||||
return [];
|
||||
@@ -250,16 +254,17 @@ export class CrashLogManager {
|
||||
public async cleanupAllCrashLogs(): Promise<void> {
|
||||
try {
|
||||
await this.ensureCrashLogsDir();
|
||||
const files = await plugins.smartfile.fs.listFileTree(this.crashLogsDir, '*.log');
|
||||
|
||||
for (const file of files) {
|
||||
const filepath = plugins.path.join(this.crashLogsDir, file);
|
||||
await plugins.smartfile.fs.remove(filepath);
|
||||
const entries = await smartfs.directory(this.crashLogsDir).list();
|
||||
const files = entries.filter(e => e.name.endsWith('.log'));
|
||||
|
||||
for (const entry of files) {
|
||||
const filepath = plugins.path.join(this.crashLogsDir, entry.name);
|
||||
await smartfs.file(filepath).delete();
|
||||
}
|
||||
|
||||
|
||||
console.log(`Cleaned up ${files.length} crash logs`);
|
||||
} catch (error) {
|
||||
console.error('Failed to cleanup crash logs:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as paths from '../paths.js';
|
||||
import type { IProcessLog } from '../shared/protocol/ipc.types.js';
|
||||
import type { ProcessId } from '../shared/protocol/id.js';
|
||||
|
||||
const smartfs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
|
||||
|
||||
/**
|
||||
* Manages persistent log storage for processes
|
||||
*/
|
||||
@@ -24,7 +26,7 @@ export class LogPersistence {
|
||||
* Ensure the logs directory exists
|
||||
*/
|
||||
private async ensureLogsDir(): Promise<void> {
|
||||
await plugins.smartfile.fs.ensureDir(this.logsDir);
|
||||
await smartfs.directory(this.logsDir).create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,12 +35,9 @@ export class LogPersistence {
|
||||
public async saveLogs(processId: ProcessId, logs: IProcessLog[]): Promise<void> {
|
||||
await this.ensureLogsDir();
|
||||
const filePath = this.getLogFilePath(processId);
|
||||
|
||||
|
||||
// Write logs as JSON
|
||||
await plugins.smartfile.memory.toFs(
|
||||
JSON.stringify(logs, null, 2),
|
||||
filePath
|
||||
);
|
||||
await smartfs.file(filePath).encoding('utf8').write(JSON.stringify(logs, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,16 +45,16 @@ export class LogPersistence {
|
||||
*/
|
||||
public async loadLogs(processId: ProcessId): Promise<IProcessLog[]> {
|
||||
const filePath = this.getLogFilePath(processId);
|
||||
|
||||
|
||||
try {
|
||||
const exists = await plugins.smartfile.fs.fileExists(filePath);
|
||||
const exists = await smartfs.file(filePath).exists();
|
||||
if (!exists) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const content = await plugins.smartfile.fs.toStringSync(filePath);
|
||||
const content = await smartfs.file(filePath).encoding('utf8').read() as string;
|
||||
const logs = JSON.parse(content) as IProcessLog[];
|
||||
|
||||
|
||||
// Convert date strings back to Date objects
|
||||
return logs.map(log => ({
|
||||
...log,
|
||||
@@ -72,11 +71,11 @@ export class LogPersistence {
|
||||
*/
|
||||
public async deleteLogs(processId: ProcessId): Promise<void> {
|
||||
const filePath = this.getLogFilePath(processId);
|
||||
|
||||
|
||||
try {
|
||||
const exists = await plugins.smartfile.fs.fileExists(filePath);
|
||||
const exists = await smartfs.file(filePath).exists();
|
||||
if (exists) {
|
||||
await plugins.smartfile.fs.remove(filePath);
|
||||
await smartfs.file(filePath).delete();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to delete logs for process ${processId}:`, error);
|
||||
@@ -98,20 +97,21 @@ export class LogPersistence {
|
||||
public async cleanupOldLogs(): Promise<void> {
|
||||
try {
|
||||
await this.ensureLogsDir();
|
||||
const files = await plugins.smartfile.fs.listFileTree(this.logsDir, '*.json');
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = plugins.path.join(this.logsDir, file);
|
||||
const stats = await plugins.smartfile.fs.stat(filePath);
|
||||
|
||||
const entries = await smartfs.directory(this.logsDir).list();
|
||||
const files = entries.filter(e => e.name.endsWith('.json'));
|
||||
|
||||
for (const entry of files) {
|
||||
const filePath = plugins.path.join(this.logsDir, entry.name);
|
||||
const stats = await smartfs.file(filePath).stat();
|
||||
|
||||
// Delete files older than 7 days
|
||||
const ageInDays = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24);
|
||||
if (ageInDays > 7) {
|
||||
await plugins.smartfile.fs.remove(filePath);
|
||||
await smartfs.file(filePath).delete();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to cleanup old logs:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user