All files / backend/dist/logging log-cleaner.js

0% Statements 0/52
0% Branches 0/16
0% Functions 0/9
0% Lines 0/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                                                                                                                                                                                                                                             
/**
 * LogCleaner - Enforces retention policy by deleting old log files
 */
import fs from 'fs-extra';
import path from 'path';
import os from 'os';
export class LogCleaner {
    /**
     * Clean old log files based on retention policy
     * @param retentionDays - Number of days to keep logs (0 = never delete)
     */
    async cleanOldLogs(retentionDays) {
        if (retentionDays === 0) {
            // Never delete logs
            return;
        }
        const cutoffDate = this.getCutoffDate(retentionDays);
        // Clean global application logs
        await this.cleanDirectory(path.join(os.homedir(), 'Quiqr', 'logs'), cutoffDate, /^application-(\d{4}-\d{2}-\d{2})\.jsonl$/);
        // Clean site logs (recursively scan all sites and workspaces)
        await this.cleanSiteLogs(path.join(os.homedir(), 'Quiqr', 'sites'), cutoffDate);
    }
    /**
     * Get cutoff date (files older than this should be deleted)
     */
    getCutoffDate(retentionDays) {
        const cutoff = new Date();
        cutoff.setDate(cutoff.getDate() - retentionDays);
        cutoff.setHours(0, 0, 0, 0); // Start of day
        return cutoff;
    }
    /**
     * Clean log files in a directory matching a pattern
     */
    async cleanDirectory(dirPath, cutoffDate, pattern) {
        try {
            if (!await fs.pathExists(dirPath)) {
                return;
            }
            const files = await fs.readdir(dirPath);
            for (const file of files) {
                const match = pattern.exec(file);
                if (!match) {
                    continue;
                }
                const dateStr = match[1]; // Extract date from filename
                const fileDate = this.parseDate(dateStr);
                if (fileDate && fileDate < cutoffDate) {
                    const filePath = path.join(dirPath, file);
                    try {
                        await fs.remove(filePath);
                        console.log(`Deleted old log file: ${filePath}`);
                    }
                    catch (error) {
                        console.error(`Failed to delete log file ${filePath}:`, error);
                    }
                }
            }
        }
        catch (error) {
            console.error(`Failed to clean directory ${dirPath}:`, error);
        }
    }
    /**
     * Clean site logs recursively
     */
    async cleanSiteLogs(sitesDir, cutoffDate) {
        try {
            if (!await fs.pathExists(sitesDir)) {
                return;
            }
            const siteKeys = await fs.readdir(sitesDir);
            for (const siteKey of siteKeys) {
                const siteDir = path.join(sitesDir, siteKey);
                const stat = await fs.stat(siteDir);
                if (!stat.isDirectory()) {
                    continue;
                }
                // Pattern: {workspaceKey}-YYYY-MM-DD.jsonl
                const pattern = /^(.+)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
                await this.cleanDirectory(siteDir, cutoffDate, pattern);
            }
        }
        catch (error) {
            console.error(`Failed to clean site logs in ${sitesDir}:`, error);
        }
    }
    /**
     * Parse date string (YYYY-MM-DD) to Date object
     */
    parseDate(dateStr) {
        const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateStr);
        if (!match) {
            return null;
        }
        const year = parseInt(match[1], 10);
        const month = parseInt(match[2], 10) - 1; // Month is 0-indexed
        const day = parseInt(match[3], 10);
        const date = new Date(year, month, day);
        date.setHours(0, 0, 0, 0);
        return date;
    }
    /**
     * Schedule periodic cleanup (runs daily)
     */
    scheduleCleanup(retentionDays) {
        // Run cleanup immediately
        this.cleanOldLogs(retentionDays).catch(error => {
            console.error('Failed to run scheduled log cleanup:', error);
        });
        // Schedule daily cleanup (every 24 hours)
        return setInterval(() => {
            this.cleanOldLogs(retentionDays).catch(error => {
                console.error('Failed to run scheduled log cleanup:', error);
            });
        }, 24 * 60 * 60 * 1000);
    }
}