@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
281 lines • 10.8 kB
JavaScript
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