117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
import * as plugins from '../plugins.js';
|
|
import * as paths from '../paths.js';
|
|
import type { IProcessLog } from '../shared/protocol/ipc.types.js';
|
|
import type { ProcessId } from '../shared/protocol/id.js';
|
|
|
|
/**
|
|
* Manages persistent log storage for processes
|
|
*/
|
|
export class LogPersistence {
|
|
private logsDir: string;
|
|
|
|
constructor() {
|
|
this.logsDir = plugins.path.join(paths.tspmDir, 'logs');
|
|
}
|
|
|
|
/**
|
|
* Get the log file path for a process
|
|
*/
|
|
private getLogFilePath(processId: ProcessId): string {
|
|
return plugins.path.join(this.logsDir, `process-${processId}.json`);
|
|
}
|
|
|
|
/**
|
|
* Ensure the logs directory exists
|
|
*/
|
|
private async ensureLogsDir(): Promise<void> {
|
|
await plugins.smartfile.fs.ensureDir(this.logsDir);
|
|
}
|
|
|
|
/**
|
|
* Save logs to disk
|
|
*/
|
|
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
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Load logs from disk
|
|
*/
|
|
public async loadLogs(processId: ProcessId): Promise<IProcessLog[]> {
|
|
const filePath = this.getLogFilePath(processId);
|
|
|
|
try {
|
|
const exists = await plugins.smartfile.fs.fileExists(filePath);
|
|
if (!exists) {
|
|
return [];
|
|
}
|
|
|
|
const content = await plugins.smartfile.fs.toStringSync(filePath);
|
|
const logs = JSON.parse(content) as IProcessLog[];
|
|
|
|
// Convert date strings back to Date objects
|
|
return logs.map(log => ({
|
|
...log,
|
|
timestamp: new Date(log.timestamp)
|
|
}));
|
|
} catch (error) {
|
|
console.error(`Failed to load logs for process ${processId}:`, error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete logs from disk after loading
|
|
*/
|
|
public async deleteLogs(processId: ProcessId): Promise<void> {
|
|
const filePath = this.getLogFilePath(processId);
|
|
|
|
try {
|
|
const exists = await plugins.smartfile.fs.fileExists(filePath);
|
|
if (exists) {
|
|
await plugins.smartfile.fs.remove(filePath);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Failed to delete logs for process ${processId}:`, error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate approximate memory size of logs in bytes
|
|
*/
|
|
public static calculateLogMemorySize(logs: IProcessLog[]): number {
|
|
// Estimate based on JSON string size
|
|
// This is an approximation but good enough for our purposes
|
|
return JSON.stringify(logs).length;
|
|
}
|
|
|
|
/**
|
|
* Clean up old log files (for maintenance)
|
|
*/
|
|
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);
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to cleanup old logs:', error);
|
|
}
|
|
}
|
|
} |