diff --git a/src/db/index.ts b/src/db/index.ts index 336af0123..839094c37 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -112,7 +112,6 @@ db.on("populate", async () => { // ended up throwing lots of errors to the user... and they'd end up in a state // where they couldn't take action because they couldn't unlock that identity.) -// check for the secret in storage async function useSecretAndInitializeAccountsDB( secretDB: SecretDexie, accountsDB: SensitiveDexie, @@ -214,26 +213,31 @@ export async function updateAccountSettings( } } -// similar method is in the sw_scripts/additional-scripts.js file -export async function logConsoleAndDb( - message: string, - isError = false, -): Promise { - if (isError) { - logger.error(`${new Date().toISOString()} ${message}`); - } else { - logger.log(`${new Date().toISOString()} ${message}`); - } - +export async function logToDb(message: string): Promise { await db.open(); const todayKey = new Date().toDateString(); // only keep one day's worth of logs const previous = await db.logs.get(todayKey); if (!previous) { // when this is today's first log, clear out everything previous + // to avoid the log table getting too large + // (let's limit a different way someday) await db.logs.clear(); } const prevMessages = (previous && previous.message) || ""; const fullMessage = `${prevMessages}\n${new Date().toISOString()} ${message}`; await db.logs.update(todayKey, { message: fullMessage }); } + +// similar method is in the sw_scripts/additional-scripts.js file +export async function logConsoleAndDb( + message: string, + isError = false, +): Promise { + if (isError) { + logger.error(`${new Date().toISOString()} ${message}`); + } else { + logger.log(`${new Date().toISOString()} ${message}`); + } + await logToDb(message); +} diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 8eaebed90..fcf0847a6 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,18 +1,46 @@ +import { logToDb } from "../db"; + +function safeStringify(obj: unknown) { + const seen = new WeakSet(); + + return JSON.stringify(obj, (key, value) => { + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return "[Circular]"; + } + seen.add(value); + } + + if (typeof value === "function") { + return `[Function: ${value.name || "anonymous"}]`; + } + + return value; + }); +} + export const logger = { log: (message: string, ...args: unknown[]) => { if (process.env.NODE_ENV !== "production") { // eslint-disable-next-line no-console console.log(message, ...args); + const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; + logToDb(message + argsString); } }, warn: (message: string, ...args: unknown[]) => { if (process.env.NODE_ENV !== "production") { // eslint-disable-next-line no-console console.warn(message, ...args); + const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; + logToDb(message + argsString); } }, error: (message: string, ...args: unknown[]) => { + // Errors will always be logged // eslint-disable-next-line no-console - console.error(message, ...args); // Errors should always be logged + console.error(message, ...args); + const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; + logToDb(message + argsString); }, };