mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-04 06:31:35 +08:00
refactor(utils): add safeExtractMessageAndStackFromError util to remove code duplication
This commit is contained in:
parent
e20b662ea7
commit
ecf1a0e4ad
@ -9,6 +9,7 @@ import log from "../../services/log.js";
|
|||||||
import NotFoundError from "../../errors/not_found_error.js";
|
import NotFoundError from "../../errors/not_found_error.js";
|
||||||
import type { Request, Response } from "express";
|
import type { Request, Response } from "express";
|
||||||
import ValidationError from "../../errors/validation_error.js";
|
import ValidationError from "../../errors/validation_error.js";
|
||||||
|
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||||
|
|
||||||
function exportBranch(req: Request, res: Response) {
|
function exportBranch(req: Request, res: Response) {
|
||||||
const { branchId, type, format, version, taskId } = req.params;
|
const { branchId, type, format, version, taskId } = req.params;
|
||||||
@ -38,10 +39,11 @@ function exportBranch(req: Request, res: Response) {
|
|||||||
throw new NotFoundError(`Unrecognized export format '${format}'`);
|
throw new NotFoundError(`Unrecognized export format '${format}'`);
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const message = `Export failed with following error: '${(e instanceof Error) ? e.message : e}'. More details might be in the logs.`;
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
|
const message = `Export failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||||
taskContext.reportError(message);
|
taskContext.reportError(message);
|
||||||
|
|
||||||
log.error((e instanceof Error) ? message + e.stack : message);
|
log.error(errMessage + errStack);
|
||||||
|
|
||||||
res.setHeader("Content-Type", "text/plain").status(500).send(message);
|
res.setHeader("Content-Type", "text/plain").status(500).send(message);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import TaskContext from "../../services/task_context.js";
|
|||||||
import ValidationError from "../../errors/validation_error.js";
|
import ValidationError from "../../errors/validation_error.js";
|
||||||
import type { Request } from "express";
|
import type { Request } from "express";
|
||||||
import type BNote from "../../becca/entities/bnote.js";
|
import type BNote from "../../becca/entities/bnote.js";
|
||||||
|
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||||
|
|
||||||
async function importNotesToBranch(req: Request) {
|
async function importNotesToBranch(req: Request) {
|
||||||
const { parentNoteId } = req.params;
|
const { parentNoteId } = req.params;
|
||||||
@ -69,7 +70,7 @@ async function importNotesToBranch(req: Request) {
|
|||||||
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
|
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const [errMessage, errStack] = e instanceof Error ? [e.message, e.stack] : ["Unknown Error", undefined];
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||||
taskContext.reportError(message);
|
taskContext.reportError(message);
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ async function importAttachmentsToNote(req: Request) {
|
|||||||
try {
|
try {
|
||||||
await singleImportService.importAttachment(taskContext, file, parentNote);
|
await singleImportService.importAttachment(taskContext, file, parentNote);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const [errMessage, errStack] = e instanceof Error ? [e.message, e.stack] : ["Unknown Error", undefined];
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
|
|
||||||
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
const message = `Import failed with following error: '${errMessage}'. More details might be in the logs.`;
|
||||||
taskContext.reportError(message);
|
taskContext.reportError(message);
|
||||||
|
@ -6,6 +6,7 @@ import becca from "../../becca/becca.js";
|
|||||||
import syncService from "../../services/sync.js";
|
import syncService from "../../services/sync.js";
|
||||||
import sql from "../../services/sql.js";
|
import sql from "../../services/sql.js";
|
||||||
import type { Request } from "express";
|
import type { Request } from "express";
|
||||||
|
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||||
|
|
||||||
interface ScriptBody {
|
interface ScriptBody {
|
||||||
script: string;
|
script: string;
|
||||||
@ -34,9 +35,10 @@ async function exec(req: Request) {
|
|||||||
maxEntityChangeId: syncService.getMaxEntityChangeId()
|
maxEntityChangeId: syncService.getMaxEntityChangeId()
|
||||||
};
|
};
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
const [errMessage] = safeExtractMessageAndStackFromError(e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: (e instanceof Error) ? e.message : "Unknown Error"
|
error: errMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import sql from "../../services/sql.js";
|
|||||||
import becca from "../../becca/becca.js";
|
import becca from "../../becca/becca.js";
|
||||||
import type { Request } from "express";
|
import type { Request } from "express";
|
||||||
import ValidationError from "../../errors/validation_error.js";
|
import ValidationError from "../../errors/validation_error.js";
|
||||||
|
import { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||||
|
|
||||||
function getSchema() {
|
function getSchema() {
|
||||||
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
||||||
@ -57,9 +58,10 @@ function execute(req: Request) {
|
|||||||
results
|
results
|
||||||
};
|
};
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
const [errMessage] = safeExtractMessageAndStackFromError(e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: (e instanceof Error) ? e.message : "Unknown Error"
|
error: errMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import optionService from "../../services/options.js";
|
|||||||
import contentHashService from "../../services/content_hash.js";
|
import contentHashService from "../../services/content_hash.js";
|
||||||
import log from "../../services/log.js";
|
import log from "../../services/log.js";
|
||||||
import syncOptions from "../../services/sync_options.js";
|
import syncOptions from "../../services/sync_options.js";
|
||||||
import utils from "../../services/utils.js";
|
import utils, { safeExtractMessageAndStackFromError } from "../../services/utils.js";
|
||||||
import ws from "../../services/ws.js";
|
import ws from "../../services/ws.js";
|
||||||
import type { Request } from "express";
|
import type { Request } from "express";
|
||||||
import type { EntityChange } from "../../services/entity_changes_interface.js";
|
import type { EntityChange } from "../../services/entity_changes_interface.js";
|
||||||
@ -31,9 +31,10 @@ async function testSync() {
|
|||||||
|
|
||||||
return { success: true, message: t("test_sync.successful") };
|
return { success: true, message: t("test_sync.successful") };
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
const [errMessage] = safeExtractMessageAndStackFromError(e);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: (e instanceof Error) ? e.message : "Unknown Error"
|
error: errMessage
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import cls from "../services/cls.js";
|
|||||||
import sql from "../services/sql.js";
|
import sql from "../services/sql.js";
|
||||||
import becca from "../becca/becca.js";
|
import becca from "../becca/becca.js";
|
||||||
import type { Request, Response, Router } from "express";
|
import type { Request, Response, Router } from "express";
|
||||||
|
import { safeExtractMessageAndStackFromError } from "../services/utils.js";
|
||||||
|
|
||||||
function handleRequest(req: Request, res: Response) {
|
function handleRequest(req: Request, res: Response) {
|
||||||
// express puts content after first slash into 0 index element
|
// express puts content after first slash into 0 index element
|
||||||
@ -26,7 +27,7 @@ function handleRequest(req: Request, res: Response) {
|
|||||||
try {
|
try {
|
||||||
match = path.match(regex);
|
match = path.match(regex);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const [errMessage, errStack] = e instanceof Error ? [e.message, e.stack] : ["Unknown Error", undefined];
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
log.error(`Testing path for label '${attr.attributeId}', regex '${attr.value}' failed with error: ${errMessage}, stack: ${errStack}`);
|
log.error(`Testing path for label '${attr.attributeId}', regex '${attr.value}' failed with error: ${errMessage}, stack: ${errStack}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -47,10 +48,8 @@ function handleRequest(req: Request, res: Response) {
|
|||||||
res
|
res
|
||||||
});
|
});
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const [errMessage, errStack] = e instanceof Error ? [e.message, e.stack] : ["Unknown Error", undefined];
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
|
|
||||||
log.error(`Custom handler '${note.noteId}' failed with: ${errMessage}, ${errStack}`);
|
log.error(`Custom handler '${note.noteId}' failed with: ${errMessage}, ${errStack}`);
|
||||||
|
|
||||||
res.setHeader("Content-Type", "text/plain").status(500).send(errMessage);
|
res.setHeader("Content-Type", "text/plain").status(500).send(errMessage);
|
||||||
}
|
}
|
||||||
} else if (attr.name === "customResourceProvider") {
|
} else if (attr.name === "customResourceProvider") {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { isElectron } from "../services/utils.js";
|
import { isElectron, safeExtractMessageAndStackFromError } from "../services/utils.js";
|
||||||
import multer from "multer";
|
import multer from "multer";
|
||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
@ -494,10 +494,7 @@ function handleResponse(resultHandler: ApiResultHandler, req: express.Request, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleException(e: unknown | Error, method: HttpMethod, path: string, res: express.Response) {
|
function handleException(e: unknown | Error, method: HttpMethod, path: string, res: express.Response) {
|
||||||
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
const [errMessage, errStack]: [message: string, stack: string] = (e instanceof Error)
|
|
||||||
? [e.message, e.stack || "No Stack Trace"]
|
|
||||||
: ["Unknown Error", "No Stack Trace"];
|
|
||||||
|
|
||||||
log.error(`${method} ${path} threw exception: '${errMessage}', stack: ${errStack}`);
|
log.error(`${method} ${path} threw exception: '${errMessage}', stack: ${errStack}`);
|
||||||
|
|
||||||
|
@ -500,6 +500,23 @@ describe("#isDev", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#safeExtractMessageAndStackFromError", () => {
|
||||||
|
it("should correctly extract the message and stack property if it gets passed an instance of an Error", () => {
|
||||||
|
const testMessage = "Test Message";
|
||||||
|
const testError = new Error(testMessage);
|
||||||
|
const actual = utils.safeExtractMessageAndStackFromError(testError);
|
||||||
|
expect(actual[0]).toBe(testMessage);
|
||||||
|
expect(actual[1]).not.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use the fallback 'Unknown Error' message, if it gets passed anything else than an instance of an Error", () => {
|
||||||
|
const testNonError = "this is not an instance of an Error, but JS technically allows us to throw this anyways";
|
||||||
|
const actual = utils.safeExtractMessageAndStackFromError(testNonError);
|
||||||
|
expect(actual[0]).toBe("Unknown Error");
|
||||||
|
expect(actual[1]).toBeUndefined();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
describe("#formatDownloadTitle", () => {
|
describe("#formatDownloadTitle", () => {
|
||||||
//prettier-ignore
|
//prettier-ignore
|
||||||
const testCases: [fnValue: Parameters<typeof utils.formatDownloadTitle>, expectedValue: ReturnType<typeof utils.formatDownloadTitle>][] = [
|
const testCases: [fnValue: Parameters<typeof utils.formatDownloadTitle>, expectedValue: ReturnType<typeof utils.formatDownloadTitle>][] = [
|
||||||
|
@ -363,6 +363,11 @@ export function processStringOrBuffer(data: string | Buffer | null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function safeExtractMessageAndStackFromError(err: unknown) {
|
||||||
|
return (err instanceof Error) ? [err.message, err.stack] as const : ["Unknown Error", undefined] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
compareVersions,
|
compareVersions,
|
||||||
crash,
|
crash,
|
||||||
@ -393,6 +398,7 @@ export default {
|
|||||||
removeDiacritic,
|
removeDiacritic,
|
||||||
removeTextFileExtension,
|
removeTextFileExtension,
|
||||||
replaceAll,
|
replaceAll,
|
||||||
|
safeExtractMessageAndStackFromError,
|
||||||
sanitizeSqlIdentifier,
|
sanitizeSqlIdentifier,
|
||||||
stripTags,
|
stripTags,
|
||||||
timeLimit,
|
timeLimit,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user