Skip to content

Instantly share code, notes, and snippets.

@madrang
Created April 27, 2020 23:42
Show Gist options
  • Save madrang/0f4b456c29fa9fc9d35f84721b1da638 to your computer and use it in GitHub Desktop.
Save madrang/0f4b456c29fa9fc9d35f84721b1da638 to your computer and use it in GitHub Desktop.
JS Events Logging
/*
* Module code goes here. Use 'module.exports' to export things:
* module.exports.thing = 'a thing';
*
* You can import it from another modules like this:
* var mod = require('events');
* mod.thing == 'a thing'; // true
*/
module.exports = (function(){
const _eventLevel = {
// System is in a situation that poses an immediate risk,
// require urgent intervention to prevent a worsening of the situation.
EMERGENCY: 0
// An error of sufficient magnitude that the system aborted all operations to protect itself.
, FATAL: 1 << 0
// An error of sufficient magnitude that it cannot be handled.
// Should be corrected immediately. Impact system operations.
, CRITICAL: 1 << 1
// An error that prevents an operation from completing successfully,
// Could be handled without affecting the system continued operation.
// Should be corrected immediately, but the failure is in a secondary system. System remains functional.
, ERROR: 1 << 2
// Indication that an error will occur if no action is taken.
, WARNING: 1 << 3
// Events that are unusual but not error conditions.
, NOTICE: 1 << 4
// Normal operational messages.
, INFORMATIVE: 1 << 5
// Debug information that will only need to be seen when tracking down specific problems.
, DEBUG: 1 << 6
// Not sure if usefull, use Trace.
// Spam box, Whatever info that could be usefull...
, TRACE: 1 << 7
// All messages will be logged.
, ALL: 0xFF
};
// Minimal logging, errors and warning only.
_eventLevel.MINIMUM = _eventLevel.FATAL | _eventLevel.CRITICAL | _eventLevel.ERROR | _eventLevel.WARNING;
// Standard messages will be logged.
_eventLevel.STANDARD = _eventLevel.MINIMUM | _eventLevel.NOTICE | _eventLevel.INFORMATIVE;
// Verbose, Standard and Debugging.
// Does not include Trace.
_eventLevel.VERBOSE = _eventLevel.STANDARD | _eventLevel.DEBUG;
let _consoleLogLevel = _eventLevel.STANDARD;
let _consoleLogFilter = function(logger, logLvl, ...args){
return true;
};
const _Event = function(level){
this.level = level;
};
Object.freeze(_Event);
const _getColor = function (level) {
switch (level) {
case _eventLevel.TRACE:
return "RoyalBlue";
case _eventLevel.DEBUG:
return "SeaGreen";
case _eventLevel.INFORMATIVE:
return "WhiteSmoke";
case _eventLevel.NOTICE:
return "Lime";
case _eventLevel.WARNING:
return "Yellow";
case _eventLevel.ERROR:
return "Orangered";
case _eventLevel.FATAL:
return "Crimson";
case _eventLevel.CRITICAL:
return "MediumVioletRed";
case _eventLevel.EMERGENCY:
return "DeepPink";
default:
return "White";
}
};
const _mapArgsToString = function (...args) {
return _.map(args, (a) => {
const aType = typeof a;
if(aType === 'undefined') {
return 'undefined';
} else if (aType === "string") {
return a;
} else if(typeof a.toString === "function") {
return a.toString();
} else {
return JSON.stringify(a);
}
});
};
const _printEvent = function(logLevel, ...args) {
if (!Number.isInteger(logLevel) || (logLevel & _consoleLogLevel === 0)) {
return;
}
const color = _getColor(logLevel);
const message = _mapArgsToString(...args).join('');
console.log("<font color=\"" + color + "\">" + message + "</>");
};
const _logBase = function(name) {
if (typeof name === "undefined") {
throw new Error("Name is undefined.")
} else if (typeof name === "string") {
this.name = name;
} else {
throw new Error("Name is not a string.")
}
};
//Add log functions.
for (const levelName of Object.keys(_eventLevel)) {
const logLvl = _eventLevel[levelName];
_logBase.prototype[levelName.toLowerCase()] = function(...args) {
if (_consoleLogFilter(this, logLvl, ...args) !== true) {
return;
}
if (typeof this.name !== "undefined" && this.name !== "System") {
args.unshift(this.name, "-->");
}
_printEvent(logLvl, ...args);
};
}
_logBase.prototype.info = _logBase.prototype.informative;
_logBase.prototype.warn = _logBase.prototype.warning;
const _logHandler = Object.create(null);
_logHandler.set = function(target, propertyKey, value, receiver) {
Reflect.set(target, propertyKey, value, receiver);
};
const _createLogger = function(parentLogger, name) {
let newLoggerName;
if (typeof parentLogger === "string" && typeof name === "undefined") {
//Name was passed as first arg.
newLoggerName = parentLogger;
} else if (typeof name === "string") {
if (typeof parentLogger === "object" && typeof parentLogger.name === "string" && parentLogger.name !== "System") {
newLoggerName = [parentLogger.name, "->", name].join('');
} else {
//No parent.
newLoggerName = name;
}
} else {
throw new Error("Name is not a string.")
}
return new Proxy(new _logBase(newLoggerName), _logHandler);
};
_logHandler.get = function(target, propertyKey) {
const propType = typeof propertyKey;
if (propType === "undefined") {
throw new Error("propertyKey is undefined.");
}
if (propertyKey in target) {
const propVal = Reflect.get(target, propertyKey);
return propVal;
}
if (propType === "object") {
//WeakMap keys must be objects, not primitive values
let weakLogMap;
if (typeof target.__weakLogMap === "undefined") {
weakLogMap = new WeakMap();
target.__weakLogMap = weakLogMap;
} else {
weakLogMap = target.__weakLogMap;
}
if (weakLogMap.has(propertyKey)) {
return weakLogMap.get(propertyKey);
} else {
let newLoggerName;
if (typeof propertyKey.name === "string") {
newLoggerName = propertyKey.name;
} else if(typeof propertyKey.toString === "function") {
newLoggerName = propertyKey.toString();
} else {
//If function, propertyKey.displayName
newLoggerName = propertyKey.prototype.name;
}
const newLog = _createLogger(target, newLoggerName);
weakLogMap.set(propertyKey, newLog);
return newLog;
}
} else {
const newLog = _createLogger(target, propertyKey);
return newLog;
}
};
Object.freeze(_logHandler);
const logProxy = _createLogger("System");
return {
Event: _Event
, levels: _eventLevel
, write: _printEvent
, setLogLevel: function(logLevel) {
if (!Number.isInteger(logLevel)) {
throw new Error("logLevel is not an integer.")
}
_consoleLogLevel = logLevel;
}
, setLogFilter: function(logFilter) {
if (typeof logFilter !== "function") {
throw new Error("logFilter is not a function.")
}
_consoleLogFilter = logFilter;
}
, log: logProxy
, mapArgsToString: _mapArgsToString
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment