feat(utils): add structured error logging to Result.wrap

Integrate the Logger into `Result.wrap` so that caught exceptions are
recorded with stack trace, error type, and a `component: "Result"`
tag before being wrapped into a `Result<T>`. Errors are first
normalized via `toError` to preserve `.stack`, `.code`, and `.status`
fields, then logged through the standard pipeline (dev console in
development, JSON pipeline in production). Callers continue to receive
a `Result<T>` — re-throwing remains opt-in via `Result.unwrap`.
This commit is contained in:
2026-06-11 14:58:54 +08:00
parent d189a18f03
commit 2f4d414412
+18 -1
View File
@@ -14,10 +14,15 @@
* `ApiError extends Error`),仓库 `Result.wrap` 捕获后用 `toError` 规范化, * `ApiError extends Error`),仓库 `Result.wrap` 捕获后用 `toError` 规范化,
* 调用方能可靠地 `instanceof ApiError` / `error.message` 访问错误信息。 * 调用方能可靠地 `instanceof ApiError` / `error.message` 访问错误信息。
*/ */
import { Logger } from "./logger";
export type Result<T> = export type Result<T> =
| { readonly success: true; readonly data: T } | { readonly success: true; readonly data: T }
| { readonly success: false; readonly error: Error }; | { readonly success: false; readonly error: Error };
/** 仓库层 Result.wrap 专用 logger —— 自动带 component: "Result" 标签 */
const log = new Logger("Result");
export const Result = { export const Result = {
/** 构造成功结果。 */ /** 构造成功结果。 */
ok<T>(data: T): Result<T> { ok<T>(data: T): Result<T> {
@@ -49,12 +54,24 @@ export const Result = {
/** /**
* 捕获异步 thunk 的异常并包装成 `Result<T>`。仓库内主要用这个把 * 捕获异步 thunk 的异常并包装成 `Result<T>`。仓库内主要用这个把
* `*Api` 调用从「throw 风格」桥接到「Result 风格」。 * `*Api` 调用从「throw 风格」桥接到「Result 风格」。
*
* 错误处理策略(重点):
* 1. 捕获后用 `toError` 规范化(保留 .stack / .code / .status 等字段)
* 2. **用 Logger 记录**(带 stack + component=Result 标签)—— 调试 dev 控制台可见,
* 生产环境走 JSON pipeline 接入日志平台
* 3. **不**重新抛出 —— 调用方拿到的永远是 `Result<T>`throw 风格调用方可在
* 最外层显式 `throw Result.unwrap(r)`
*/ */
async wrap<T>(thunk: () => Promise<T>): Promise<Result<T>> { async wrap<T>(thunk: () => Promise<T>): Promise<Result<T>> {
try { try {
return Result.ok(await thunk()); return Result.ok(await thunk());
} catch (e) { } catch (e) {
return Result.err(e); const err = toError(e);
log.error(
{ err, stack: err.stack, type: err.constructor.name },
"Result.wrap caught exception",
);
return Result.err(err);
} }
}, },
} as const; } as const;