privateGPT MCP Server
by Fujitsu-AI
- src
// logger.js
import winston from 'winston';
import chalk from 'chalk';
import stripAnsi from 'strip-ansi';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// ESM-Äquivalent von __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Bestimmen Sie den Pfad zur Log-Datei relativ zu `logger.js`
const LOG_FILE_PATH = path.join(__dirname, '../logs/server.log'); // Passen Sie den Pfad nach Bedarf an
// Hilfsfunktionen für Symbole und Farben
function getLevelSymbol(level) {
const symbols = {
info: 'ℹ️',
warn: '⚠️',
error: '❌',
debug: '🐞',
};
return symbols[level] || '';
}
function chalkForLevel(level) {
const levels = {
info: chalk.blue,
warn: chalk.yellow,
error: chalk.red,
debug: chalk.green,
};
return levels[level] || chalk.white;
}
// Variable zur Steuerung der Dateiausgabe
let allowWrittenLogfile = false;
// Initialisieren der Transports mit nur der Konsolenausgabe
const transports = [
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(({ timestamp, level, message }) => {
const symbol = getLevelSymbol(level);
const coloredMessage = `${chalkForLevel(level)(symbol)} ${message}`;
return `${timestamp} | ${coloredMessage}`;
})
),
}),
];
// Erstellen des Winston-Loggers
const logger = winston.createLogger({
level: 'info',
transports: transports,
});
/**
* Funktion zum Hinzufügen des File-Transports
*/
function addFileTransport() {
const logDir = path.dirname(LOG_FILE_PATH);
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
const fileTransport = new winston.transports.File({
filename: LOG_FILE_PATH,
level: 'info', // Stellen Sie sicher, dass der Level ausreichend niedrig ist
maxsize: 10485760, // 10 MB pro Datei
maxFiles: 5, // Maximal 5 Dateien
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.printf(({ timestamp, level, message }) => {
const symbol = getLevelSymbol(level);
const plainMessage = stripAnsi(`${symbol} ${message}`); // ANSI-Codes entfernen
return `${timestamp} | ${plainMessage}`;
})
),
});
// Fehler-Handler hinzufügen
fileTransport.on('error', (error) => {
console.error(chalk.red('File-Transport Fehler:'), error);
});
// Prüfen, ob der Transport bereits hinzugefügt wurde, um Duplikate zu vermeiden
if (!logger.transports.some(t => t instanceof winston.transports.File)) {
logger.add(fileTransport);
}
}
/**
* Funktion zum Entfernen des File-Transports
*/
function removeFileTransport() {
const fileTransport = logger.transports.find(
(t) => t instanceof winston.transports.File
);
if (fileTransport) {
logger.remove(fileTransport);
}
}
/**
* Funktion zum Setzen von allowWrittenLogfile
* @param {boolean} value - true, um Dateilogs zu erlauben; false, um sie zu deaktivieren
*/
function setAllowWrittenLogfile(value) {
allowWrittenLogfile = value;
if (allowWrittenLogfile) {
addFileTransport();
logEvent('system', 'wrlog', 'File logs activated.', 'File logs are now activated.', 'info');
// Überprüfen, ob der File-Transport hinzugefügt wurde
const fileTransport = logger.transports.find(t => t instanceof winston.transports.File);
if (fileTransport) {
// console.log(chalk.green('File-Transport erfolgreich hinzugefügt.'));
} else {
console.log(chalk.red('Error: File transport could not be added.'));
}
} else {
removeFileTransport();
logEvent('system', 'wrlog', 'File logs deactivated.', 'File logs are now deactivated.', 'info');
}
}
/**
* Zentrale Logging-Funktion
* @param {string} clientIP - IP-Adresse des Clients
* @param {number|string} clientPort - Port des Clients
* @param {string} functionName - Name der aufgerufenen Funktion
* @param {string|object} status - Status der Rückmeldung
* @param {string} level - Log-Level ('info', 'warn', 'error', 'debug')
*/
function logEvent(clientIP, clientPort, functionName, status, level = 'info') {
// Kürzen und formatieren der Felder
const ip = String(clientIP || 'N/A').padEnd(23).substring(0, 23); // Mindestens 8 Zeichen für die IP
const port = String(clientPort || 'N/A').padEnd(5).substring(0, 5); // 5 Zeichen für den Port
const func = String(functionName || 'N/A').padEnd(26).substring(0, 26); // 20 Zeichen für den Funktionsnamen
const stat = String(status || '').padEnd(120).substring(0, 120); // 100 Zeichen für den Status
// Formatierte Logzeile
const logLine = `${ip}:${port} | ${func} | ${stat}`;
// Log-Ausgabe basierend auf dem Level
logger.log({ level, message: logLine });
}
export { logger, logEvent, setAllowWrittenLogfile, LOG_FILE_PATH };