UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

281 lines 10.8 kB
import { configInfo } from "../_dependencies"; import { getSecondsElapsed } from "../helpers/date"; import { consoleLoggerFilter, isDebug } from "../helpers/debug"; import { getGlobal, jsonClone } from "../helpers/objects"; import { padLeft, padRight } from "../helpers/strings"; import { isFunction, isNullOrEmptyString, isNullOrUndefined, isNumber, isNumeric, isString } from "../helpers/typecheckers"; const DEFAULT_LOGGER_NAME = "DEFAULT"; const LoggerPrefix = "[kw]"; // eslint-disable-next-line no-shadow export var LoggerLevel; (function (LoggerLevel) { LoggerLevel[LoggerLevel["VERBOSE"] = 0] = "VERBOSE"; LoggerLevel[LoggerLevel["DEBUG"] = 1] = "DEBUG"; LoggerLevel[LoggerLevel["INFO"] = 2] = "INFO"; LoggerLevel[LoggerLevel["LOG"] = 3] = "LOG"; /** shows when debug=off */ LoggerLevel[LoggerLevel["WARN"] = 4] = "WARN"; /** shows when debug=off */ LoggerLevel[LoggerLevel["TRACE"] = 5] = "TRACE"; /** shows when debug=off */ LoggerLevel[LoggerLevel["ERROR"] = 6] = "ERROR"; LoggerLevel[LoggerLevel["OFF"] = 10] = "OFF"; })(LoggerLevel || (LoggerLevel = {})); export class ConsoleLogger { constructor(context) { this.context = context; } static get(name, prefix) { var global = ConsoleLogger._getGlobal(); var loggers = global.loggers; if (!global.loggedBuild) { global.loggedBuild = true; console.debug(`${ConsoleLogger.commonPrefix()} KWIZ build ${configInfo.ReleaseStatus}.${configInfo.BuildNumber}`); } const key = `${name}|${prefix}`; return loggers[key] || (loggers[key] = new ConsoleLogger({ name: name, prefix: prefix })); } static _getGlobal() { var global = getGlobal("loggers", { loggedBuild: false, loggers: {} }, true); return global; } static _getDefaultLogger() { return ConsoleLogger.get(DEFAULT_LOGGER_NAME); } static setLevel(newLevel) { ConsoleLogger._getDefaultLogger().setLevel(newLevel); } static getLevel() { return ConsoleLogger._getDefaultLogger().getLevel(); } static debug(message) { ConsoleLogger._getDefaultLogger().debug(message); } static info(message) { ConsoleLogger._getDefaultLogger().info(message); } static log(message) { ConsoleLogger._getDefaultLogger().log(message); } static warn(message) { ConsoleLogger._getDefaultLogger().warn(message); } static error(message) { ConsoleLogger._getDefaultLogger().error(message); } static trace(message) { ConsoleLogger._getDefaultLogger().trace(message); } static commonPrefix(prefix) { var d = new Date(); var timestamp = padLeft(d.getHours().toString(), 2, "0") + ":" + padLeft(d.getMinutes().toString(), 2, "0") + ":" + padLeft(d.getSeconds().toString(), 2, "0") + "." + padRight(d.getMilliseconds().toString(), 3, "0"); return `[${timestamp}] ${prefix || LoggerPrefix}`; } contextPrefix() { return `${ConsoleLogger.commonPrefix(this.context.prefix)} [${this.context.name}]`; } format(message) { return `${this.contextPrefix()} ${message}`; } setLevel(newLevel) { if (isNumeric(newLevel)) { this.context.filterLevel = newLevel; } } getLevel() { if (isNumeric(this.context.filterLevel)) return this.context.filterLevel; else return isDebug() ? LoggerLevel.VERBOSE : LoggerLevel.WARN; } enabledFor(level) { if (consoleLoggerFilter().indexOf(this.context.name) >= 0) return false; var filterLevel = this.getLevel(); return level >= filterLevel; } debug(message) { this.logWithLevel(LoggerLevel.DEBUG, message); } info(message) { this.logWithLevel(LoggerLevel.INFO, message); } log(message) { this.logWithLevel(LoggerLevel.LOG, message); } /** output a message when debug is off */ warn(message) { this.logWithLevel(LoggerLevel.WARN, message); } /** output a message when debug is off */ error(message) { this.logWithLevel(LoggerLevel.ERROR, message); } /** output a message when debug is off */ trace(message) { this.logWithLevel(LoggerLevel.TRACE, message); } /**start timer on a label, call timeEnd with the same label to print out the time that passed */ time(label) { if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.time)) console.time(`[timer] [kw] [${this.context.name}] ${label}`); } /**start timer on a label, call timeEnd with the same label to print out the time that passed */ timeEnd(label) { if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.timeEnd)) console.timeEnd(`[timer] [kw] [${this.context.name}] ${label}`); } /**prints an array or dictionary to the console inside a group */ table(data, groupLabel, groupCollapsed) { if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.table)) { this.group(() => console.table(data), groupLabel, groupCollapsed); } } /**prints a JSON object to the console inside a group */ json(data, groupLabel, groupCollapsed) { if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.dir)) { this.group(() => console.dir(data), groupLabel, groupCollapsed); } } /**prints an XML object to the console inside a group. If data is string that looks like an XML - will try to parse it. */ xml(data, groupLabel, groupCollapsed) { if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.dirxml)) { this.group(() => { if (isString(data) && data.startsWith('<')) { try { //maybe this string is an html element? data = new DOMParser().parseFromString(data, "text/html"); } catch (e) { } } console.dirxml(data); }, groupLabel, groupCollapsed); } } /** render messages inside a group, and closes the group when done. if a label is not provided - a group will not be rendered */ group(renderContent, label, collapsed) { let hadGroup = false; if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.group) && !isNullOrEmptyString(label)) { if (collapsed) { console.groupCollapsed(`${this.contextPrefix()} ${label}`); } else { console.group(`${this.contextPrefix()} ${label}`); } hadGroup = true; } if (hadGroup) this.time(label); //we must run render content even if no groups - since this might hold other code the caller needs to run renderContent(); if (hadGroup) { this.timeEnd(label); console.groupEnd(); } } groupSync(label, renderContent, options) { if (isNullOrEmptyString(label)) label = "SyncGroup"; let { logMessages, start, logMessage } = this.$startGroup(); let result; try { result = renderContent(logMessage); } catch (e) { logMessage(`Unhandled exception: ${e}`); throw this.$finishGroup(label, e, start, logMessages, options); } return this.$finishGroup(label, result, start, logMessages, options); } async groupAsync(label, renderContent, options) { if (isNullOrEmptyString(label)) label = "AsyncGroup"; let { logMessages, start, logMessage } = this.$startGroup(); let result; try { result = await renderContent(logMessage); } catch (e) { logMessage(`Unhandled exception: ${e}`); throw this.$finishGroup(label, e, start, logMessages, options); } return this.$finishGroup(label, result, start, logMessages, options); } $startGroup() { let logMessages = []; let start = new Date(); let lastMessage = start; let logMessage = (message) => { logMessages.push({ message: isString(message) || isNullOrUndefined(message) ? message : jsonClone(message), seconds: getSecondsElapsed(lastMessage) }); lastMessage = new Date(); }; return { logMessage, logMessages, start }; } $finishGroup(label, result, start, logMessages, options) { if (options && options.supress) return result; label = `${label} (${getSecondsElapsed(start)}s)`; if (this.enabledFor(LoggerLevel.DEBUG) && isFunction(console.group) && !isNullOrEmptyString(label)) { if (options && options.expand) { console.group(`${this.contextPrefix()} ${label}`); } else { console.groupCollapsed(`${this.contextPrefix()} ${label}`); } } else return result; //drop directly, without a prefix, in the group logMessages.forEach(m => { if (isString(m.message)) console.debug(`(${m.seconds}s) ${m.message}`); else { console.debug(`(${m.seconds}s) ${m.message.label}`); console.dir(m.message.value); } }); console.groupEnd(); return result; } logWithLevel(level, message) { try { if (this.enabledFor(level)) { var isSimpleObject = isString(message) || isNumber(message); var logMessage = this.format(isSimpleObject ? "%s" : "%o"); switch (level) { case LoggerLevel.DEBUG: console.debug(logMessage, message); break; case LoggerLevel.ERROR: console.error(logMessage, message); break; case LoggerLevel.WARN: console.warn(logMessage, message); break; case LoggerLevel.INFO: console.info(logMessage, message); break; case LoggerLevel.TRACE: console.trace(logMessage, message); break; default: console.log(logMessage, message); } } } catch (ex) { //empty } } } //# sourceMappingURL=consolelogger.js.map