UNPKG

@sehirapp/core-microservice

Version:

Modern mikroservis core paketi - MongoDB 6.7, Express API, Mongoose, PM2 cluster desteği

246 lines (210 loc) 6.02 kB
import winston from 'winston'; class Logger { constructor(config = {}) { const { level = 'info', filename = null, serviceName = 'microservice' } = config; // Request-scoped log collection this.requestLogs = new Map(); // requestId -> logs array this.serviceName = serviceName; const transports = [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ timestamp, level, message, ...meta }) => { let logMessage = `${timestamp} [${level}] ${message}`; if (Object.keys(meta).length) { logMessage += ` ${JSON.stringify(meta)}`; } return logMessage; }) ) }) ]; // Eğer filename verilmişse file transport ekle if (filename) { transports.push( new winston.transports.File({ filename: filename, format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ) }) ); } this.logger = winston.createLogger({ level, format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), transports }); // Cleanup eski request logs - 5 dakika setInterval(() => { this.cleanupOldLogs(); }, 5 * 60 * 1000); } info(message, meta = {}) { this._log('info', message, meta); } error(message, meta = {}) { this._log('error', message, meta); } warn(message, meta = {}) { this._log('warn', message, meta); } debug(message, meta = {}) { this._log('debug', message, meta); } /** * Internal log method - request-scoped collection ile */ _log(level, message, meta = {}) { const timestamp = Date.now(); // Milisaniye epoch // Normal winston logging this.logger[level](message, meta); // Request-scoped log collection const requestId = meta.requestId || this.getCurrentRequestId(); if (requestId && this.requestLogs.has(requestId)) { const logEntry = { microserviceId: this.serviceName, timestamp, type: level, message, meta: { ...meta }, requestId }; this.requestLogs.get(requestId).logs.push(logEntry); } } /** * Request için log collection başlat */ startRequestLogging(requestId, requestInfo = {}) { if (!requestId) { requestId = this.generateRequestId(); } this.requestLogs.set(requestId, { logs: [], startTime: Date.now(), requestInfo, timestamp: Date.now() }); // İlk log entry'si this._log('info', '🔍 Request logging started', { requestId, ...requestInfo }); return requestId; } /** * Request log collection'ı sonlandır ve logları döndür */ finishRequestLogging(requestId) { if (!this.requestLogs.has(requestId)) { return null; } const requestLogData = this.requestLogs.get(requestId); const endTime = Date.now(); const duration = endTime - requestLogData.startTime; // Son log entry'si this._log('info', '✅ Request logging finished', { requestId, totalDuration: `${duration}ms`, totalLogs: requestLogData.logs.length }); // Logs'u al ve cleanup yap const logs = requestLogData.logs; this.requestLogs.delete(requestId); return { requestId, microserviceId: this.serviceName, duration: `${duration}ms`, totalLogs: logs.length, startTime: requestLogData.timestamp, endTime: Date.now(), requestInfo: requestLogData.requestInfo, logs }; } /** * Request için tüm logları al (bitirmeden) */ getRequestLogs(requestId) { if (!this.requestLogs.has(requestId)) { return null; } const requestLogData = this.requestLogs.get(requestId); const duration = Date.now() - requestLogData.startTime; return { requestId, microserviceId: this.serviceName, duration: `${duration}ms`, totalLogs: requestLogData.logs.length, startTime: requestLogData.timestamp, requestInfo: requestLogData.requestInfo, logs: [...requestLogData.logs] // Copy }; } /** * Request ID oluştur */ generateRequestId() { return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Async context'den current request ID'yi al */ getCurrentRequestId() { // AsyncLocalStorage veya cls-hooked kullanılabilir // Şimdilik basit implementation return global.__currentRequestId || null; } /** * Current request ID'yi set et */ setCurrentRequestId(requestId) { global.__currentRequestId = requestId; } /** * Current request ID'yi temizle */ clearCurrentRequestId() { global.__currentRequestId = null; } /** * Eski request loglarını temizle */ cleanupOldLogs() { const now = Date.now(); const maxAge = 10 * 60 * 1000; // 10 dakika for (const [requestId, logData] of this.requestLogs.entries()) { if (now - logData.startTime > maxAge) { this.requestLogs.delete(requestId); } } if (this.requestLogs.size > 0) { this.debug(`🧹 Cleaned up old request logs, active: ${this.requestLogs.size}`); } } /** * Request logs istatistikleri */ getRequestLogsStats() { return { activeRequests: this.requestLogs.size, oldestRequestAge: this.requestLogs.size > 0 ? Math.max(...Array.from(this.requestLogs.values()).map(r => Date.now() - r.startTime)) : 0, serviceName: this.serviceName, timestamp: Date.now() }; } } // Default logger instance const logger = new Logger(); export default Logger; export { logger };