UNPKG

@uisap/core

Version:

A modular Fastify-based framework inspired by Laravel

134 lines (125 loc) 4.01 kB
import winston from "winston"; import DailyRotateFile from "winston-daily-rotate-file"; import { join } from "path"; export class Logger { constructor(config = {}) { this.logDir = config.logDir || join(process.cwd(), "logs"); this.level = config.level || process.env.LOG_LEVEL || "info"; const safeStringify = (obj, indent = 2) => { const seen = new WeakSet(); return JSON.stringify( obj, (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return "[Circular]"; } seen.add(value); } return value; }, indent ); }; const getCallerInfo = () => { const err = new Error(); Error.captureStackTrace(err); const stackLines = err.stack.split("\n"); for (let i = 2; i < stackLines.length; i++) { const line = stackLines[i].trim(); if ( !line.includes("node_modules") && !line.includes("logger.js") && !line.includes("winston") && !line.includes("logform") ) { const match = line.match(/([^/\\]+\.js):(\d+):(\d+)/); return match ? `${match[1]}:${match[2]}` : line; } } return "N/A"; }; const customFormat = winston.format.printf( ({ level, message, timestamp, stack, ...metadata }) => { const logMessageText = typeof message === "object" ? safeStringify(message) : message; let logLine = `${timestamp} [${level.toUpperCase()}] ${logMessageText}`; const caller = metadata.caller || getCallerInfo(); if (caller !== "N/A" && !metadata.caller) { logLine += ` | Caller: ${caller}`; } else if (metadata.caller) { logLine += ` | Caller: ${metadata.caller}`; } const metaKeys = Object.keys(metadata).filter( (key) => key !== "level" && key !== "message" && key !== "timestamp" && key !== "caller" && key !== "stack" ); if (metaKeys.length > 0) { const contextParts = metaKeys.map((key) => { const value = metadata[key]; return `${key}=${ typeof value === "object" ? safeStringify(value) : value }`; }); logLine += ` | ${contextParts.join(" ")}`; } if (stack && (level === "error" || metadata.level === "error")) { logLine += `\n Stack: ${stack}`; } return logLine; } ); this.winstonLogger = winston.createLogger({ level: this.level, format: winston.format.combine( winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston.format.errors({ stack: true }), customFormat ), transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), customFormat ), }), new DailyRotateFile({ filename: join(this.logDir, "app-%DATE%.log"), datePattern: "YYYY-MM-DD", maxSize: "10m", maxFiles: "7d", level: "info", zippedArchive: true, }), new DailyRotateFile({ filename: join(this.logDir, "error-%DATE%.log"), datePattern: "YYYY-MM-DD", maxSize: "10m", maxFiles: "7d", level: "error", zippedArchive: true, }), ], }); this.winstonLogger.exitOnError = false; } info(message, context = {}) { this.winstonLogger.info(message, context); } error(message, context = {}) { this.winstonLogger.error(message, context); } warn(message, context = {}) { this.winstonLogger.warn(message, context); } debug(message, context = {}) { this.winstonLogger.debug(message, context); } child(bindings) { return this.winstonLogger.child(bindings); } }