BetterDiscordApp-rauenzi/renderer/src/builtins/developer/debuglogs.js

89 lines
3.3 KiB
JavaScript

import fs from "fs";
import path from "path";
import Builtin from "@structs/builtin";
import DataStore from "@modules/datastore";
import Strings from "@modules/strings";
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 {
// Not been created yet, no need to check filesize
if (!fs.existsSync(this.logFile)) return;
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);
}
}
};