UNPKG

@zowe/imperative

Version:
229 lines 9.53 kB
"use strict"; /* * This program and the accompanying materials are made available under the terms of the * Eclipse Public License v2.0 which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-v20.html * * SPDX-License-Identifier: EPL-2.0 * * Copyright Contributors to the Zowe Project. * */ Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultPrintfFormat = exports.customLevels = void 0; exports.mapLog4jsToDayjsFormat = mapLog4jsToDayjsFormat; exports.translateLog4jsPattern = translateLog4jsPattern; exports.isPatternLayout = isPatternLayout; exports.hasPatternLayout = hasPatternLayout; exports.log4jsConfigToWinstonConfig = log4jsConfigToWinstonConfig; exports.isAppenderWithType = isAppenderWithType; const winston_1 = require("winston"); const os = require("os"); const dayjs = require("dayjs"); exports.customLevels = { levels: { fatal: 0, error: 1, warn: 2, info: 3, mark: 4, debug: 5, trace: 6, all: 7 }, colors: { fatal: "magenta", error: "red", warn: "yellow", info: "green", mark: "white", debug: "blue", trace: "gray", }, }; (0, winston_1.addColors)(exports.customLevels.colors); /** * Maps log4js date formatting specifiers to dayjs format * @param log4jsFormat The log4js date formatting to convert to dayjs format. * @returns The corresponding dayjs format. */ function mapLog4jsToDayjsFormat(log4jsFormat) { // https://github.com/log4js-node/log4js-node/issues/1012#issuecomment-1017144708 // Support reserved log4js -> date-format strings in pattern options switch (log4jsFormat) { case "ISO8601": return "YYYY-MM-DDTHH:mm:ss.SSS"; case "ISO8601_WITH_TZ_OFFSET": // dayjs format for ISO8601 with timezone offset return "YYYY-MM-DDTHH:mm:ss.SSSZZ"; case "ABSOLUTE": return "HH:mm:ss.SSS"; case "DATE": return "DD MM YYYY HH:mm:ss.SSS"; default: break; } // Basic replacements - dayjs uses similar tokens to log4js/fecha for common cases return (log4jsFormat .replace(/yyyy/g, "YYYY") // Year .replace(/yy/g, "YY") // Year, two digits // MM is month (already correct) // dd is day (use DD for dayjs) .replace(/dd/g, "DD") // hh is hour (use HH for 24-hour format in dayjs) .replace(/hh/g, "HH") // mm is minute (already correct) // ss is seconds (already correct) // SSS is milliseconds (already correct) .replace(/O/g, "ZZ")); // Timezone offset } /** * Translates a log4js pattern string into a Winston format object. * Handles common tokens like %d, %p, %m, %c, %n, %h, %z, %%. * Supports multiple %d tokens with different format specifiers (e.g., %d{yyyy/MM/dd}, %d{hh:mm:ss}). * Strips color codes (%[ and %]). * @param pattern The log4js pattern string. * @returns A Winston format object. */ function translateLog4jsPattern(pattern) { return winston_1.format.combine(winston_1.format.timestamp(), // Add timestamp to the info object, default format (ISO) winston_1.format.printf((info) => { // Process the pattern for each log entry let output = pattern; // Handle colorization tokens first (%[ and %]) - simple removal output = output.replace(/%\[/g, "").replace(/%\]/g, ""); const dateTokenRegex = /%d(?:\{([^}]+)\})?/g; // Regex specifically for date tokens output = output.replace(dateTokenRegex, (dateToken, capturedFormat) => { // Default format for plain %d let formatString = "YYYY-MM-DDTHH:mm:ss.SSS"; if (capturedFormat) { // If a format like %d{...} is found, map it formatString = mapLog4jsToDayjsFormat(capturedFormat); } // Use dayjs to format the timestamp with the specific format for this token return dayjs(info.timestamp).format(formatString); }); // Regex for non-date, non-color tokens handled previously const otherTokenRegex = /(%p|%c|%m|%n|%h|%z|%%)/g; output = output.replace(otherTokenRegex, (token) => { var _a; // Handle remaining tokens switch (token) { case "%p": return String(info.level).toLocaleUpperCase(); case "%m": return String(info.message); case "%n": return "\n"; case "%c": return String((_a = info.category) !== null && _a !== void 0 ? _a : "default"); case "%h": return os.hostname(); case "%z": return String(process.pid); case "%%": return "%"; } }); // Add category to info object if not present and %c is in the original pattern if (!info.category && pattern.includes("%c")) { info.category = "default"; } return output; })); } function isPatternLayout(layout) { return typeof layout === "object" && layout !== null && "type" in layout && "pattern" in layout && layout.type === "pattern" && typeof layout.pattern === "string"; } /** * Type guard for log4js appender with a pattern layout. */ function hasPatternLayout(appender) { return (typeof appender === "object" && appender !== null && "layout" in appender && isPatternLayout(appender.layout)); } const defaultPrintfFormat = ({ timestamp, level, message }) => `[${timestamp}] [${level}] ${message}`; exports.defaultPrintfFormat = defaultPrintfFormat; // Define default formats outside the main function const defaultWinstonFormat = winston_1.format.combine(winston_1.format.colorize(), winston_1.format.timestamp(), winston_1.format.printf(exports.defaultPrintfFormat)); const defaultWinstonFileFormat = winston_1.format.combine(winston_1.format.timestamp(), winston_1.format.printf(exports.defaultPrintfFormat)); /** * Translates a log4js-style config to a winston LoggerOptions config. * Supports basic "console" and "file" appenders. * Handles basic log4js pattern layouts. * @param log4jsConfig The full log4js configuration object. * @param level The desired log level for this specific logger configuration. * @param includeAppenders An array of appender names to include in the returned transports. */ function log4jsConfigToWinstonConfig(log4jsConfig, level, includeAppenders) { var _a; const winstonTransports = []; const allAppenders = (_a = log4jsConfig.appenders) !== null && _a !== void 0 ? _a : {}; // Map only the specified appenders to winston transports for (const appenderName of includeAppenders) { const appender = allAppenders[appenderName]; if (!appender) { // eslint-disable-next-line no-console console.warn(`Appender "${appenderName}" specified for category not found in log4jsConfig.appenders. Skipping.`); continue; } let winstonFormat = defaultWinstonFormat; let winstonFileFormat = defaultWinstonFileFormat; // Check for layout pattern if (hasPatternLayout(appender)) { try { // Add try-catch for robustness during translation const pattern = appender.layout.pattern; const translatedFormat = translateLog4jsPattern(pattern); // Apply colorize only for console transport formats derived from patterns winstonFormat = winston_1.format.combine(winston_1.format.colorize(), translatedFormat); winstonFileFormat = translatedFormat; // No colorize for files } catch (error) { // Log an error or warning if translation fails, and fall back to default // eslint-disable-next-line no-console console.warn(`Failed to translate log4js pattern for appender "${appenderName}". Falling back to default format. Error: ${error.message}`); // Keep defaults } } // Use the level passed specifically for this configuration const transportLevel = level; if (isAppenderWithType(appender, "console")) { winstonTransports.push(new winston_1.transports.Console({ level: transportLevel, format: winstonFormat, })); } else if (isAppenderWithType(appender, "file") || isAppenderWithType(appender, "fileSync")) { winstonTransports.push(new winston_1.transports.File({ filename: appender.filename, level: transportLevel, format: winstonFileFormat, // Use potentially translated format (no color) })); } } // Use the level passed into the function for this specific logger config return { levels: exports.customLevels.levels, level: level, transports: winstonTransports, exitOnError: false, }; } /** * Type guard for log4js appender with a specific type. */ function isAppenderWithType(appender, type) { return (typeof appender === "object" && appender !== null && "type" in appender && appender.type === type); } //# sourceMappingURL=log4jsToWinston.js.map