86 lines
3.1 KiB
JavaScript
86 lines
3.1 KiB
JavaScript
import fs from "fs";
|
|
import path from "path";
|
|
|
|
import Builtin from "@structs/builtin";
|
|
import DataStore from "@modules/datastore";
|
|
|
|
import Modals from "@ui/modals";
|
|
|
|
|
|
const timestamp = () => new Date().toISOString().replace("T", " ").replace("Z", "");
|
|
const levels = ["log", "info", "warn", "error", "debug"];
|
|
const getCircularReplacer = () => {
|
|
const seen = new WeakSet();
|
|
return (key, value) => {
|
|
if (typeof value === "object" && value !== null) {
|
|
if (seen.has(value)) return "[Circular Reference]";
|
|
seen.add(value);
|
|
}
|
|
return value;
|
|
};
|
|
};
|
|
|
|
const occurrences = (source, substring) => {
|
|
const regex = new RegExp(substring, "g");
|
|
return (source.match(regex) || []).length;
|
|
};
|
|
|
|
export default new class DebugLogs extends Builtin {
|
|
get name() {return "DebugLogs";}
|
|
get category() {return "developer";}
|
|
get id() {return "debugLogs";}
|
|
|
|
async enabled() {
|
|
this.logFile = path.join(DataStore.dataFolder, "debug.log");
|
|
await this.checkFilesize();
|
|
this.stream = fs.createWriteStream(this.logFile, {flags: "a"});
|
|
this.stream.write(`\n\n================= Starting Debug Log (${timestamp()}) =================\n`);
|
|
for (const level of levels) {
|
|
this.after(console, level, (_, originalArgs) => {
|
|
const data = this.sanitize(...originalArgs);
|
|
this.stream.write(`[${timestamp()}][CONSOLE:${level.toUpperCase()}] ${data}\n`);
|
|
});
|
|
}
|
|
}
|
|
|
|
disabled() {
|
|
this.unpatchAll();
|
|
if (this.stream) this.stream.end(`\n\n================= Ending Debug Log (${timestamp()}) =================`);
|
|
}
|
|
|
|
sanitize(...args) {
|
|
const sanitized = [];
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
if (typeof(arg) === "string") {
|
|
const styleCount = occurrences(arg, "%c");
|
|
sanitized.push(arg.replace(/%c/g, ""));
|
|
if (styleCount > 0) i += styleCount;
|
|
}
|
|
|
|
if (typeof(arg) === "undefined") sanitized.push("undefined");
|
|
if (typeof(arg) === "object" && arg && arg.message && arg.stack) sanitized.push(`${arg.message}\n${arg.stack}`);
|
|
else if (typeof(arg) === "object") sanitized.push(JSON.stringify(arg, getCircularReplacer()));
|
|
if (typeof(arg) === "function" || typeof(arg) === "boolean" || typeof(arg) === "number") sanitized.push(arg.toString());
|
|
}
|
|
return sanitized.join(" ");
|
|
}
|
|
|
|
async checkFilesize() {
|
|
try {
|
|
const stats = fs.statSync(this.logFile);
|
|
const mb = stats.size / (1024 * 1024);
|
|
if (mb < 100) return; // Under 100MB, all good
|
|
return new Promise(resolve => Modals.showConfirmationModal(Strings.Modals.additionalInfo, Strings.Modals.debuglog, {
|
|
confirmText: Strings.Modals.okay,
|
|
cancelText: Strings.Modals.cancel,
|
|
danger: true,
|
|
onConfirm: () => fs.rmSync(this.logFile),
|
|
onClose: resolve
|
|
}));
|
|
}
|
|
catch (e) {
|
|
this.error(e);
|
|
}
|
|
}
|
|
}; |