flechtware_generateTracking.../csv_logger.js

110 lines
3.0 KiB
JavaScript

const fs = require('fs');
const path = require('path');
class CsvLogger {
/**
* @param {string} logDir - Directory where log files will be saved
* @param {string[]} headers - CSV header row
* @param {number} maxFileAgeDays - How many days log files should be kept
*/
constructor(logDir, headers = ['timestamp', 'level', 'message'], maxFileAgeDays = 30) {
this.logDir = logDir;
this.headers = headers;
this.maxFileAgeDays = maxFileAgeDays;
this.timestamp = null
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
// Cleanup old log files once on startup
this.deleteOldLogFiles().catch(console.error);
}
/**
* Writes a new log entry to today's CSV file
* @param {string} level - Log level (e.g., 'info', 'error')
* @param {string} message - Log message
* @param {string[]} extraFields - Optional additional fields
*/
log(level, message, extraFields = []) {
const timestamp = new Date().toISOString();
const filePath = this.getLogFilePath();
this.ensureFileWithHeaders(filePath);
const row = [timestamp, level, message, ...extraFields]
.map(this.escapeCsv)
.join(',') + '\n';
fs.appendFileSync(filePath, row, (err) => {
if (err) {
console.error('Failed to write to log file:', err);
}
});
}
/**
* Constructs the log file path for today
*/
getLogFilePath() {
const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
let filename = "logs.csv"
if (this.timestamp == null) {
filename = `logs_${today}.csv`
} else {
filename = `${this.timestamp}_logs.csv`
}
return path.join(this.logDir, filename);
}
/**
* Ensures headers are written if file doesn't exist
*/
ensureFileWithHeaders(filePath) {
if (!fs.existsSync(filePath)) {
const headerRow = this.headers.join(',') + '\n';
fs.writeFileSync(filePath, headerRow);
}
}
/**
* Escapes a value for safe CSV output
*/
escapeCsv(value) {
if (value == null) return '';
const str = String(value);
return /[",\n]/.test(str) ? `"${str.replace(/"/g, '""')}"` : str;
}
/**
* Deletes log files older than maxFileAgeDays
*/
async deleteOldLogFiles() {
const files = await fs.promises.readdir(this.logDir);
const now = Date.now();
const maxAgeMs = this.maxFileAgeDays * 24 * 60 * 60 * 1000;
for (const file of files) {
const filePath = path.join(this.logDir, file);
if (!/^logs_\d{4}-\d{2}-\d{2}\.csv$/.test(file)) continue;
try {
const stats = await fs.promises.stat(filePath);
const age = now - stats.mtimeMs;
if (age > maxAgeMs) {
await fs.promises.unlink(filePath);
console.log(`Deleted old log file: ${file}`);
}
} catch (err) {
console.warn(`Could not process file ${file}: ${err.message}`);
}
}
}
}
module.exports = CsvLogger;