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

20% Statements 10/50
0% Branches 0/18
18.18% Functions 2/11
20.4% Lines 10/49

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 120 121              1x 1x 1x 1x   1x           1x 1x 1x 1x 1x                                                                                                                                                                                                    
/**
 * LogWriter - Handles writing log entries to JSONL files with daily rotation
 */
import fs from 'fs-extra';
import path from 'path';
import os from 'os';
export class LogWriter {
    writeQueue = [];
    flushTimeout = null;
    isWriting = false;
    currentDate = '';
    constructor() {
        this.currentDate = this.getTodayDate();
    }
    /**
     * Get today's date in YYYY-MM-DD format
     */
    getTodayDate() {
        const now = new Date();
        const year = now.getFullYear();
        const month = String(now.getMonth() + 1).padStart(2, '0');
        const day = String(now.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    }
    /**
     * Get the log file path for global application logs
     */
    getApplicationLogPath(date) {
        const logDate = date || this.getTodayDate();
        const logsDir = path.join(os.homedir(), 'Quiqr', 'logs');
        return path.join(logsDir, `application-${logDate}.jsonl`);
    }
    /**
     * Get the log file path for site-specific logs
     */
    getSiteLogPath(siteKey, workspaceKey, date) {
        const logDate = date || this.getTodayDate();
        const sitesDir = path.join(os.homedir(), 'Quiqr', 'sites');
        return path.join(sitesDir, siteKey, `${workspaceKey}-${logDate}.jsonl`);
    }
    /**
     * Write a log entry asynchronously
     */
    async write(entry) {
        const filePath = entry.type === 'global'
            ? this.getApplicationLogPath()
            : this.getSiteLogPath(entry.siteKey, entry.workspaceKey);
        // Add to queue
        this.writeQueue.push({ entry, filePath });
        // Schedule flush
        if (this.flushTimeout) {
            clearTimeout(this.flushTimeout);
        }
        this.flushTimeout = setTimeout(() => {
            this.flush().catch(err => {
                console.error('Failed to flush log queue:', err);
            });
        }, 100); // Batch writes every 100ms
    }
    /**
     * Flush the write queue to disk
     */
    async flush() {
        if (this.isWriting || this.writeQueue.length === 0) {
            return;
        }
        this.isWriting = true;
        try {
            // Check if date has changed (daily rotation)
            const today = this.getTodayDate();
            if (today !== this.currentDate) {
                this.currentDate = today;
            }
            // Group entries by file path
            const entriesByFile = new Map();
            for (const { entry, filePath } of this.writeQueue) {
                if (!entriesByFile.has(filePath)) {
                    entriesByFile.set(filePath, []);
                }
                entriesByFile.get(filePath).push(entry);
            }
            // Write to each file
            for (const [filePath, entries] of entriesByFile) {
                await this.writeToFile(filePath, entries);
            }
            // Clear the queue
            this.writeQueue = [];
        }
        finally {
            this.isWriting = false;
        }
    }
    /**
     * Write entries to a specific file
     */
    async writeToFile(filePath, entries) {
        try {
            // Ensure directory exists
            await fs.ensureDir(path.dirname(filePath));
            // Convert entries to JSONL format
            const lines = entries.map(entry => JSON.stringify(entry)).join('\n') + '\n';
            // Append to file
            await fs.appendFile(filePath, lines, 'utf8');
        }
        catch (error) {
            console.error(`Failed to write to log file ${filePath}:`, error);
            throw error;
        }
    }
    /**
     * Force flush any pending writes (e.g., on shutdown)
     */
    async forceFlush() {
        if (this.flushTimeout) {
            clearTimeout(this.flushTimeout);
            this.flushTimeout = null;
        }
        await this.flush();
    }
}