Last active
November 10, 2023 15:58
-
-
Save peaBerberian/fa3d5068e5178144190a429953d7095b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ================================ HTML-LOGGER ================================ | |
// | |
// This code will display a semi-opaque div HTMLElement on the top of the screen | |
// containing log produced through `console` methods (and optionally logging | |
// requests). | |
// | |
// You can configure it by updating the variables below. | |
/** | |
* To set to `true` to also show HTTP(S) requests made through either the | |
* `XMLHttpRequest` or `fetch` API. | |
* | |
* Note that by enabling it you risk showing a lot of logs on the screen. | |
*/ | |
var SHOULD_LOG_REQUESTS = false; | |
/** Maximum amounts of logs that can be shown on the screen at any given time. */ | |
var MAX_NUMBER_OF_LOGS = 50; | |
/** | |
* Maximum number UTF-16 code units a shown log string can have. | |
* Logs exceeding that size will be shortened. | |
*/ | |
var MAX_LOG_LENGTH = 2e3; | |
/** | |
* Console methods patched by this tool. | |
* | |
* You can remove elements to only keep those you feel are important if doing so | |
* on the application-side is not straightforward. | |
*/ | |
var PATCHED_LOG_FUNCTIONS = [ | |
"log", | |
"error", | |
"info", | |
"warn", | |
"debug" | |
]; | |
/** Style of the whole div on which logs will be appended. */ | |
var LOG_CONTAINER_ELT_STYLE = { | |
position: "fixed", | |
top: "0px", | |
left: "0px", | |
width: "100%", | |
fontSize: "12px", | |
fontFamily: "monospace mono", | |
zIndex: "999999999999999999", | |
backgroundColor: "#00000099", | |
color: "#ffffff", | |
display: "flex", | |
flexDirection: "column-reverse", | |
pointerEvents: "none", | |
padding: "20px" | |
}; | |
/** | |
* Style of a single log appended to the log container. | |
* | |
* Note: the `color` style will be overwritten depending on the type of logs and | |
* can be configured below. | |
*/ | |
var LOG_ELT_STYLE = { | |
backgroundColor: "transparent", | |
margin: "0px", | |
padding: "0px", | |
}; | |
/** Color of logs about network requests. */ | |
var LOG_COLOR_NETWORK = "#ff77ff"; | |
/** Color of "error" logs. */ | |
var LOG_COLOR_ERROR = "#ff9999"; | |
/** Color of "warning" logs. */ | |
var LOG_COLOR_WARNING = "#ffff66"; | |
/** Color of "info" logs. */ | |
var LOG_COLOR_INFO = "#66ffff"; | |
/** Color of other logs not categorized previously. */ | |
var LOG_COLOR_OTHERS = "#ffffff"; | |
// END OF CONFIGURATION | |
// ============================================================================= | |
if (MAX_NUMBER_OF_LOGS <= 0) { | |
throw new Error("HTML-LOGGER: Invalid maximum number of logs"); | |
} | |
if (MAX_LOG_LENGTH <= 0) { | |
throw new Error("HTML-LOGGER: Invalid maximum log length"); | |
} | |
var loggerElt = document.createElement("div"); | |
var styleKeys = Object.keys(LOG_CONTAINER_ELT_STYLE); | |
for (var ctnrStyleIdx = 0; ctnrStyleIdx < styleKeys.length; ctnrStyleIdx++) { | |
var styleProp = styleKeys[ctnrStyleIdx]; | |
var styleValue = LOG_CONTAINER_ELT_STYLE[styleProp]; | |
loggerElt.style[styleProp] = styleValue; | |
} | |
if (document.body != null) { | |
document.body.appendChild(loggerElt); | |
} else { | |
// TODO is this scenario possible? | |
document.addEventListener("DOMContentLoaded", function () { | |
document.body.appendChild(loggerElt); | |
}); | |
} | |
var spyRemovers = PATCHED_LOG_FUNCTIONS.map(function (meth) { | |
var oldConsoleFn = console[meth]; | |
console[meth] = function () { | |
var args = []; | |
for (var _i = 0; _i < arguments.length; _i++) { | |
args[_i] = arguments[_i]; | |
} | |
var argStr = args.map(processLogArg).join(" "); | |
addLog(meth, argStr); | |
return oldConsoleFn.apply(this, args); | |
}; | |
return function () { | |
console[meth] = oldConsoleFn; | |
}; | |
}); | |
if (SHOULD_LOG_REQUESTS) { | |
var originalXhrOpen_1 = XMLHttpRequest.prototype.open; | |
XMLHttpRequest.prototype.open = function () { | |
var method = arguments[0]; | |
var url = arguments[1]; | |
if (typeof method !== "string" || typeof url !== "string") { | |
return originalXhrOpen_1.apply(this, arguments); | |
} | |
this.addEventListener("load", function () { | |
addLog("Network", "Loaded ".concat(method, " XHR from: ").concat(url, " (status: ").concat(this.status, ")")); | |
}); | |
this.addEventListener("error", function () { | |
addLog("Network", "Errored ".concat(method, " XHR from: ").concat(url)); | |
}); | |
this.abort = function () { | |
addLog("Network", "Aborted ".concat(method, " XHR from: ").concat(url)); | |
return XMLHttpRequest.prototype.abort.apply(this, arguments); | |
}; | |
this.send = function () { | |
addLog("Network", "Sending ".concat(method, " XHR to: ").concat(url)); | |
return XMLHttpRequest.prototype.send.apply(this, arguments); | |
}; | |
return originalXhrOpen_1.apply(this, arguments); | |
}; | |
spyRemovers.push(function () { | |
XMLHttpRequest.prototype.open = originalXhrOpen_1; | |
}); | |
var originalFetch_1 = window.fetch; | |
window.fetch = function () { | |
var url; | |
var method; | |
if (arguments[0] == null) { | |
url = void 0; | |
} | |
else if (typeof arguments[0] === "string") { | |
url = arguments[0]; | |
} | |
else if (arguments[0] instanceof URL) { | |
url = arguments[0].href; | |
} | |
else if (typeof arguments[0].url === "string") { | |
url = arguments[0].url; | |
} | |
else { | |
try { | |
url = arguments[0].toString(); | |
} | |
catch (_) { | |
} | |
} | |
if (arguments[0] == null) { | |
method = "GET"; | |
} | |
else if (typeof arguments[0].method === "string") { | |
method = arguments[0].method; | |
} | |
else if (arguments[1] != null && typeof arguments[1].method === "string") { | |
method = arguments[0].method; | |
} | |
else { | |
method = "GET"; | |
} | |
addLog("Network", "Sending ".concat(method, " fetch to: ").concat(url)); | |
var realFetch = originalFetch_1.apply(this, arguments); | |
return realFetch.then(function (res) { | |
addLog("Network", "Loaded ".concat(method, " fetch from: ").concat(url, " (status: ").concat(res.status, ")")); | |
return res; | |
}, function (err) { | |
addLog("Network", "Errored/Aborted ".concat(method, " fetch from: ").concat(url)); | |
throw err; | |
}); | |
}; | |
spyRemovers.push(function () { | |
window.fetch = originalFetch_1; | |
}); | |
} | |
function addLog(level, str) { | |
var logElt = document.createElement("pre"); | |
var preStyleKeys = Object.keys(LOG_ELT_STYLE); | |
for (var preStyleIdx = 0; preStyleIdx < preStyleKeys.length; preStyleIdx++) { | |
var styleProp = preStyleKeys[preStyleIdx]; | |
var styleValue = LOG_ELT_STYLE[styleProp]; | |
logElt.style[styleProp] = styleValue; | |
} | |
logElt.style.color = | |
level === "Network" ? LOG_COLOR_NETWORK : | |
level === "error" ? LOG_COLOR_ERROR : | |
level === "warning" ? LOG_COLOR_WARNING : | |
level === "info" ? LOG_COLOR_INFO : | |
LOG_COLOR_OTHERS; | |
var date = new Date(); | |
var strDate = | |
String(date.getHours()) + | |
":" + | |
String(date.getMinutes()) + | |
":" + | |
String(date.getSeconds()); | |
logElt.textContent = strDate + " [" + level + "] " + str; | |
while (loggerElt.children.length >= MAX_NUMBER_OF_LOGS) { | |
loggerElt.removeChild(loggerElt.children[0]); | |
} | |
loggerElt.appendChild(logElt); | |
return; | |
} | |
function processLogArg(arg2) { | |
var processed; | |
switch (typeof arg2) { | |
case "function": | |
case "symbol": | |
case "bigint": | |
processed = ""; | |
break; | |
case "string": | |
case "number": | |
case "boolean": | |
case "undefined": | |
processed = arg2; | |
break; | |
case "object": | |
if (arg2 === null) { | |
processed = "null"; | |
} | |
else if (arg2 instanceof Error) { | |
processed = "NAME: " + String(arg2.name) + " ~ CODE: " + String(arg2.code) + " ~ MESSAGE: " + String(arg2.message); | |
} | |
else { | |
processed = "{}"; | |
} | |
break; | |
default: | |
processed = ""; | |
break; | |
} | |
if (typeof processed === "string" && processed.length > MAX_LOG_LENGTH) { | |
return processed.substring(0, MAX_LOG_LENGTH - 1) + "\u2026"; | |
} | |
return processed; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment