UNPKG

dash-core

Version:

A foundational toolkit of types, collections, services, and architectural patterns designed to accelerate application development.

197 lines (196 loc) 7.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ServiceLogger = exports.LogLevel = void 0; const path_1 = __importDefault(require("path")); const winston_1 = require("winston"); const RESET = '\x1b[0m'; // Reset to default color const RED = '\x1b[31m'; const YELLOW = '\x1b[33m'; const CYAN = "\x1b[36m"; const GREEN = "\x1b[32m"; var LogLevel; (function (LogLevel) { LogLevel["DEBUG"] = "debug"; LogLevel["INFO"] = "info"; LogLevel["WARNING"] = "warn"; LogLevel["ERROR"] = "error"; })(LogLevel || (exports.LogLevel = LogLevel = {})); const LogLevelMap = { [LogLevel.ERROR]: 1, [LogLevel.WARNING]: 2, [LogLevel.INFO]: 3, [LogLevel.DEBUG]: 4 }; const defaultFormat = winston_1.format.combine(winston_1.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston_1.format.errors({ stack: true }), winston_1.format.splat()); const fileFormat = winston_1.format.combine(defaultFormat, winston_1.format.printf((info) => { const { timestamp, level, message, service } = info; const splat = (info[Symbol.for('splat')] || []); let baseLog = `${timestamp}\t${level}\t${service}\t${message}`; if (splat && splat.length > 0) baseLog += '\n' + deserializeSplat(splat); return baseLog; })); const consoleFormat = winston_1.format.combine(defaultFormat, winston_1.format.printf((info) => { const { timestamp, level, message, service } = info; const splat = (info[Symbol.for('splat')] || []); let baseLog = level === LogLevel.INFO || level === LogLevel.DEBUG ? `${CYAN}${timestamp}${RESET}\t${level}\t${GREEN}${service}${RESET}\t${message}` : `${timestamp}\t${level}\t${service}\t${message}`; if (splat && splat.length > 0) baseLog += '\n' + deserializeSplat(splat); if (level === LogLevel.ERROR) return `${RED}${baseLog}${RESET}`; if (level === LogLevel.WARNING) return `${YELLOW}${baseLog}${RESET}`; return baseLog; })); function deserializeSplat(splat) { return splat .map((data) => { if (data instanceof Error) { return data.stack; } if (typeof data === 'object') { try { return JSON.stringify(data, null, 2); } catch { return String(data); } } return String(data); }) .join(' '); } function parseFilter(input) { const map = new Map(); if (!input) { return map; } input.split(",").forEach((raw) => { const item = raw.trim(); if (item === "") return; const isIncluded = !item.startsWith("!"); const name = item.replace(/^!/, "").trim(); map.set(name, isIncluded); }); return map; } function createWinstonLogger(options) { const globalLogLevel = options.globalLogLevel; const targetLogLevel = options.logLevel; const logLevel = LogLevelMap[globalLogLevel] < LogLevelMap[targetLogLevel] ? globalLogLevel : targetLogLevel; const projectDirectory = options.logPath || process.cwd(); const logDirectory = path_1.default.join(projectDirectory, 'logs'); const result = (0, winston_1.createLogger)({ level: logLevel, format: fileFormat, defaultMeta: { service: 'user-service' }, transports: [ new winston_1.transports.File({ filename: path_1.default.join(logDirectory, 'error.log'), level: LogLevel.ERROR }), new winston_1.transports.File({ filename: path_1.default.join(logDirectory, 'combined.log') }), ], }); if (options.verbose) { result.add(new winston_1.transports.Console({ format: consoleFormat })); } return result; } /** Encapsulates service logging with configurable options. */ class ServiceLogger { logger; options; get isObservable() { const item = this.options.globalFilter.get(this.options.serviceName); if (item === undefined) return true; return item; } /** * Creates a new instance of the ServiceLogger class with specified options. * If no options are provided, defaults are used. * @param {ServiceOptions} [options={}] - Configuration options for the logger. * @param {string} options.serviceName - The name of the service (default is "nameless-service"). * @param {LogLevel} options.logLevel - The default log level (default is LogLevel.DEBUG). * @param {boolean} options.verbose - Indicates whether verbose logging is enabled (default is true). * @param {string} options.logPath - The directory where logs will be stored (default is the current working directory). * @param {LogLevel} options.globalLogLevel - The global log level for the service (default is LogLevel.DEBUG). * @param {string} options.globalFilter - A filter string for global logging configuration. */ constructor(options = {}) { this.options = { serviceName: options.serviceName || "nameless-service", logLevel: options.logLevel || LogLevel.DEBUG, verbose: options.verbose || true, logPath: options.logPath || process.cwd(), globalLogLevel: typeof options.globalLogLevel === 'string' ? options.globalLogLevel : options.globalLogLevel || LogLevel.DEBUG, globalFilter: parseFilter(options.globalFilter) }; this.logger = createWinstonLogger(this.options); this.logger.defaultMeta = { service: this.options.serviceName }; } /** * Logs an informational message if the service is observable. * @param {string} message - The message to log. * @param {...unknown[]} meta - Additional metadata to log alongside the message. */ info(message, ...meta) { if (!this.isObservable) return; this.logger.info(message, ...meta); } ; /** * Logs a warning message. * @param {string} message - The message to log. * @param {...unknown[]} meta - Additional metadata to log alongside the message. */ warning(message, ...meta) { this.logger.warn(message, ...meta); } /** * Logs a debug message if the service is observable. * @param {string} message - The message to log. * @param {...unknown[]} meta - Additional metadata to log alongside the message. */ debug(message, ...meta) { if (!this.isObservable) return; this.logger.debug(message, ...meta); } /** * Logs an error message and returns an Error object. * @param {string} message - The error message. * @param {...unknown[]} meta - Additional metadata to log alongside the message. * @returns {Error} The created error. */ error(message, ...meta) { this.logger.error(message, ...meta); return new Error(message); } /** * Adds transport to the logger to write logs to a specified file. * @param {string} relativePath - The relative path where the log file will be stored. * @param {LogLevel} [logLevel] - The log level for this transport. If not provided, all logs will be written. */ addTransport(relativePath, logLevel) { if (!this.options.verbose) return; let transport; const fullLogPath = path_1.default.join(this.options.logPath, relativePath); if (!logLevel) { transport = new winston_1.transports.File({ filename: path_1.default.join(fullLogPath) }); } else { transport = new winston_1.transports.File({ filename: path_1.default.join(fullLogPath), level: logLevel }); } this.logger.add(transport); } } exports.ServiceLogger = ServiceLogger;