diff --git a/routes/_middleware.ts b/routes/_middleware.ts index c83545b..900ba24 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -11,11 +11,12 @@ import { i18n_get_lang } from "../server/i18ns.ts"; import { SharedTokenType } from "../db.ts"; import { initDOMParser } from "../utils.ts"; import { DOMParser } from "deno_dom/wasm-noinit"; -import { get_host } from "../server/utils.ts"; +import { get_host, return_error } from "../server/utils.ts"; +import { base_logger } from "../utils/logger.ts"; const STATIC_FILES = ["/common.css", "/scrollBar.css", "/sw.js", "/sw.js.map"]; -export async function handler(req: Request, ctx: FreshContext) { +async function default_handler(req: Request, ctx: FreshContext) { const url = new URL(req.url); const m = get_task_manager(); const enable_server_timing = m.cfg.enable_server_timing; @@ -184,3 +185,30 @@ export async function handler(req: Request, ctx: FreshContext) { } return res; } + +// Disable error stack +const unhandle_error_logger = base_logger.get_logger("unhandle_error", { + stack: false, +}); + +async function handleError(req: Request, ctx: FreshContext) { + try { + return await ctx.next(); + } catch (e) { + unhandle_error_logger.error(e); + try { + const u = new URL(req.url); + const is_api = u.pathname.startsWith("/api"); + return is_api + ? return_error(500, "Internal Server Error") + : new Response("Internal Server Error", { status: 500 }); + } catch (_) { + return new Response("Internal Server Error", { status: 500 }); + } + } +} + +export const handler = [ + handleError, + default_handler, +]; diff --git a/utils/logger.ts b/utils/logger.ts index a8ad212..f387873 100644 --- a/utils/logger.ts +++ b/utils/logger.ts @@ -49,6 +49,11 @@ export const enum LogLevel { Error = 6, } +export type LoggerOptions = { + /// Whether to record stack traces for logs. + stack?: boolean | null; +}; + export function format_message( message: unknown[], options?: Deno.InspectOptions, @@ -139,15 +144,19 @@ class BaseLogger extends EventTarget { ]); }); } - add(type: string, level: number, ...messages: unknown[]) { + add( + type: string, + level: number, + options?: LoggerOptions, + ...messages: unknown[] + ) { this.#fallback(type, level, ...messages); if (!this.db || !this.#cfg) return; const message = format_message(messages); - const stack = this.#cfg.logging_stack || - (level >= LogLevel.Trace && level < LogLevel.Debug) || - level >= LogLevel.Warn - ? stackTrace(2) - : undefined; + const enable_stack = options?.stack ?? (this.#cfg.logging_stack || + (level >= LogLevel.Trace && level < LogLevel.Debug) || + level >= LogLevel.Warn); + const stack = enable_stack ? stackTrace(2) : undefined; const now = new Date(); const result = this.db.query<[number | bigint]>( "INSERT INTO log (time, message, level, type, stack) VALUES (?, ?, ?, ?, ?) RETURNING id;", @@ -263,7 +272,7 @@ class BaseLogger extends EventTarget { return 0; } debug(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Debug, ...messages); + this.add(type, LogLevel.Debug, undefined, ...messages); } delete_log(id: number | bigint) { if (!this.db) return; @@ -277,7 +286,7 @@ class BaseLogger extends EventTarget { return super.dispatchEvent(new CustomEvent(type, { detail })); } error(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Error, ...messages); + this.add(type, LogLevel.Error, undefined, ...messages); } #fallback(type: string, level: number, ...messages: unknown[]) { if (type === "default") { @@ -323,11 +332,11 @@ class BaseLogger extends EventTarget { )); return cur.length ? cur[0] : null; } - get_logger(type: string) { - return new Logger(this, type); + get_logger(type: string, options?: LoggerOptions) { + return new Logger(this, type, options); } info(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Info, ...messages); + this.add(type, LogLevel.Info, undefined, ...messages); } list( offset: number = 0, @@ -394,7 +403,7 @@ class BaseLogger extends EventTarget { return this.#convert(cur); } log(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Log, ...messages); + this.add(type, LogLevel.Log, undefined, ...messages); } optimize() { if (!this.db) return; @@ -413,37 +422,39 @@ class BaseLogger extends EventTarget { ); } trace(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Trace, ...messages); + this.add(type, LogLevel.Trace, undefined, ...messages); } warn(type: string, ...messages: unknown[]) { - this.add(type, LogLevel.Warn, ...messages); + this.add(type, LogLevel.Warn, undefined, ...messages); } } class Logger { #base: BaseLogger; #type: string; - constructor(base: BaseLogger, type: string) { + #options?: LoggerOptions; + constructor(base: BaseLogger, type: string, options?: LoggerOptions) { this.#base = base; this.#type = type; + this.#options = options; } debug(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Debug, ...messages); + this.#base.add(this.#type, LogLevel.Debug, this.#options, ...messages); } error(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Error, ...messages); + this.#base.add(this.#type, LogLevel.Error, this.#options, ...messages); } info(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Info, ...messages); + this.#base.add(this.#type, LogLevel.Info, this.#options, ...messages); } log(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Log, ...messages); + this.#base.add(this.#type, LogLevel.Log, this.#options, ...messages); } trace(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Trace, ...messages); + this.#base.add(this.#type, LogLevel.Trace, this.#options, ...messages); } warn(...messages: unknown[]) { - this.#base.add(this.#type, LogLevel.Warn, ...messages); + this.#base.add(this.#type, LogLevel.Warn, this.#options, ...messages); } }